32815 lines
1.6 MiB
Plaintext
32815 lines
1.6 MiB
Plaintext
const char *__doc_igl_AABB = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_AABB_H
|
|
#define IGL_AABB_H
|
|
|
|
// Implementation of semi-general purpose axis-aligned bounding box hierarchy.
|
|
// The mesh (V,Ele) is stored and managed by the caller and each routine here
|
|
// simply takes it as references (it better not change between calls).
|
|
//
|
|
// It's a little annoying that the Dimension is a template parameter and not
|
|
// picked up at run time from V. This leads to duplicated code for 2d/3d (up to
|
|
// dim).
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
template <typename DerivedV, int DIM>
|
|
class AABB
|
|
{
|
|
public:
|
|
typedef typename DerivedV::Scalar Scalar;
|
|
typedef Eigen::Matrix<Scalar,1,DIM> RowVectorDIMS;
|
|
typedef Eigen::Matrix<Scalar,DIM,1> VectorDIMS;
|
|
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,DIM> MatrixXDIMS;
|
|
// Shared pointers are slower...
|
|
AABB * m_left;
|
|
AABB * m_right;
|
|
Eigen::AlignedBox<Scalar,DIM> m_box;
|
|
// -1 non-leaf
|
|
int m_primitive;
|
|
//Scalar m_max_sqr_d;
|
|
//int m_depth;
|
|
AABB():
|
|
m_left(NULL), m_right(NULL),
|
|
m_box(), m_primitive(-1)
|
|
//m_max_sqr_d(std::numeric_limits<double>::infinity()),
|
|
//m_depth(0)
|
|
{}
|
|
// http://stackoverflow.com/a/3279550/148668
|
|
AABB(const AABB& other):
|
|
m_left(other.m_left ? new AABB(*other.m_left) : NULL),
|
|
m_right(other.m_right ? new AABB(*other.m_right) : NULL),
|
|
m_box(other.m_box),
|
|
m_primitive(other.m_primitive)
|
|
//m_max_sqr_d(other.m_max_sqr_d),
|
|
//m_depth(std::max(
|
|
// m_left ? m_left->m_depth + 1 : 0,
|
|
// m_right ? m_right->m_depth + 1 : 0))
|
|
{
|
|
}
|
|
// copy-swap idiom
|
|
friend void swap(AABB& first, AABB& second)
|
|
{
|
|
// Enable ADL
|
|
using std::swap;
|
|
swap(first.m_left,second.m_left);
|
|
swap(first.m_right,second.m_right);
|
|
swap(first.m_box,second.m_box);
|
|
swap(first.m_primitive,second.m_primitive);
|
|
//swap(first.m_max_sqr_d,second.m_max_sqr_d);
|
|
//swap(first.m_depth,second.m_depth);
|
|
}
|
|
// Pass-by-value (aka copy)
|
|
AABB& operator=(AABB other)
|
|
{
|
|
swap(*this,other);
|
|
return *this;
|
|
}
|
|
AABB(AABB&& other):
|
|
// initialize via default constructor
|
|
AABB()
|
|
{
|
|
swap(*this,other);
|
|
}
|
|
// Seems like there should have been an elegant solution to this using
|
|
// the copy-swap idiom above:
|
|
inline void deinit()
|
|
{
|
|
m_primitive = -1;
|
|
m_box = Eigen::AlignedBox<Scalar,DIM>();
|
|
delete m_left;
|
|
m_left = NULL;
|
|
delete m_right;
|
|
m_right = NULL;
|
|
}
|
|
~AABB()
|
|
{
|
|
deinit();
|
|
}
|
|
// Build an Axis-Aligned Bounding Box tree for a given mesh and given
|
|
// serialization of a previous AABB tree.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions.
|
|
// Ele #Ele by dim+1 list of mesh indices into #V.
|
|
// bb_mins max_tree by dim list of bounding box min corner positions
|
|
// bb_maxs max_tree by dim list of bounding box max corner positions
|
|
// elements max_tree list of element or (not leaf id) indices into Ele
|
|
// i recursive call index {0}
|
|
template <typename Derivedbb_mins, typename Derivedbb_maxs>
|
|
inline void init(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<Derivedbb_mins> & bb_mins,
|
|
const Eigen::PlainObjectBase<Derivedbb_maxs> & bb_maxs,
|
|
const Eigen::VectorXi & elements,
|
|
const int i = 0);
|
|
// Wrapper for root with empty serialization
|
|
inline void init(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele);
|
|
// Build an Axis-Aligned Bounding Box tree for a given mesh.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions.
|
|
// Ele #Ele by dim+1 list of mesh indices into #V.
|
|
// SI #Ele by dim list revealing for each coordinate where Ele's
|
|
// barycenters would be sorted: SI(e,d) = i --> the dth coordinate of
|
|
// the barycenter of the eth element would be placed at position i in a
|
|
// sorted list.
|
|
// I #I list of indices into Ele of elements to include (for recursive
|
|
// calls)
|
|
//
|
|
inline void init(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::MatrixXi & SI,
|
|
const Eigen::VectorXi & I);
|
|
// Return whether at leaf node
|
|
inline bool is_leaf() const;
|
|
// Find the indices of elements containing given point.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions. **Should be same as used to
|
|
// construct mesh.**
|
|
// Ele #Ele by dim+1 list of mesh indices into #V. **Should be same as used to
|
|
// construct mesh.**
|
|
// q dim row-vector query position
|
|
// first whether to only return first element containing q
|
|
// Returns:
|
|
// list of indices of elements containing q
|
|
template <typename Derivedq>
|
|
inline std::vector<int> find(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<Derivedq> & q,
|
|
const bool first=false) const;
|
|
|
|
// If number of elements m then total tree size should be 2*h where h is
|
|
// the deepest depth 2^ceil(log(#Ele*2-1))
|
|
inline int subtree_size() const;
|
|
|
|
// Serialize this class into 3 arrays (so we can pass it pack to matlab)
|
|
//
|
|
// Outputs:
|
|
// bb_mins max_tree by dim list of bounding box min corner positions
|
|
// bb_maxs max_tree by dim list of bounding box max corner positions
|
|
// elements max_tree list of element or (not leaf id) indices into Ele
|
|
// i recursive call index into these arrays {0}
|
|
template <typename Derivedbb_mins, typename Derivedbb_maxs>
|
|
inline void serialize(
|
|
Eigen::PlainObjectBase<Derivedbb_mins> & bb_mins,
|
|
Eigen::PlainObjectBase<Derivedbb_maxs> & bb_maxs,
|
|
Eigen::VectorXi & elements,
|
|
const int i = 0) const;
|
|
// Compute squared distance to a query point
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// Ele #Ele by dim list of simplex indices
|
|
// P 3 list of query point coordinates
|
|
// min_sqr_d current minimum squared distance (only find distances
|
|
// less than this)
|
|
// Outputs:
|
|
// I #P list of facet indices corresponding to smallest distances
|
|
// C #P by 3 list of closest points
|
|
// Returns squared distance
|
|
//
|
|
// Known bugs: currently assumes Elements are triangles regardless of
|
|
// dimension.
|
|
inline Scalar squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const RowVectorDIMS & p,
|
|
int & i,
|
|
RowVectorDIMS & c) const;
|
|
private:
|
|
inline Scalar squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const RowVectorDIMS & p,
|
|
const Scalar min_sqr_d,
|
|
int & i,
|
|
RowVectorDIMS & c) const;
|
|
public:
|
|
template <
|
|
typename DerivedP,
|
|
typename DerivedsqrD,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
inline void squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C) const;
|
|
|
|
template <
|
|
typename Derivedother_V,
|
|
typename DerivedsqrD,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
inline void squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const AABB<Derivedother_V,DIM> & other,
|
|
const Eigen::PlainObjectBase<Derivedother_V> & other_V,
|
|
const Eigen::MatrixXi & other_Ele,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C) const;
|
|
private:
|
|
template <
|
|
typename Derivedother_V,
|
|
typename DerivedsqrD,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
inline Scalar squared_distance_helper(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const AABB<Derivedother_V,DIM> * other,
|
|
const Eigen::PlainObjectBase<Derivedother_V> & other_V,
|
|
const Eigen::MatrixXi & other_Ele,
|
|
const Scalar min_sqr_d,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C) const;
|
|
// Helper function for leaves: works in-place on sqr_d
|
|
inline void leaf_squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const RowVectorDIMS & p,
|
|
Scalar & sqr_d,
|
|
int & i,
|
|
RowVectorDIMS & c) const;
|
|
inline void set_min(
|
|
const RowVectorDIMS & p,
|
|
const Scalar sqr_d_candidate,
|
|
const int i_candidate,
|
|
const RowVectorDIMS & c_candidate,
|
|
Scalar & sqr_d,
|
|
int & i,
|
|
RowVectorDIMS & c) const;
|
|
public:
|
|
static
|
|
inline void barycentric_coordinates(
|
|
const RowVectorDIMS & p,
|
|
const RowVectorDIMS & a,
|
|
const RowVectorDIMS & b,
|
|
const RowVectorDIMS & c,
|
|
Eigen::Matrix<Scalar,1,3> & bary);
|
|
public:
|
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
|
};
|
|
}
|
|
|
|
// Implementation
|
|
#include "EPS.h"
|
|
#include "barycenter.h"
|
|
#include "colon.h"
|
|
#include "colon.h"
|
|
#include "doublearea.h"
|
|
#include "matlab_format.h"
|
|
#include "project_to_line_segment.h"
|
|
#include "sort.h"
|
|
#include "volume.h"
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <limits>
|
|
#include <list>
|
|
|
|
template <typename DerivedV, int DIM>
|
|
template <typename Derivedbb_mins, typename Derivedbb_maxs>
|
|
inline void igl::AABB<DerivedV,DIM>::init(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<Derivedbb_mins> & bb_mins,
|
|
const Eigen::PlainObjectBase<Derivedbb_maxs> & bb_maxs,
|
|
const Eigen::VectorXi & elements,
|
|
const int i)
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
if(bb_mins.size() > 0)
|
|
{
|
|
assert(bb_mins.rows() == bb_maxs.rows() && "Serial tree arrays must match");
|
|
assert(bb_mins.cols() == V.cols() && "Serial tree array dim must match V");
|
|
assert(bb_mins.cols() == bb_maxs.cols() && "Serial tree arrays must match");
|
|
assert(bb_mins.rows() == elements.rows() &&
|
|
"Serial tree arrays must match");
|
|
// construct from serialization
|
|
m_box.extend(bb_mins.row(i).transpose());
|
|
m_box.extend(bb_maxs.row(i).transpose());
|
|
m_primitive = elements(i);
|
|
// Not leaf then recurse
|
|
if(m_primitive == -1)
|
|
{
|
|
m_left = new AABB();
|
|
m_left->init( V,Ele,bb_mins,bb_maxs,elements,2*i+1);
|
|
m_right = new AABB();
|
|
m_right->init( V,Ele,bb_mins,bb_maxs,elements,2*i+2);
|
|
//m_depth = std::max( m_left->m_depth, m_right->m_depth)+1;
|
|
}
|
|
}else
|
|
{
|
|
VectorXi allI = colon<int>(0,Ele.rows()-1);
|
|
MatrixXDIMS BC;
|
|
if(Ele.cols() == 1)
|
|
{
|
|
// points
|
|
BC = V;
|
|
}else
|
|
{
|
|
// Simplices
|
|
barycenter(V,Ele,BC);
|
|
}
|
|
MatrixXi SI(BC.rows(),BC.cols());
|
|
{
|
|
MatrixXDIMS _;
|
|
MatrixXi IS;
|
|
igl::sort(BC,1,true,_,IS);
|
|
// Need SI(i) to tell which place i would be sorted into
|
|
const int dim = IS.cols();
|
|
for(int i = 0;i<IS.rows();i++)
|
|
{
|
|
for(int d = 0;d<dim;d++)
|
|
{
|
|
SI(IS(i,d),d) = i;
|
|
}
|
|
}
|
|
}
|
|
init(V,Ele,SI,allI);
|
|
}
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline void igl::AABB<DerivedV,DIM>::init(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele)
|
|
{
|
|
using namespace Eigen;
|
|
return init(V,Ele,MatrixXDIMS(),MatrixXDIMS(),VectorXi(),0);
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline void igl::AABB<DerivedV,DIM>::init(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::MatrixXi & SI,
|
|
const Eigen::VectorXi & I)
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
assert(DIM == V.cols() && "V.cols() should matched declared dimension");
|
|
const Scalar inf = numeric_limits<Scalar>::infinity();
|
|
m_box = AlignedBox<Scalar,DIM>();
|
|
// Compute bounding box
|
|
for(int i = 0;i<I.rows();i++)
|
|
{
|
|
for(int c = 0;c<Ele.cols();c++)
|
|
{
|
|
m_box.extend(V.row(Ele(I(i),c)).transpose());
|
|
m_box.extend(V.row(Ele(I(i),c)).transpose());
|
|
}
|
|
}
|
|
switch(I.size())
|
|
{
|
|
case 0:
|
|
{
|
|
assert(false);
|
|
}
|
|
case 1:
|
|
{
|
|
m_primitive = I(0);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// Compute longest direction
|
|
int max_d = -1;
|
|
m_box.diagonal().maxCoeff(&max_d);
|
|
// Can't use median on BC directly because many may have same value,
|
|
// but can use median on sorted BC indices
|
|
VectorXi SIdI(I.rows());
|
|
for(int i = 0;i<I.rows();i++)
|
|
{
|
|
SIdI(i) = SI(I(i),max_d);
|
|
}
|
|
// Since later I use <= I think I don't need to worry about odd/even
|
|
// Pass by copy to avoid changing input
|
|
const auto median = [](VectorXi A)->Scalar
|
|
{
|
|
size_t n = A.size()/2;
|
|
nth_element(A.data(),A.data()+n,A.data()+A.size());
|
|
if(A.rows() % 2 == 1)
|
|
{
|
|
return A(n);
|
|
}else
|
|
{
|
|
nth_element(A.data(),A.data()+n-1,A.data()+A.size());
|
|
return 0.5*(A(n)+A(n-1));
|
|
}
|
|
};
|
|
const Scalar med = median(SIdI);
|
|
VectorXi LI((I.rows()+1)/2),RI(I.rows()/2);
|
|
assert(LI.rows()+RI.rows() == I.rows());
|
|
// Distribute left and right
|
|
{
|
|
int li = 0;
|
|
int ri = 0;
|
|
for(int i = 0;i<I.rows();i++)
|
|
{
|
|
if(SIdI(i)<=med)
|
|
{
|
|
LI(li++) = I(i);
|
|
}else
|
|
{
|
|
RI(ri++) = I(i);
|
|
}
|
|
}
|
|
}
|
|
//m_depth = 0;
|
|
if(LI.rows()>0)
|
|
{
|
|
m_left = new AABB();
|
|
m_left->init(V,Ele,SI,LI);
|
|
//m_depth = std::max(m_depth, m_left->m_depth+1);
|
|
}
|
|
if(RI.rows()>0)
|
|
{
|
|
m_right = new AABB();
|
|
m_right->init(V,Ele,SI,RI);
|
|
//m_depth = std::max(m_depth, m_right->m_depth+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline bool igl::AABB<DerivedV,DIM>::is_leaf() const
|
|
{
|
|
return m_primitive != -1;
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
template <typename Derivedq>
|
|
inline std::vector<int> igl::AABB<DerivedV,DIM>::find(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<Derivedq> & q,
|
|
const bool first) const
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
assert(q.size() == DIM &&
|
|
"Query dimension should match aabb dimension");
|
|
assert(Ele.cols() == V.cols()+1 &&
|
|
"AABB::find only makes sense for (d+1)-simplices");
|
|
const Scalar epsilon = igl::EPS<Scalar>();
|
|
// Check if outside bounding box
|
|
bool inside = m_box.contains(q.transpose());
|
|
if(!inside)
|
|
{
|
|
return std::vector<int>();
|
|
}
|
|
assert(m_primitive==-1 || (m_left == NULL && m_right == NULL));
|
|
if(is_leaf())
|
|
{
|
|
// Initialize to some value > -epsilon
|
|
Scalar a1=1,a2=1,a3=1,a4=1;
|
|
switch(DIM)
|
|
{
|
|
case 3:
|
|
{
|
|
// Barycentric coordinates
|
|
typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
|
|
const RowVector3S V1 = V.row(Ele(m_primitive,0));
|
|
const RowVector3S V2 = V.row(Ele(m_primitive,1));
|
|
const RowVector3S V3 = V.row(Ele(m_primitive,2));
|
|
const RowVector3S V4 = V.row(Ele(m_primitive,3));
|
|
a1 = volume_single(V2,V4,V3,(RowVector3S)q);
|
|
a2 = volume_single(V1,V3,V4,(RowVector3S)q);
|
|
a3 = volume_single(V1,V4,V2,(RowVector3S)q);
|
|
a4 = volume_single(V1,V2,V3,(RowVector3S)q);
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
// Barycentric coordinates
|
|
typedef Eigen::Matrix<Scalar,2,1> Vector2S;
|
|
const Vector2S V1 = V.row(Ele(m_primitive,0));
|
|
const Vector2S V2 = V.row(Ele(m_primitive,1));
|
|
const Vector2S V3 = V.row(Ele(m_primitive,2));
|
|
// Hack for now to keep templates simple. If becomes bottleneck
|
|
// consider using std::enable_if_t
|
|
const Vector2S q2 = q.head(2);
|
|
Scalar a0 = doublearea_single(V1,V2,V3);
|
|
a1 = doublearea_single(V1,V2,q2);
|
|
a2 = doublearea_single(V2,V3,q2);
|
|
a3 = doublearea_single(V3,V1,q2);
|
|
break;
|
|
}
|
|
default:assert(false);
|
|
}
|
|
if(
|
|
a1>=-epsilon &&
|
|
a2>=-epsilon &&
|
|
a3>=-epsilon &&
|
|
a4>=-epsilon)
|
|
{
|
|
return std::vector<int>(1,m_primitive);
|
|
}else
|
|
{
|
|
return std::vector<int>();
|
|
}
|
|
}
|
|
std::vector<int> left = m_left->find(V,Ele,q,first);
|
|
if(first && !left.empty())
|
|
{
|
|
return left;
|
|
}
|
|
std::vector<int> right = m_right->find(V,Ele,q,first);
|
|
if(first)
|
|
{
|
|
return right;
|
|
}
|
|
left.insert(left.end(),right.begin(),right.end());
|
|
return left;
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline int igl::AABB<DerivedV,DIM>::subtree_size() const
|
|
{
|
|
// 1 for self
|
|
int n = 1;
|
|
int n_left = 0,n_right = 0;
|
|
if(m_left != NULL)
|
|
{
|
|
n_left = m_left->subtree_size();
|
|
}
|
|
if(m_right != NULL)
|
|
{
|
|
n_right = m_right->subtree_size();
|
|
}
|
|
n += 2*std::max(n_left,n_right);
|
|
return n;
|
|
}
|
|
|
|
|
|
template <typename DerivedV, int DIM>
|
|
template <typename Derivedbb_mins, typename Derivedbb_maxs>
|
|
inline void igl::AABB<DerivedV,DIM>::serialize(
|
|
Eigen::PlainObjectBase<Derivedbb_mins> & bb_mins,
|
|
Eigen::PlainObjectBase<Derivedbb_maxs> & bb_maxs,
|
|
Eigen::VectorXi & elements,
|
|
const int i) const
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
// Calling for root then resize output
|
|
if(i==0)
|
|
{
|
|
const int m = subtree_size();
|
|
//cout<<"m: "<<m<<endl;
|
|
bb_mins.resize(m,DIM);
|
|
bb_maxs.resize(m,DIM);
|
|
elements.resize(m,1);
|
|
}
|
|
//cout<<i<<" ";
|
|
bb_mins.row(i) = m_box.min();
|
|
bb_maxs.row(i) = m_box.max();
|
|
elements(i) = m_primitive;
|
|
if(m_left != NULL)
|
|
{
|
|
m_left->serialize(bb_mins,bb_maxs,elements,2*i+1);
|
|
}
|
|
if(m_right != NULL)
|
|
{
|
|
m_right->serialize(bb_mins,bb_maxs,elements,2*i+2);
|
|
}
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline typename igl::AABB<DerivedV,DIM>::Scalar
|
|
igl::AABB<DerivedV,DIM>::squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const RowVectorDIMS & p,
|
|
int & i,
|
|
RowVectorDIMS & c) const
|
|
{
|
|
return squared_distance(V,Ele,p,std::numeric_limits<Scalar>::infinity(),i,c);
|
|
}
|
|
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline typename igl::AABB<DerivedV,DIM>::Scalar
|
|
igl::AABB<DerivedV,DIM>::squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const RowVectorDIMS & p,
|
|
Scalar min_sqr_d,
|
|
int & i,
|
|
RowVectorDIMS & c) const
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
using namespace igl;
|
|
Scalar sqr_d = min_sqr_d;
|
|
assert(DIM == 3 && "Code has only been tested for DIM == 3");
|
|
assert((Ele.cols() == 3 || Ele.cols() == 2 || Ele.cols() == 1)
|
|
&& "Code has only been tested for simplex sizes 3,2,1");
|
|
|
|
assert(m_primitive==-1 || (m_left == NULL && m_right == NULL));
|
|
if(is_leaf())
|
|
{
|
|
leaf_squared_distance(V,Ele,p,sqr_d,i,c);
|
|
}else
|
|
{
|
|
bool looked_left = false;
|
|
bool looked_right = false;
|
|
const auto & look_left = [&]()
|
|
{
|
|
int i_left;
|
|
RowVectorDIMS c_left = c;
|
|
Scalar sqr_d_left = m_left->squared_distance(V,Ele,p,sqr_d,i_left,c_left);
|
|
set_min(p,sqr_d_left,i_left,c_left,sqr_d,i,c);
|
|
looked_left = true;
|
|
};
|
|
const auto & look_right = [&]()
|
|
{
|
|
int i_right;
|
|
RowVectorDIMS c_right = c;
|
|
Scalar sqr_d_right = m_right->squared_distance(V,Ele,p,sqr_d,i_right,c_right);
|
|
set_min(p,sqr_d_right,i_right,c_right,sqr_d,i,c);
|
|
looked_right = true;
|
|
};
|
|
|
|
// must look left or right if in box
|
|
if(m_left->m_box.contains(p.transpose()))
|
|
{
|
|
look_left();
|
|
}
|
|
if(m_right->m_box.contains(p.transpose()))
|
|
{
|
|
look_right();
|
|
}
|
|
// if haven't looked left and could be less than current min, then look
|
|
Scalar left_min_sqr_d = m_left->m_box.squaredExteriorDistance(p.transpose());
|
|
Scalar right_min_sqr_d = m_right->m_box.squaredExteriorDistance(p.transpose());
|
|
if(left_min_sqr_d < right_min_sqr_d)
|
|
{
|
|
if(!looked_left && left_min_sqr_d<sqr_d)
|
|
{
|
|
look_left();
|
|
}
|
|
if( !looked_right && right_min_sqr_d<sqr_d)
|
|
{
|
|
look_right();
|
|
}
|
|
}else
|
|
{
|
|
if( !looked_right && right_min_sqr_d<sqr_d)
|
|
{
|
|
look_right();
|
|
}
|
|
if(!looked_left && left_min_sqr_d<sqr_d)
|
|
{
|
|
look_left();
|
|
}
|
|
}
|
|
}
|
|
return sqr_d;
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
template <
|
|
typename DerivedP,
|
|
typename DerivedsqrD,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
inline void igl::AABB<DerivedV,DIM>::squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C) const
|
|
{
|
|
assert(P.cols() == V.cols() && "cols in P should match dim of cols in V");
|
|
sqrD.resize(P.rows(),1);
|
|
I.resize(P.rows(),1);
|
|
C.resize(P.rows(),P.cols());
|
|
for(int p = 0;p<P.rows();p++)
|
|
{
|
|
RowVectorDIMS Pp = P.row(p), c;
|
|
int Ip;
|
|
sqrD(p) = squared_distance(V,Ele,Pp,Ip,c);
|
|
I(p) = Ip;
|
|
C.row(p) = c;
|
|
}
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
template <
|
|
typename Derivedother_V,
|
|
typename DerivedsqrD,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
inline void igl::AABB<DerivedV,DIM>::squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const AABB<Derivedother_V,DIM> & other,
|
|
const Eigen::PlainObjectBase<Derivedother_V> & other_V,
|
|
const Eigen::MatrixXi & other_Ele,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C) const
|
|
{
|
|
assert(other_Ele.cols() == 1 &&
|
|
"Only implemented for other as list of points");
|
|
assert(other_V.cols() == V.cols() && "other must match this dimension");
|
|
sqrD.setConstant(other_Ele.rows(),1,std::numeric_limits<double>::infinity());
|
|
I.resize(other_Ele.rows(),1);
|
|
C.resize(other_Ele.rows(),other_V.cols());
|
|
// All points in other_V currently think they need to check against root of
|
|
// this. The point of using another AABB is to quickly prune chunks of
|
|
// other_V so that most points just check some subtree of this.
|
|
|
|
// This holds a conservative estimate of max(sqr_D) where sqr_D is the
|
|
// current best minimum squared distance for all points in this subtree
|
|
double min_sqr_d = std::numeric_limits<double>::infinity();
|
|
squared_distance_helper(
|
|
V,Ele,&other,other_V,other_Ele,min_sqr_d,sqrD,I,C);
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
template <
|
|
typename Derivedother_V,
|
|
typename DerivedsqrD,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
inline typename igl::AABB<DerivedV,DIM>::Scalar igl::AABB<DerivedV,DIM>::squared_distance_helper(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const AABB<Derivedother_V,DIM> * other,
|
|
const Eigen::PlainObjectBase<Derivedother_V> & other_V,
|
|
const Eigen::MatrixXi & other_Ele,
|
|
const Scalar min_sqr_d,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C) const
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
|
|
// This implementation is a bit disappointing. There's no major speed up. Any
|
|
// performance gains seem to come from accidental cache coherency and
|
|
// diminish for larger "other" (the opposite of what was intended).
|
|
|
|
// Base case
|
|
if(other->is_leaf() && this->is_leaf())
|
|
{
|
|
Scalar sqr_d = sqrD(other->m_primitive);
|
|
int i = I(other->m_primitive);
|
|
RowVectorDIMS c = C.row( other->m_primitive);
|
|
RowVectorDIMS p = other_V.row(other->m_primitive);
|
|
leaf_squared_distance(V,Ele,p,sqr_d,i,c);
|
|
sqrD( other->m_primitive) = sqr_d;
|
|
I( other->m_primitive) = i;
|
|
C.row(other->m_primitive) = c;
|
|
//cout<<"leaf: "<<sqr_d<<endl;
|
|
//other->m_max_sqr_d = sqr_d;
|
|
return sqr_d;
|
|
}
|
|
|
|
if(other->is_leaf())
|
|
{
|
|
Scalar sqr_d = sqrD(other->m_primitive);
|
|
int i = I(other->m_primitive);
|
|
RowVectorDIMS c = C.row( other->m_primitive);
|
|
RowVectorDIMS p = other_V.row(other->m_primitive);
|
|
sqr_d = squared_distance(V,Ele,p,sqr_d,i,c);
|
|
sqrD( other->m_primitive) = sqr_d;
|
|
I( other->m_primitive) = i;
|
|
C.row(other->m_primitive) = c;
|
|
//other->m_max_sqr_d = sqr_d;
|
|
return sqr_d;
|
|
}
|
|
|
|
//// Exact minimum squared distance between arbitary primitives inside this and
|
|
//// othre's bounding boxes
|
|
//const auto & min_squared_distance = [&](
|
|
// const AABB<DerivedV,DIM> * A,
|
|
// const AABB<Derivedother_V,DIM> * B)->Scalar
|
|
//{
|
|
// return A->m_box.squaredExteriorDistance(B->m_box);
|
|
//};
|
|
|
|
if(this->is_leaf())
|
|
{
|
|
//if(min_squared_distance(this,other) < other->m_max_sqr_d)
|
|
if(true)
|
|
{
|
|
this->squared_distance_helper(
|
|
V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C);
|
|
this->squared_distance_helper(
|
|
V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C);
|
|
}else
|
|
{
|
|
// This is never reached...
|
|
}
|
|
//// we know other is not a leaf
|
|
//other->m_max_sqr_d = std::max(other->m_left->m_max_sqr_d,other->m_right->m_max_sqr_d);
|
|
return 0;
|
|
}
|
|
|
|
// FORCE DOWN TO OTHER LEAF EVAL
|
|
//if(min_squared_distance(this,other) < other->m_max_sqr_d)
|
|
if(true)
|
|
{
|
|
if(true)
|
|
{
|
|
this->squared_distance_helper(
|
|
V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C);
|
|
this->squared_distance_helper(
|
|
V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C);
|
|
}else // this direction never seems to be faster
|
|
{
|
|
this->m_left->squared_distance_helper(
|
|
V,Ele,other,other_V,other_Ele,0,sqrD,I,C);
|
|
this->m_right->squared_distance_helper(
|
|
V,Ele,other,other_V,other_Ele,0,sqrD,I,C);
|
|
}
|
|
}else
|
|
{
|
|
// this is never reached ... :-(
|
|
}
|
|
//// we know other is not a leaf
|
|
//other->m_max_sqr_d = std::max(other->m_left->m_max_sqr_d,other->m_right->m_max_sqr_d);
|
|
|
|
return 0;
|
|
#if 0 // False
|
|
|
|
// _Very_ conservative approximation of maximum squared distance between
|
|
// primitives inside this and other's bounding boxes
|
|
const auto & max_squared_distance = [](
|
|
const AABB<DerivedV,DIM> * A,
|
|
const AABB<Derivedother_V,DIM> * B)->Scalar
|
|
{
|
|
AlignedBox<Scalar,DIM> combo = A->m_box;
|
|
combo.extend(B->m_box);
|
|
return combo.diagonal().squaredNorm();
|
|
};
|
|
|
|
//// other base-case
|
|
//if(other->is_leaf())
|
|
//{
|
|
// double sqr_d = sqrD(other->m_primitive);
|
|
// int i = I(other->m_primitive);
|
|
// RowVectorDIMS c = C.row(m_primitive);
|
|
// RowVectorDIMS p = other_V.row(m_primitive);
|
|
// leaf_squared_distance(V,Ele,p,sqr_d,i,c);
|
|
// sqrD(other->m_primitive) = sqr_d;
|
|
// I(other->m_primitive) = i;
|
|
// C.row(m_primitive) = c;
|
|
// return;
|
|
//}
|
|
std::vector<const AABB<DerivedV,DIM> * > this_list;
|
|
if(this->is_leaf())
|
|
{
|
|
this_list.push_back(this);
|
|
}else
|
|
{
|
|
assert(this->m_left);
|
|
this_list.push_back(this->m_left);
|
|
assert(this->m_right);
|
|
this_list.push_back(this->m_right);
|
|
}
|
|
std::vector<AABB<Derivedother_V,DIM> *> other_list;
|
|
if(other->is_leaf())
|
|
{
|
|
other_list.push_back(other);
|
|
}else
|
|
{
|
|
assert(other->m_left);
|
|
other_list.push_back(other->m_left);
|
|
assert(other->m_right);
|
|
other_list.push_back(other->m_right);
|
|
}
|
|
|
|
//const std::function<Scalar(
|
|
// const AABB<Derivedother_V,DIM> * other)
|
|
// > max_sqr_d = [&sqrD,&max_sqr_d](const AABB<Derivedother_V,DIM> * other)->Scalar
|
|
// {
|
|
// if(other->is_leaf())
|
|
// {
|
|
// return sqrD(other->m_primitive);
|
|
// }else
|
|
// {
|
|
// return std::max(max_sqr_d(other->m_left),max_sqr_d(other->m_right));
|
|
// }
|
|
// };
|
|
|
|
//// Potentially recurse on all pairs, if minimum distance is less than running
|
|
//// bound
|
|
//Eigen::Matrix<Scalar,Eigen::Dynamic,1> other_max_sqr_d =
|
|
// Eigen::Matrix<Scalar,Eigen::Dynamic,1>::Constant(other_list.size(),1,min_sqr_d);
|
|
for(size_t child = 0;child<other_list.size();child++)
|
|
{
|
|
auto other_tree = other_list[child];
|
|
|
|
Eigen::Matrix<Scalar,Eigen::Dynamic,1> this_max_sqr_d(this_list.size(),1);
|
|
for(size_t t = 0;t<this_list.size();t++)
|
|
{
|
|
const auto this_tree = this_list[t];
|
|
this_max_sqr_d(t) = max_squared_distance(this_tree,other_tree);
|
|
}
|
|
if(this_list.size() ==2 &&
|
|
( this_max_sqr_d(0) > this_max_sqr_d(1))
|
|
)
|
|
{
|
|
std::swap(this_list[0],this_list[1]);
|
|
//std::swap(this_max_sqr_d(0),this_max_sqr_d(1));
|
|
}
|
|
const Scalar sqr_d = this_max_sqr_d.minCoeff();
|
|
|
|
|
|
for(size_t t = 0;t<this_list.size();t++)
|
|
{
|
|
const auto this_tree = this_list[t];
|
|
|
|
//const auto mm = max_sqr_d(other_tree);
|
|
//const Scalar mc = other_max_sqr_d(child);
|
|
//assert(mc == mm);
|
|
// Only look left/right in this_list if can possible decrease somebody's
|
|
// distance in this_tree.
|
|
const Scalar min_this_other = min_squared_distance(this_tree,other_tree);
|
|
if(
|
|
min_this_other < sqr_d &&
|
|
min_this_other < other_tree->m_max_sqr_d)
|
|
{
|
|
//cout<<"before: "<<other_max_sqr_d(child)<<endl;
|
|
//other_max_sqr_d(child) = std::min(
|
|
// other_max_sqr_d(child),
|
|
// this_tree->squared_distance_helper(
|
|
// V,Ele,other_tree,other_V,other_Ele,other_max_sqr_d(child),sqrD,I,C));
|
|
//cout<<"after: "<<other_max_sqr_d(child)<<endl;
|
|
this_tree->squared_distance_helper(
|
|
V,Ele,other_tree,other_V,other_Ele,0,sqrD,I,C);
|
|
}
|
|
}
|
|
}
|
|
//const Scalar ret = other_max_sqr_d.maxCoeff();
|
|
//const auto mm = max_sqr_d(other);
|
|
//assert(mm == ret);
|
|
//cout<<"non-leaf: "<<ret<<endl;
|
|
//return ret;
|
|
if(!other->is_leaf())
|
|
{
|
|
other->m_max_sqr_d = std::max(other->m_left->m_max_sqr_d,other->m_right->m_max_sqr_d);
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const RowVectorDIMS & p,
|
|
Scalar & sqr_d,
|
|
int & i,
|
|
RowVectorDIMS & c) const
|
|
{
|
|
using namespace Eigen;
|
|
using namespace igl;
|
|
using namespace std;
|
|
|
|
// Simplex size
|
|
const size_t ss = Ele.cols();
|
|
// Only one element per node
|
|
// plane unit normal
|
|
bool inside_triangle = false;
|
|
Scalar d_j = std::numeric_limits<Scalar>::infinity();
|
|
RowVectorDIMS pp;
|
|
// Only consider triangles, and non-degenerate triangles at that
|
|
if(ss == 3 &&
|
|
Ele(m_primitive,0) != Ele(m_primitive,1) &&
|
|
Ele(m_primitive,1) != Ele(m_primitive,2) &&
|
|
Ele(m_primitive,2) != Ele(m_primitive,0))
|
|
{
|
|
const RowVectorDIMS v10 = (V.row(Ele(m_primitive,1))- V.row(Ele(m_primitive,0)));
|
|
const RowVectorDIMS v20 = (V.row(Ele(m_primitive,2))- V.row(Ele(m_primitive,0)));
|
|
const RowVectorDIMS n = v10.cross(v20);
|
|
Scalar n_norm = n.norm();
|
|
if(n_norm > 0)
|
|
{
|
|
const RowVectorDIMS un = n/n.norm();
|
|
// vector to plane
|
|
const RowVectorDIMS bc =
|
|
1./3.*
|
|
( V.row(Ele(m_primitive,0))+
|
|
V.row(Ele(m_primitive,1))+
|
|
V.row(Ele(m_primitive,2)));
|
|
const auto & v = p-bc;
|
|
// projected point on plane
|
|
d_j = v.dot(un);
|
|
pp = p - d_j*un;
|
|
// determine if pp is inside triangle
|
|
Eigen::Matrix<Scalar,1,3> b;
|
|
barycentric_coordinates(
|
|
pp,
|
|
V.row(Ele(m_primitive,0)),
|
|
V.row(Ele(m_primitive,1)),
|
|
V.row(Ele(m_primitive,2)),
|
|
b);
|
|
inside_triangle = fabs(fabs(b(0)) + fabs(b(1)) + fabs(b(2)) - 1.) <= 1e-10;
|
|
}
|
|
}
|
|
const auto & point_point_squared_distance = [&](const RowVectorDIMS & s)
|
|
{
|
|
const Scalar sqr_d_s = (p-s).squaredNorm();
|
|
set_min(p,sqr_d_s,m_primitive,s,sqr_d,i,c);
|
|
};
|
|
if(inside_triangle)
|
|
{
|
|
// point-triangle squared distance
|
|
const Scalar sqr_d_j = d_j*d_j;
|
|
//cout<<"point-triangle..."<<endl;
|
|
set_min(p,sqr_d_j,m_primitive,pp,sqr_d,i,c);
|
|
}else
|
|
{
|
|
if(ss >= 2)
|
|
{
|
|
// point-segment distance
|
|
// number of edges
|
|
size_t ne = ss==3?3:1;
|
|
for(size_t x = 0;x<ne;x++)
|
|
{
|
|
const size_t e1 = Ele(m_primitive,(x+1)%ss);
|
|
const size_t e2 = Ele(m_primitive,(x+2)%ss);
|
|
const RowVectorDIMS & s = V.row(e1);
|
|
const RowVectorDIMS & d = V.row(e2);
|
|
// Degenerate edge
|
|
if(e1 == e2 || (s-d).squaredNorm()==0)
|
|
{
|
|
// only consider once
|
|
if(e1 < e2)
|
|
{
|
|
point_point_squared_distance(s);
|
|
}
|
|
continue;
|
|
}
|
|
Matrix<Scalar,1,1> sqr_d_j_x(1,1);
|
|
Matrix<Scalar,1,1> t(1,1);
|
|
project_to_line_segment(p,s,d,t,sqr_d_j_x);
|
|
const RowVectorDIMS q = s+t(0)*(d-s);
|
|
set_min(p,sqr_d_j_x(0),m_primitive,q,sqr_d,i,c);
|
|
}
|
|
}else
|
|
{
|
|
// So then Ele is just a list of points...
|
|
assert(ss == 1);
|
|
const RowVectorDIMS & s = V.row(Ele(m_primitive,0));
|
|
point_point_squared_distance(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline void igl::AABB<DerivedV,DIM>::set_min(
|
|
const RowVectorDIMS & p,
|
|
const Scalar sqr_d_candidate,
|
|
const int i_candidate,
|
|
const RowVectorDIMS & c_candidate,
|
|
Scalar & sqr_d,
|
|
int & i,
|
|
RowVectorDIMS & c) const
|
|
{
|
|
#ifndef NDEBUG
|
|
//std::cout<<matlab_format(c_candidate,"c_candidate")<<std::endl;
|
|
const Scalar pc_norm = (p-c_candidate).squaredNorm();
|
|
const Scalar diff = fabs(sqr_d_candidate - pc_norm);
|
|
assert(diff<=1e-10 && "distance should match norm of difference");
|
|
#endif
|
|
if(sqr_d_candidate < sqr_d)
|
|
{
|
|
i = i_candidate;
|
|
c = c_candidate;
|
|
sqr_d = sqr_d_candidate;
|
|
}
|
|
}
|
|
|
|
|
|
template <typename DerivedV, int DIM>
|
|
inline void
|
|
igl::AABB<DerivedV,DIM>::barycentric_coordinates(
|
|
const RowVectorDIMS & p,
|
|
const RowVectorDIMS & a,
|
|
const RowVectorDIMS & b,
|
|
const RowVectorDIMS & c,
|
|
Eigen::Matrix<Scalar,1,3> & bary)
|
|
{
|
|
// http://gamedev.stackexchange.com/a/23745
|
|
const RowVectorDIMS v0 = b - a;
|
|
const RowVectorDIMS v1 = c - a;
|
|
const RowVectorDIMS v2 = p - a;
|
|
Scalar d00 = v0.dot(v0);
|
|
Scalar d01 = v0.dot(v1);
|
|
Scalar d11 = v1.dot(v1);
|
|
Scalar d20 = v2.dot(v0);
|
|
Scalar d21 = v2.dot(v1);
|
|
Scalar denom = d00 * d11 - d01 * d01;
|
|
bary(1) = (d11 * d20 - d01 * d21) / denom;
|
|
bary(2) = (d00 * d21 - d01 * d20) / denom;
|
|
bary(0) = 1.0f - bary(1) - bary(2);
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_active_set = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ACTIVE_SET_H
|
|
#define IGL_ACTIVE_SET_H
|
|
|
|
#include "igl_inline.h"
|
|
#include "SolverStatus.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
struct active_set_params;
|
|
// Known Bugs: rows of [Aeq;Aieq] **must** be linearly independent. Should be
|
|
// using QR decomposition otherwise:
|
|
// http://www.okstate.edu/sas/v8/sashtml/ormp/chap5/sect32.htm
|
|
//
|
|
// ACTIVE_SET Minimize quadratic energy
|
|
//
|
|
// 0.5*Z'*A*Z + Z'*B + C with constraints
|
|
//
|
|
// that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq,
|
|
// and further optionally subject to the linear inequality constraints that
|
|
// Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux
|
|
//
|
|
// Templates:
|
|
// Inputs:
|
|
// A n by n matrix of quadratic coefficients
|
|
// B n by 1 column of linear coefficients
|
|
// known list of indices to known rows in Z
|
|
// Y list of fixed values corresponding to known rows in Z
|
|
// Aeq meq by n list of linear equality constraint coefficients
|
|
// Beq meq by 1 list of linear equality constraint constant values
|
|
// Aieq mieq by n list of linear inequality constraint coefficients
|
|
// Bieq mieq by 1 list of linear inequality constraint constant values
|
|
// lx n by 1 list of lower bounds [] implies -Inf
|
|
// ux n by 1 list of upper bounds [] implies Inf
|
|
// params struct of additional parameters (see below)
|
|
// Z if not empty, is taken to be an n by 1 list of initial guess values
|
|
// (see output)
|
|
// Outputs:
|
|
// Z n by 1 list of solution values
|
|
// Returns true on success, false on error
|
|
//
|
|
// Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
|
|
// secs, igl/min_quad_with_fixed.h 7.1 secs
|
|
//
|
|
|
|
template <
|
|
typename AT,
|
|
typename DerivedB,
|
|
typename Derivedknown,
|
|
typename DerivedY,
|
|
typename AeqT,
|
|
typename DerivedBeq,
|
|
typename AieqT,
|
|
typename DerivedBieq,
|
|
typename Derivedlx,
|
|
typename Derivedux,
|
|
typename DerivedZ
|
|
>
|
|
IGL_INLINE igl::SolverStatus active_set(
|
|
const Eigen::SparseMatrix<AT>& A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<Derivedknown> & known,
|
|
const Eigen::PlainObjectBase<DerivedY> & Y,
|
|
const Eigen::SparseMatrix<AeqT>& Aeq,
|
|
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
|
|
const Eigen::SparseMatrix<AieqT>& Aieq,
|
|
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
|
|
const Eigen::PlainObjectBase<Derivedlx> & lx,
|
|
const Eigen::PlainObjectBase<Derivedux> & ux,
|
|
const igl::active_set_params & params,
|
|
Eigen::PlainObjectBase<DerivedZ> & Z
|
|
);
|
|
};
|
|
|
|
#include "EPS.h"
|
|
struct igl::active_set_params
|
|
{
|
|
// Input parameters for active_set:
|
|
// Auu_pd whether Auu is positive definite {false}
|
|
// max_iter Maximum number of iterations (0 = Infinity, {100})
|
|
// inactive_threshold Threshold on Lagrange multiplier values to determine
|
|
// whether to keep constraints active {EPS}
|
|
// constraint_threshold Threshold on whether constraints are violated (0
|
|
// is perfect) {EPS}
|
|
// solution_diff_threshold Threshold on the squared norm of the difference
|
|
// between two consecutive solutions {EPS}
|
|
bool Auu_pd;
|
|
int max_iter;
|
|
double inactive_threshold;
|
|
double constraint_threshold;
|
|
double solution_diff_threshold;
|
|
active_set_params():
|
|
Auu_pd(false),
|
|
max_iter(100),
|
|
inactive_threshold(igl::DOUBLE_EPS),
|
|
constraint_threshold(igl::DOUBLE_EPS),
|
|
solution_diff_threshold(igl::DOUBLE_EPS)
|
|
{};
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "active_set.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_adjacency_list = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ADJACENCY_LIST_H
|
|
#define IGL_ADJACENCY_LIST_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Constructs the graph adjacency list of a given mesh (V,F)
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// F #F by dim list of mesh faces (must be triangles)
|
|
// sorted flag that indicates if the list should be sorted counter-clockwise
|
|
// Outputs:
|
|
// A vector<vector<T> > containing at row i the adjacent vertices of vertex i
|
|
//
|
|
// Example:
|
|
// // Mesh in (V,F)
|
|
// vector<vector<double> > A;
|
|
// adjacency_list(F,A);
|
|
//
|
|
// See also: edges, cotmatrix, diag
|
|
template <typename Index, typename IndexVector>
|
|
IGL_INLINE void adjacency_list(
|
|
const Eigen::PlainObjectBase<Index> & F,
|
|
std::vector<std::vector<IndexVector> >& A,
|
|
bool sorted = false);
|
|
|
|
// Variant that accepts polygonal faces.
|
|
// Each element of F is a set of indices of a polygonal face.
|
|
template <typename Index>
|
|
IGL_INLINE void adjacency_list(
|
|
const std::vector<std::vector<Index> > & F,
|
|
std::vector<std::vector<Index> >& A);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "adjacency_list.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_adjacency_matrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ADJACENCY_MATRIX_H
|
|
#define IGL_ADJACENCY_MATRIX_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Constructs the graph adjacency matrix of a given mesh (V,F)
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// F #F by dim list of mesh simplices
|
|
// Outputs:
|
|
// A max(F) by max(F) cotangent matrix, each row i corresponding to V(i,:)
|
|
//
|
|
// Example:
|
|
// // Mesh in (V,F)
|
|
// Eigen::SparseMatrix<double> A;
|
|
// adjacency_matrix(F,A);
|
|
// // sum each row
|
|
// SparseVector<double> Asum;
|
|
// sum(A,1,Asum);
|
|
// // Convert row sums into diagonal of sparse matrix
|
|
// SparseMatrix<double> Adiag;
|
|
// diag(Asum,Adiag);
|
|
// // Build uniform laplacian
|
|
// SparseMatrix<double> U;
|
|
// U = A-Adiag;
|
|
//
|
|
// See also: edges, cotmatrix, diag
|
|
template <typename T>
|
|
IGL_INLINE void adjacency_matrix(
|
|
const Eigen::MatrixXi & F,
|
|
Eigen::SparseMatrix<T>& A);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "adjacency_matrix.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_all_edges = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ALL_EDGES_H
|
|
#define IGL_ALL_EDGES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// ALL_EDGES Determines all "directed edges" of a given set of simplices
|
|
//
|
|
// Inputs:
|
|
// F #F by simplex_size list of "faces"
|
|
// Outputs:
|
|
// E #E by simplex_size-1 list of edges
|
|
//
|
|
// Note: this is not the same as igl::edges because this includes every
|
|
// directed edge including repeats (meaning interior edges on a surface will
|
|
// show up once for each direction and non-manifold edges may appear more than
|
|
// once for each direction).
|
|
template <typename DerivedF, typename DerivedE>
|
|
IGL_INLINE void all_edges(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedE> & E);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "all_edges.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_all_pairs_distances = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ALL_PAIRS_DISTANCES_H
|
|
#define IGL_ALL_PAIRS_DISTANCES_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// ALL_PAIRS_DISTANCES compute distances between each point i in V and point j
|
|
// in U
|
|
//
|
|
// D = all_pairs_distances(V,U)
|
|
//
|
|
// Templates:
|
|
// Mat matrix class like MatrixXd
|
|
// Inputs:
|
|
// V #V by dim list of points
|
|
// U #U by dim list of points
|
|
// squared whether to return squared distances
|
|
// Outputs:
|
|
// D #V by #U matrix of distances, where D(i,j) gives the distance or
|
|
// squareed distance between V(i,:) and U(j,:)
|
|
//
|
|
template <typename Mat>
|
|
IGL_INLINE void all_pairs_distances(
|
|
const Mat & V,
|
|
const Mat & U,
|
|
const bool squared,
|
|
Mat & D);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "all_pairs_distances.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_angle_bound_frame_fields = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_ANGLE_BOUND_FRAME_FIELDS
|
|
#define IGL_ANGLE_BOUND_FRAME_FIELDS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
//todo
|
|
/// Given 2 vectors centered on origin calculate the rotation matrix from first to the second
|
|
|
|
// Inputs:
|
|
// v0, v1 the two #3 by 1 vectors
|
|
// normalized boolean, if false, then the vectors are normalized prior to the calculation
|
|
// Output:
|
|
// 3 by 3 rotation matrix that takes v0 to v1
|
|
//
|
|
template <typename DerivedV, typename DerivedF>
|
|
class AngleBoundFFSolverData;
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedO>
|
|
IGL_INLINE bool angle_bound_frame_fields(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const typename DerivedV::Scalar &thetaMin,
|
|
const Eigen::VectorXi &isConstrained,
|
|
const Eigen::PlainObjectBase<DerivedO> &initialSolution,
|
|
Eigen::PlainObjectBase<DerivedO> &output,
|
|
int _maxIter = 50,
|
|
const typename DerivedV::Scalar &_lambdaInit = 100,
|
|
const typename DerivedV::Scalar &_lambdaMultFactor = 1.5,
|
|
const bool _doHardConstraints = false);
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedO>
|
|
IGL_INLINE bool angle_bound_frame_fields(const AngleBoundFFSolverData<DerivedV, DerivedF> &csdata,
|
|
const typename DerivedV::Scalar &thetaMin,
|
|
const Eigen::VectorXi &isConstrained,
|
|
const Eigen::PlainObjectBase<DerivedO> &initialSolution,
|
|
Eigen::PlainObjectBase<DerivedO> &output,
|
|
int _maxIter = 50,
|
|
const typename DerivedV::Scalar &_lambdaInit = 100,
|
|
const typename DerivedV::Scalar &_lambdaMultFactor = 1.5,
|
|
const bool _doHardConstraints = false,
|
|
typename DerivedV::Scalar *lambdaOut = NULL);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "angle_bound_frame_fields.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_ANGLE_BOUND_FRAME_FIELDS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_angular_distance = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ANGULAR_DISTANCE_H
|
|
#define IGL_ANGULAR_DISTANCE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Geometry>
|
|
namespace igl
|
|
{
|
|
// The "angular distance" between two unit quaternions is the angle of the
|
|
// smallest rotation (treated as an Axis and Angle) that takes A to B.
|
|
//
|
|
// Inputs:
|
|
// A unit quaternion
|
|
// B unit quaternion
|
|
// Returns angular distance
|
|
IGL_INLINE double angular_distance(
|
|
const Eigen::Quaterniond & A,
|
|
const Eigen::Quaterniond & B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "angular_distance.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_any_of = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ANY_OF_H
|
|
#define IGL_ANY_OF_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Wrapper for STL `any_of` for matrix types
|
|
//
|
|
// Inputs:
|
|
// S matrix
|
|
// Returns whether any entries are true
|
|
//
|
|
// Seems that Eigen (now) implements this for `Eigen::Array`
|
|
template <typename Mat>
|
|
IGL_INLINE bool any_of(const Mat & S);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "any_of.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_arap = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ARAP_H
|
|
#define IGL_ARAP_H
|
|
#include "igl_inline.h"
|
|
#include "min_quad_with_fixed.h"
|
|
#include "ARAPEnergyType.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
struct ARAPData
|
|
{
|
|
// n #V
|
|
// G #V list of group indices (1 to k) for each vertex, such that vertex i
|
|
// is assigned to group G(i)
|
|
// energy type of energy to use
|
|
// with_dynamics whether using dynamics (need to call arap_precomputation
|
|
// after changing)
|
|
// f_ext #V by dim list of external forces
|
|
// vel #V by dim list of velocities
|
|
// h dynamics time step
|
|
// ym ~Young's modulus smaller is softer, larger is more rigid/stiff
|
|
// max_iter maximum inner iterations
|
|
// K rhs pre-multiplier
|
|
// M mass matrix
|
|
// solver_data quadratic solver data
|
|
// b list of boundary indices into V
|
|
// dim dimension being used for solving
|
|
int n;
|
|
Eigen::VectorXi G;
|
|
ARAPEnergyType energy;
|
|
bool with_dynamics;
|
|
Eigen::MatrixXd f_ext,vel;
|
|
double h;
|
|
double ym;
|
|
int max_iter;
|
|
Eigen::SparseMatrix<double> K,M;
|
|
Eigen::SparseMatrix<double> CSM;
|
|
min_quad_with_fixed_data<double> solver_data;
|
|
Eigen::VectorXi b;
|
|
int dim;
|
|
ARAPData():
|
|
n(0),
|
|
G(),
|
|
energy(ARAP_ENERGY_TYPE_DEFAULT),
|
|
with_dynamics(false),
|
|
f_ext(),
|
|
h(1),
|
|
ym(1),
|
|
max_iter(10),
|
|
K(),
|
|
CSM(),
|
|
solver_data(),
|
|
b(),
|
|
dim(-1) // force this to be set by _precomputation
|
|
{
|
|
};
|
|
};
|
|
|
|
// Compute necessary information to start using an ARAP deformation
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh positions
|
|
// F #F by simplex-size list of triangle|tet indices into V
|
|
// dim dimension being used at solve time. For deformation usually dim =
|
|
// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
|
|
// b #b list of "boundary" fixed vertex indices into V
|
|
// Outputs:
|
|
// data struct containing necessary precomputation
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename Derivedb>
|
|
IGL_INLINE bool arap_precomputation(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const int dim,
|
|
const Eigen::PlainObjectBase<Derivedb> & b,
|
|
ARAPData & data);
|
|
// Inputs:
|
|
// bc #b by dim list of boundary conditions
|
|
// data struct containing necessary precomputation and parameters
|
|
// U #V by dim initial guess
|
|
template <
|
|
typename Derivedbc,
|
|
typename DerivedU>
|
|
IGL_INLINE bool arap_solve(
|
|
const Eigen::PlainObjectBase<Derivedbc> & bc,
|
|
ARAPData & data,
|
|
Eigen::PlainObjectBase<DerivedU> & U);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "arap.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_arap_dof = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ARAP_ENERGY_TYPE_DOF_H
|
|
#define IGL_ARAP_ENERGY_TYPE_DOF_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
#include "ARAPEnergyType.h"
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Caller example:
|
|
//
|
|
// Once:
|
|
// arap_dof_precomputation(...)
|
|
//
|
|
// Each frame:
|
|
// while(not satisfied)
|
|
// arap_dof_update(...)
|
|
// end
|
|
|
|
template <typename LbsMatrixType, typename SSCALAR>
|
|
struct ArapDOFData;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Arap DOF precomputation consists of two parts the computation. The first is
|
|
// that which depends solely on the mesh (V,F), the linear blend skinning
|
|
// weights (M) and the groups G. Then there's the part that depends on the
|
|
// previous precomputation and the list of free and fixed vertices.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// The code and variables differ from the description in Section 3 of "Fast
|
|
// Automatic Skinning Transformations" by [Jacobson et al. 2012]
|
|
//
|
|
// Here is a useful conversion table:
|
|
//
|
|
// [article] [code]
|
|
// S = \tilde{K} T S = CSM * Lsep
|
|
// S --> R S --> R --shuffled--> Rxyz
|
|
// Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz
|
|
// Pi_1 \tilde{K} CSolveBlock1
|
|
// Peq = [T_full; P_pos]
|
|
// T_full B_eq_fix <--- L0
|
|
// P_pos B_eq
|
|
// Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3
|
|
// Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix
|
|
// Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq
|
|
// T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3
|
|
//
|
|
|
|
// Precomputes the system we are going to optimize. This consists of building
|
|
// constructor matrices (to compute covariance matrices from transformations
|
|
// and to build the poisson solve right hand side from rotation matrix entries)
|
|
// and also prefactoring the poisson system.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// F #F by {3|4} list of face indices
|
|
// M #V * dim by #handles * dim * (dim+1) matrix such that
|
|
// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
|
|
// vectors formed by the entries in each handle's dim by dim+1
|
|
// transformation matrix. Specifcally, A =
|
|
// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
|
|
// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
|
|
// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
|
|
// handles are ordered according to P then BE (point handles before bone
|
|
// handles)
|
|
// G #V list of group indices (1 to k) for each vertex, such that vertex i
|
|
// is assigned to group G(i)
|
|
// Outputs:
|
|
// data structure containing all necessary precomputation for calling
|
|
// arap_dof_update
|
|
// Returns true on success, false on error
|
|
//
|
|
// See also: lbs_matrix_column
|
|
template <typename LbsMatrixType, typename SSCALAR>
|
|
IGL_INLINE bool arap_dof_precomputation(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const LbsMatrixType & M,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
|
|
ArapDOFData<LbsMatrixType, SSCALAR> & data);
|
|
|
|
// Should always be called after arap_dof_precomputation, but may be called in
|
|
// between successive calls to arap_dof_update, recomputes precomputation
|
|
// given that there are only changes in free and fixed
|
|
//
|
|
// Inputs:
|
|
// fixed_dim list of transformation element indices for fixed (or partailly
|
|
// fixed) handles: not necessarily the complement of 'free'
|
|
// NOTE: the constraints for fixed transformations still need to be
|
|
// present in A_eq
|
|
// A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality
|
|
// constraint coefficients. Each row corresponds to a linear constraint,
|
|
// so that A_eq * L = Beq says that the linear transformation entries in
|
|
// the column L should produce the user supplied positional constraints
|
|
// for each handle in Beq. The row A_eq(i*dim+d) corresponds to the
|
|
// constrain on coordinate d of position i
|
|
// Outputs:
|
|
// data structure containing all necessary precomputation for calling
|
|
// arap_dof_update
|
|
// Returns true on success, false on error
|
|
//
|
|
// See also: lbs_matrix_column
|
|
template <typename LbsMatrixType, typename SSCALAR>
|
|
IGL_INLINE bool arap_dof_recomputation(
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
|
|
const Eigen::SparseMatrix<double> & A_eq,
|
|
ArapDOFData<LbsMatrixType, SSCALAR> & data);
|
|
|
|
// Optimizes the transformations attached to each weight function based on
|
|
// precomputed system.
|
|
//
|
|
// Inputs:
|
|
// data precomputation data struct output from arap_dof_precomputation
|
|
// Beq dim*#constraint_points constraint values.
|
|
// L0 #handles * dim * dim+1 list of initial guess transformation entries,
|
|
// also holds fixed transformation entries for fixed handles
|
|
// max_iters maximum number of iterations
|
|
// tol stopping critera parameter. If variables (linear transformation
|
|
// matrix entries) change by less than 'tol' the optimization terminates,
|
|
// 0.75 (weak tolerance)
|
|
// 0.0 (extreme tolerance)
|
|
// Outputs:
|
|
// L #handles * dim * dim+1 list of final optimized transformation entries,
|
|
// allowed to be the same as L
|
|
template <typename LbsMatrixType, typename SSCALAR>
|
|
IGL_INLINE bool arap_dof_update(
|
|
const ArapDOFData<LbsMatrixType,SSCALAR> & data,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
|
|
const Eigen::MatrixXd & L0,
|
|
const int max_iters,
|
|
const double tol,
|
|
Eigen::MatrixXd & L
|
|
);
|
|
|
|
// Structure that contains fields for all precomputed data or data that needs
|
|
// to be remembered at update
|
|
template <typename LbsMatrixType, typename SSCALAR>
|
|
struct ArapDOFData
|
|
{
|
|
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
|
|
// Type of arap energy we're solving
|
|
igl::ARAPEnergyType energy;
|
|
//// LU decomposition precomptation data; note: not used by araf_dop_update
|
|
//// any more, replaced by M_FullSolve
|
|
//igl::min_quad_with_fixed_data<double> lu_data;
|
|
// List of indices of fixed transformation entries
|
|
Eigen::Matrix<int,Eigen::Dynamic,1> fixed_dim;
|
|
// List of precomputed covariance scatter matrices multiplied by lbs
|
|
// matrices
|
|
//std::vector<Eigen::SparseMatrix<double> > CSM_M;
|
|
std::vector<Eigen::MatrixXd> CSM_M;
|
|
LbsMatrixType M_KG;
|
|
// Number of mesh vertices
|
|
int n;
|
|
// Number of weight functions
|
|
int m;
|
|
// Number of dimensions
|
|
int dim;
|
|
// Effective dimensions
|
|
int effective_dim;
|
|
// List of indices into C of positional constraints
|
|
Eigen::Matrix<int,Eigen::Dynamic,1> interpolated;
|
|
std::vector<bool> free_mask;
|
|
// Full quadratic coefficients matrix before lagrangian (should be dense)
|
|
LbsMatrixType Q;
|
|
|
|
|
|
//// Solve matrix for the global step
|
|
//Eigen::MatrixXd M_Solve; // TODO: remove from here
|
|
|
|
// Full solve matrix that contains also conversion from rotations to the right hand side,
|
|
// i.e., solves Poisson transformations just from rotations and positional constraints
|
|
MatrixXS M_FullSolve;
|
|
|
|
// Precomputed condensed matrices (3x3 commutators folded to 1x1):
|
|
MatrixXS CSM;
|
|
MatrixXS CSolveBlock1;
|
|
|
|
// Print timings at each update
|
|
bool print_timings;
|
|
|
|
// Dynamics
|
|
bool with_dynamics;
|
|
// I'm hiding the extra dynamics stuff in this struct, which sort of defeats
|
|
// the purpose of this function-based coding style...
|
|
|
|
// Time step
|
|
double h;
|
|
|
|
// L0 #handles * dim * dim+1 list of transformation entries from
|
|
// previous solve
|
|
MatrixXS L0;
|
|
//// Lm1 #handles * dim * dim+1 list of transformation entries from
|
|
//// previous-previous solve
|
|
//MatrixXS Lm1;
|
|
// "Velocity"
|
|
MatrixXS Lvel0;
|
|
|
|
// #V by dim matrix of external forces
|
|
// fext
|
|
MatrixXS fext;
|
|
|
|
// Mass_tilde: MT * Mass * M
|
|
LbsMatrixType Mass_tilde;
|
|
|
|
// Force due to gravity (premultiplier)
|
|
Eigen::MatrixXd fgrav;
|
|
// Direction of gravity
|
|
Eigen::Vector3d grav_dir;
|
|
// Magnitude of gravity
|
|
double grav_mag;
|
|
|
|
// Π1 from the paper
|
|
MatrixXS Pi_1;
|
|
|
|
// Default values
|
|
ArapDOFData():
|
|
energy(igl::ARAP_ENERGY_TYPE_SPOKES),
|
|
with_dynamics(false),
|
|
h(1),
|
|
grav_dir(0,-1,0),
|
|
grav_mag(0)
|
|
{
|
|
}
|
|
};
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "arap_dof.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_arap_linear_block = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ARAP_LINEAR_BLOCK_H
|
|
#define IGL_ARAP_LINEAR_BLOCK_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Sparse>
|
|
#include <igl/ARAPEnergyType.h>
|
|
|
|
namespace igl
|
|
{
|
|
// ARAP_LINEAR_BLOCK constructs a block of the matrix which constructs the
|
|
// linear terms of a given arap energy. When treating rotations as knowns
|
|
// (arranged in a column) then this constructs Kd of K such that the linear
|
|
// portion of the energy is as a column:
|
|
// K * R = [Kx Z ... Ky Z ...
|
|
// Z Kx ... Z Ky ...
|
|
// ... ]
|
|
// These blocks are also used to build the "covariance scatter matrices".
|
|
// Here we want to build a scatter matrix that multiplies against positions
|
|
// (treated as known) producing covariance matrices to fit each rotation.
|
|
// Notice that in the case of the RHS of the poisson solve the rotations are
|
|
// known and the positions unknown, and vice versa for rotation fitting.
|
|
// These linear block just relate the rotations to the positions, linearly in
|
|
// each.
|
|
//
|
|
// Templates:
|
|
// MatV vertex position matrix, e.g. Eigen::MatrixXd
|
|
// MatF face index matrix, e.g. Eigen::MatrixXd
|
|
// Scalar e.g. double
|
|
// Inputs:
|
|
// V #V by dim list of initial domain positions
|
|
// F #F by #simplex size list of triangle indices into V
|
|
// d coordinate of linear constructor to build
|
|
// energy ARAPEnergyType enum value defining which energy is being used.
|
|
// See ARAPEnergyType.h for valid options and explanations.
|
|
// Outputs:
|
|
// Kd #V by #V/#F block of the linear constructor matrix corresponding to
|
|
// coordinate d
|
|
//
|
|
template <typename MatV, typename MatF, typename Scalar>
|
|
IGL_INLINE void arap_linear_block(
|
|
const MatV & V,
|
|
const MatF & F,
|
|
const int d,
|
|
const igl::ARAPEnergyType energy,
|
|
Eigen::SparseMatrix<Scalar> & Kd);
|
|
// Helper functions for each energy type
|
|
template <typename MatV, typename MatF, typename Scalar>
|
|
IGL_INLINE void arap_linear_block_spokes(
|
|
const MatV & V,
|
|
const MatF & F,
|
|
const int d,
|
|
Eigen::SparseMatrix<Scalar> & Kd);
|
|
template <typename MatV, typename MatF, typename Scalar>
|
|
IGL_INLINE void arap_linear_block_spokes_and_rims(
|
|
const MatV & V,
|
|
const MatF & F,
|
|
const int d,
|
|
Eigen::SparseMatrix<Scalar> & Kd);
|
|
template <typename MatV, typename MatF, typename Scalar>
|
|
IGL_INLINE void arap_linear_block_elements(
|
|
const MatV & V,
|
|
const MatF & F,
|
|
const int d,
|
|
Eigen::SparseMatrix<Scalar> & Kd);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "arap_linear_block.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_arap_rhs = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ARAP_RHS_H
|
|
#define IGL_ARAP_RHS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
#include <igl/ARAPEnergyType.h>
|
|
|
|
namespace igl
|
|
{
|
|
// ARAP_RHS build right-hand side constructor of global poisson solve for
|
|
// various Arap energies
|
|
// Inputs:
|
|
// V #V by Vdim list of initial domain positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// dim dimension being used at solve time. For deformation usually dim =
|
|
// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
|
|
// energy igl::ARAPEnergyType enum value defining which energy is being
|
|
// used. See igl::ARAPEnergyType.h for valid options and explanations.
|
|
// Outputs:
|
|
// K #V*dim by #(F|V)*dim*dim matrix such that:
|
|
// b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
|
|
//
|
|
// See also: arap_linear_block
|
|
IGL_INLINE void arap_rhs(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const int dim,
|
|
const igl::ARAPEnergyType energy,
|
|
Eigen::SparseMatrix<double>& K);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "arap_rhs.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ARAPEnergyType = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ARAPENERGYTYPE_H
|
|
#define IGL_ARAPENERGYTYPE_H
|
|
namespace igl
|
|
{
|
|
// ARAP_ENERGY_TYPE_SPOKES "As-rigid-as-possible Surface Modeling" by [Sorkine and
|
|
// Alexa 2007], rotations defined at vertices affecting incident edges,
|
|
// default
|
|
// ARAP_ENERGY_TYPE_SPOKES-AND-RIMS Adapted version of "As-rigid-as-possible Surface
|
|
// Modeling" by [Sorkine and Alexa 2007] presented in section 4.2 of or
|
|
// "A simple geometric model for elastic deformation" by [Chao et al.
|
|
// 2010], rotations defined at vertices affecting incident edges and
|
|
// opposite edges
|
|
// ARAP_ENERGY_TYPE_ELEMENTS "A local-global approach to mesh parameterization" by
|
|
// [Liu et al. 2010] or "A simple geometric model for elastic
|
|
// deformation" by [Chao et al. 2010], rotations defined at elements
|
|
// (triangles or tets)
|
|
// ARAP_ENERGY_TYPE_DEFAULT Choose one automatically: spokes and rims
|
|
// for surfaces, elements for planar meshes and tets (not fully
|
|
// supported)
|
|
enum ARAPEnergyType
|
|
{
|
|
ARAP_ENERGY_TYPE_SPOKES = 0,
|
|
ARAP_ENERGY_TYPE_SPOKES_AND_RIMS = 1,
|
|
ARAP_ENERGY_TYPE_ELEMENTS = 2,
|
|
ARAP_ENERGY_TYPE_DEFAULT = 3,
|
|
NUM_ARAP_ENERGY_TYPES = 4
|
|
};
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_average_onto_faces = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_AVERAGE_ONTO_FACES_H
|
|
#define IGL_AVERAGE_ONTO_FACES_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// average_onto_vertices
|
|
// Move a scalar field defined on faces to vertices by averaging
|
|
//
|
|
// Input:
|
|
// V,F: mesh
|
|
// S: scalar field defined on vertices, Vx1
|
|
//
|
|
// Output:
|
|
// SV: scalar field defined on faces
|
|
template <typename T, typename I>
|
|
IGL_INLINE void average_onto_faces(
|
|
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
|
|
const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
|
|
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
|
|
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "average_onto_faces.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_average_onto_vertices = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_AVERAGE_ONTO_VERTICES_H
|
|
#define IGL_AVERAGE_ONTO_VERTICES_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// average_onto_vertices
|
|
// Move a scalar field defined on faces to vertices by averaging
|
|
//
|
|
// Input:
|
|
// V,F: mesh
|
|
// S: scalar field defined on faces, Fx1
|
|
//
|
|
// Output:
|
|
// SV: scalar field defined on vertices
|
|
template <typename T, typename I>
|
|
IGL_INLINE void average_onto_vertices(
|
|
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
|
|
const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
|
|
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
|
|
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SV);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "average_onto_vertices.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_avg_edge_length = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_AVERAGEEDGELENGTH_H
|
|
#define IGL_AVERAGEEDGELENGTH_H
|
|
|
|
#include "igl/igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Compute the average edge length for the given triangle mesh
|
|
// Templates:
|
|
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
|
|
// DerivedF derived from face indices matrix type: i.e. MatrixXi
|
|
// DerivedL derived from edge lengths matrix type: i.e. MatrixXd
|
|
// Inputs:
|
|
// V eigen matrix #V by 3
|
|
// F #F by simplex-size list of mesh faces (must be simplex)
|
|
// Outputs:
|
|
// l average edge length
|
|
//
|
|
// See also: adjacency_matrix
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE double avg_edge_length(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "avg_edge_length.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_axis_angle_to_quat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_AXIS_ANGLE_TO_QUAT_H
|
|
#define IGL_AXIS_ANGLE_TO_QUAT_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Convert axis angle representation of a rotation to a quaternion
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
// Inputs:
|
|
// axis 3d vector
|
|
// angle scalar
|
|
// Outputs:
|
|
// quaternion
|
|
template <typename Q_type>
|
|
IGL_INLINE void axis_angle_to_quat(
|
|
const Q_type *axis,
|
|
const Q_type angle,
|
|
Q_type *out);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "axis_angle_to_quat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_barycenter = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BARYCENTER_H
|
|
#define IGL_BARYCENTER_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// BARYCENTER
|
|
//
|
|
// B = barycenter(V,F)
|
|
//
|
|
// Compute the barycenter of every simplex
|
|
//
|
|
// Inputs:
|
|
// V #V x dim matrix of vertex coordinates
|
|
// F #F x simplex_size matrix of indices of simplex corners
|
|
// Output:
|
|
// BC a #F x dim matrix of 3d vertices
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedBC>
|
|
IGL_INLINE void barycenter(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedBC> & BC);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "barycenter.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_barycentric_coordinates = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BARYCENTRIC_COORDINATES_H
|
|
#define IGL_BARYCENTRIC_COORDINATES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute barycentric coordinates in a tet
|
|
//
|
|
// Inputs:
|
|
// P #P by 3 Query points in 3d
|
|
// A #P by 3 Tet corners in 3d
|
|
// B #P by 3 Tet corners in 3d
|
|
// C #P by 3 Tet corners in 3d
|
|
// D #P by 3 Tet corners in 3d
|
|
// Outputs:
|
|
// L #P by 4 list of barycentric coordinates
|
|
//
|
|
template <
|
|
typename DerivedP,
|
|
typename DerivedA,
|
|
typename DerivedB,
|
|
typename DerivedC,
|
|
typename DerivedD,
|
|
typename DerivedL>
|
|
IGL_INLINE void barycentric_coordinates(
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedD> & D,
|
|
Eigen::PlainObjectBase<DerivedL> & L);
|
|
// Compute barycentric coordinates in a triangle
|
|
//
|
|
// Inputs:
|
|
// P #P by 2 Query points in 2d
|
|
// A #P by 2 Triangle corners in 2d
|
|
// B #P by 2 Triangle corners in 2d
|
|
// C #P by 2 Triangle corners in 2d
|
|
// Outputs:
|
|
// L #P by e list of barycentric coordinates
|
|
//
|
|
// Known bugs: this code is not tested (and probably will not work) for
|
|
// triangles and queries in 3D even if the query lives in/on the triangle.
|
|
template <
|
|
typename DerivedP,
|
|
typename DerivedA,
|
|
typename DerivedB,
|
|
typename DerivedC,
|
|
typename DerivedL>
|
|
IGL_INLINE void barycentric_coordinates(
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::PlainObjectBase<DerivedL> & L);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "barycentric_coordinates.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_barycentric_to_global = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BARYCENTRIC2GLOBAL_H
|
|
#define IGL_BARYCENTRIC2GLOBAL_H
|
|
#include <igl/igl_inline.h>
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Converts barycentric coordinates in the embree form to 3D coordinates
|
|
// Embree stores barycentric coordinates as triples: fid, bc1, bc2
|
|
// fid is the id of a face, bc1 is the displacement of the point wrt the
|
|
// first vertex v0 and the edge v1-v0. Similarly, bc2 is the displacement
|
|
// wrt v2-v0.
|
|
//
|
|
// Input:
|
|
// V: #Vx3 Vertices of the mesh
|
|
// F: #Fxe Faces of the mesh
|
|
// bc: #Xx3 Barycentric coordinates, one row per point
|
|
//
|
|
// Output:
|
|
// #X: #Xx3 3D coordinates of all points in bc
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
|
barycentric_to_global(
|
|
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
|
|
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
|
|
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "barycentric_to_global.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_basename = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BASENAME_H
|
|
#define IGL_BASENAME_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// Function like PHP's basename: /etc/sudoers.d --> sudoers.d
|
|
// Input:
|
|
// path string containing input path
|
|
// Returns string containing basename (see php's basename)
|
|
//
|
|
// See also: dirname, pathinfo
|
|
IGL_INLINE std::string basename(const std::string & path);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "basename.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_bfs_orient = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BFS_ORIENT_H
|
|
#define IGL_BFS_ORIENT_H
|
|
#include <Eigen/Core>
|
|
#include <igl/igl_inline.h>
|
|
|
|
namespace igl
|
|
{
|
|
// Consistently orient faces in orientable patches using BFS
|
|
//
|
|
// F = bfs_orient(F,V);
|
|
//
|
|
// Inputs:
|
|
// F #F by 3 list of faces
|
|
// Outputs:
|
|
// FF #F by 3 list of faces (OK if same as F)
|
|
// C #F list of component ids
|
|
//
|
|
//
|
|
template <typename DerivedF, typename DerivedFF, typename DerivedC>
|
|
IGL_INLINE void bfs_orient(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
};
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "bfs_orient.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_biharmonic_coordinates = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BIHARMONIC_COORDINATES_H
|
|
#define IGL_BIHARMONIC_COORDINATES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Compute "discrete biharmonic generalized barycentric coordinates" as
|
|
// described in "Linear Subspace Design for Real-Time Shape Deformation"
|
|
// [Wang et al. 2015]. Not to be confused with "Bounded Biharmonic Weights
|
|
// for Real-Time Deformation" [Jacobson et al. 2011] or "Biharmonic
|
|
// Coordinates" (2D complex barycentric coordinates) [Weber et al. 2012].
|
|
// These weights minimize a discrete version of the squared Laplacian energy
|
|
// subject to positional interpolation constraints at selected vertices
|
|
// (point handles) and transformation interpolation constraints at regions
|
|
// (region handles).
|
|
//
|
|
// Templates:
|
|
// HType should be a simple index type e.g. `int`,`size_t`
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// T #T by dim+1 list of / triangle indices into V if dim=2
|
|
// \ tetrahedron indices into V if dim=3
|
|
// S #point-handles+#region-handles list of lists of selected vertices for
|
|
// each handle. Point handles should have singleton lists and region
|
|
// handles should have lists of size at least dim+1 (and these points
|
|
// should be in general position).
|
|
// Outputs:
|
|
// W #V by #points-handles+(#region-handles * dim+1) matrix of weights so
|
|
// that columns correspond to each handles generalized barycentric
|
|
// coordinates (for point-handles) or animation space weights (for region
|
|
// handles).
|
|
// returns true only on success
|
|
//
|
|
// Example:
|
|
//
|
|
// MatrixXd W;
|
|
// igl::biharmonic_coordinates(V,F,S,W);
|
|
// const size_t dim = T.cols()-1;
|
|
// MatrixXd H(W.cols(),dim);
|
|
// {
|
|
// int c = 0;
|
|
// for(int h = 0;h<S.size();h++)
|
|
// {
|
|
// if(S[h].size()==1)
|
|
// {
|
|
// H.row(c++) = V.block(S[h][0],0,1,dim);
|
|
// }else
|
|
// {
|
|
// H.block(c,0,dim+1,dim).setIdentity();
|
|
// c+=dim+1;
|
|
// }
|
|
// }
|
|
// }
|
|
// assert( (V-(W*H)).array().maxCoeff() < 1e-7 );
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedT,
|
|
typename SType,
|
|
typename DerivedW>
|
|
IGL_INLINE bool biharmonic_coordinates(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedT> & T,
|
|
const std::vector<std::vector<SType> > & S,
|
|
Eigen::PlainObjectBase<DerivedW> & W);
|
|
// k 2-->biharmonic, 3-->triharmonic
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedT,
|
|
typename SType,
|
|
typename DerivedW>
|
|
IGL_INLINE bool biharmonic_coordinates(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedT> & T,
|
|
const std::vector<std::vector<SType> > & S,
|
|
const int k,
|
|
Eigen::PlainObjectBase<DerivedW> & W);
|
|
|
|
};
|
|
# ifndef IGL_STATIC_LIBRARY
|
|
# include "biharmonic_coordinates.cpp"
|
|
# endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_bone_parents = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BONE_PARENTS_H
|
|
#define IGL_BONE_PARENTS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// BONE_PARENTS Recover "parent" bones from directed graph representation.
|
|
//
|
|
// Inputs:
|
|
// BE #BE by 2 list of directed bone edges
|
|
// Outputs:
|
|
// P #BE by 1 list of parent indices into BE, -1 means root.
|
|
//
|
|
template <typename DerivedBE, typename DerivedP>
|
|
IGL_INLINE void bone_parents(
|
|
const Eigen::PlainObjectBase<DerivedBE>& BE,
|
|
Eigen::PlainObjectBase<DerivedP>& P);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "bone_parents.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boundary_conditions = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOUNDARY_CONDITIONS_H
|
|
#define IGL_BOUNDARY_CONDITIONS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
|
|
// Compute boundary conditions for automatic weights computation. This
|
|
// function expects that the given mesh (V,Ele) has sufficient samples
|
|
// (vertices) exactly at point handle locations and exactly along bone and
|
|
// cage edges.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of domain vertices
|
|
// Ele #Ele by simplex-size list of simplex indices
|
|
// C #C by dim list of handle positions
|
|
// P #P by 1 list of point handle indices into C
|
|
// BE #BE by 2 list of bone edge indices into C
|
|
// CE #CE by 2 list of cage edge indices into *P*
|
|
// Outputs:
|
|
// b #b list of boundary indices (indices into V of vertices which have
|
|
// known, fixed values)
|
|
// bc #b by #weights list of known/fixed values for boundary vertices
|
|
// (notice the #b != #weights in general because #b will include all the
|
|
// intermediary samples along each bone, etc.. The ordering of the
|
|
// weights corresponds to [P;BE]
|
|
// Returns true if boundary conditions make sense
|
|
IGL_INLINE bool boundary_conditions(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::VectorXi & P,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::MatrixXi & CE,
|
|
Eigen::VectorXi & b,
|
|
Eigen::MatrixXd & bc);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "boundary_conditions.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boundary_facets = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOUNDARY_FACETS_H
|
|
#define IGL_BOUNDARY_FACETS_H
|
|
#include "igl_inline.h"
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Dense>
|
|
#endif
|
|
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles)
|
|
// stored in T (analogous to qptoolbox's `outline` and `boundary_faces`).
|
|
//
|
|
// Templates:
|
|
// IntegerT integer-value: e.g. int
|
|
// IntegerF integer-value: e.g. int
|
|
// Input:
|
|
// T tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
|
|
// Output:
|
|
// F list of boundary faces, n by 3 (2), where n is the number of boundary faces
|
|
//
|
|
//
|
|
template <typename IntegerT, typename IntegerF>
|
|
IGL_INLINE void boundary_facets(
|
|
const std::vector<std::vector<IntegerT> > & T,
|
|
std::vector<std::vector<IntegerF> > & F);
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
// Templates:
|
|
// DerivedT integer-value: i.e. from MatrixXi
|
|
// DerivedF integer-value: i.e. from MatrixXi
|
|
template <typename DerivedT, typename DerivedF>
|
|
IGL_INLINE void boundary_facets(
|
|
const Eigen::PlainObjectBase<DerivedT>& T,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
// Same as above but returns F
|
|
template <typename DerivedT, typename Ret>
|
|
Ret boundary_facets(
|
|
const Eigen::PlainObjectBase<DerivedT>& T);
|
|
#endif
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "boundary_facets.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boundary_loop = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOUNDARY_LOOP_H
|
|
#define IGL_BOUNDARY_LOOP_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Compute list of ordered boundary loops for a manifold mesh.
|
|
//
|
|
// Templates:
|
|
// Index index type
|
|
// Inputs:
|
|
// F #V by dim list of mesh faces
|
|
// Outputs:
|
|
// L list of loops where L[i] = ordered list of boundary vertices in loop i
|
|
//
|
|
template <typename DerivedF, typename Index>
|
|
IGL_INLINE void boundary_loop(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::vector<std::vector<Index> >& L);
|
|
|
|
|
|
// Compute ordered boundary loops for a manifold mesh and return the
|
|
// longest loop in terms of vertices.
|
|
//
|
|
// Templates:
|
|
// Index index type
|
|
// Inputs:
|
|
// F #V by dim list of mesh faces
|
|
// Outputs:
|
|
// L ordered list of boundary vertices of longest boundary loop
|
|
//
|
|
template <typename DerivedF, typename Index>
|
|
IGL_INLINE void boundary_loop(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::vector<Index>& L);
|
|
|
|
// Compute ordered boundary loops for a manifold mesh and return the
|
|
// longest loop in terms of vertices.
|
|
//
|
|
// Templates:
|
|
// Index index type
|
|
// Inputs:
|
|
// F #V by dim list of mesh faces
|
|
// Outputs:
|
|
// L ordered list of boundary vertices of longest boundary loop
|
|
//
|
|
template <typename DerivedF, typename DerivedL>
|
|
IGL_INLINE void boundary_loop(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedL>& L);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "boundary_loop.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_bounding_box = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOUNDING_BOX_H
|
|
#define IGL_BOUNDING_BOX_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Build a triangle mesh of the bounding box of a given list of vertices
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of rest domain positions
|
|
// Outputs:
|
|
// BV 2^dim by dim list of bounding box corners positions
|
|
// BF #BF by dim list of simplex facets
|
|
template <typename DerivedV, typename DerivedBV, typename DerivedBF>
|
|
IGL_INLINE void bounding_box(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedBV>& BV,
|
|
Eigen::PlainObjectBase<DerivedBF>& BF);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "bounding_box.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_bounding_box_diagonal = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOUNDING_BOX_DIAGONAL_H
|
|
#define IGL_BOUNDING_BOX_DIAGONAL_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Compute the length of the diagonal of a given meshes axis-aligned bounding
|
|
// box
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// Returns length of bounding box diagonal
|
|
IGL_INLINE double bounding_box_diagonal( const Eigen::MatrixXd & V);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "bounding_box_diagonal.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_C_STR = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_C_STR_H
|
|
#define IGL_C_STR_H
|
|
// http://stackoverflow.com/a/2433143/148668
|
|
// Suppose you have a function:
|
|
// void func(const char * c);
|
|
// Then you can write:
|
|
// func(C_STR("foo"<<1<<"bar"));
|
|
#include <sstream>
|
|
#include <string>
|
|
#define C_STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str().c_str()
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_Camera = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CAMERA_H
|
|
#define IGL_CAMERA_H
|
|
|
|
// you're idiot, M$!
|
|
#if defined(_WIN32)
|
|
#undef far
|
|
#undef near
|
|
#endif
|
|
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/Core>
|
|
|
|
#define IGL_CAMERA_MIN_ANGLE 5.0
|
|
namespace igl
|
|
{
|
|
|
|
// A simple camera class. The camera stores projection parameters (field of
|
|
// view angle, aspect ratio, near and far clips) as well as a rigid
|
|
// tranformation *of the camera as if it were also a scene object*. Thus, the
|
|
// **inverse** of this rigid transformation is the modelview transformation.
|
|
class Camera
|
|
{
|
|
public:
|
|
// On windows you might need: -fno-delayed-template-parsing
|
|
//static constexpr double IGL_CAMERA_MIN_ANGLE = 5.;
|
|
// m_angle Field of view angle in degrees {45}
|
|
// m_aspect Aspect ratio {1}
|
|
// m_near near clipping plane {1e-2}
|
|
// m_far far clipping plane {100}
|
|
// m_at_dist distance of looking at point {1}
|
|
// m_orthographic whether to use othrographic projection {false}
|
|
// m_rotation_conj Conjugate of rotation part of rigid transformation of
|
|
// camera {identity}. Note: we purposefully store the conjugate because
|
|
// this is what TW_TYPE_QUAT4D is expecting.
|
|
// m_translation Translation part of rigid transformation of camera
|
|
// {(0,0,1)}
|
|
double m_angle, m_aspect, m_near, m_far, m_at_dist;
|
|
bool m_orthographic;
|
|
Eigen::Quaterniond m_rotation_conj;
|
|
Eigen::Vector3d m_translation;
|
|
public:
|
|
inline Camera();
|
|
inline virtual ~Camera(){}
|
|
// Return projection matrix that takes relative camera coordinates and
|
|
// transforms it to viewport coordinates
|
|
//
|
|
// Note:
|
|
//
|
|
// if(m_angle > 0)
|
|
// {
|
|
// gluPerspective(m_angle,m_aspect,m_near,m_at_dist+m_far);
|
|
// }else
|
|
// {
|
|
// gluOrtho(-0.5*aspect,0.5*aspect,-0.5,0.5,m_at_dist+m_near,m_far);
|
|
// }
|
|
//
|
|
// Is equivalent to
|
|
//
|
|
// glMultMatrixd(projection().data());
|
|
//
|
|
inline Eigen::Matrix4d projection() const;
|
|
// Return an Affine transformation (rigid actually) that takes a world 3d coordinate and
|
|
// transforms it into the relative camera coordinates.
|
|
inline Eigen::Affine3d affine() const;
|
|
// Return an Affine transformation (rigid actually) that takes relative
|
|
// coordinates and tramsforms them into world 3d coordinates.
|
|
//
|
|
// Note:
|
|
//
|
|
// gluLookAt(
|
|
// eye()(0), eye()(1), eye()(2),
|
|
// at()(0), at()(1), at()(2),
|
|
// up()(0), up()(1), up()(2));
|
|
//
|
|
// Is equivalent to
|
|
//
|
|
// glMultMatrixd(camera.affine().matrix().data());
|
|
//
|
|
// See also: affine, eye, at, up
|
|
inline Eigen::Affine3d inverse() const;
|
|
// Returns world coordinates position of center or "eye" of camera.
|
|
inline Eigen::Vector3d eye() const;
|
|
// Returns world coordinate position of a point "eye" is looking at.
|
|
inline Eigen::Vector3d at() const;
|
|
// Returns world coordinate unit vector of "up" vector
|
|
inline Eigen::Vector3d up() const;
|
|
// Return top right corner of unit plane in relative coordinates, that is
|
|
// (w/2,h/2,1)
|
|
inline Eigen::Vector3d unit_plane() const;
|
|
// Move dv in the relative coordinate frame of the camera (move the FPS)
|
|
//
|
|
// Inputs:
|
|
// dv (x,y,z) displacement vector
|
|
//
|
|
inline void dolly(const Eigen::Vector3d & dv);
|
|
// "Scale zoom": Move `eye`, but leave `at`
|
|
//
|
|
// Input:
|
|
// s amount to scale distance to at
|
|
inline void push_away(const double s);
|
|
// Aka "Hitchcock", "Vertigo", "Spielberg" or "Trombone" zoom:
|
|
// simultaneously dolly while changing angle so that `at` not only stays
|
|
// put in relative coordinates but also projected coordinates. That is
|
|
//
|
|
// Inputs:
|
|
// da change in angle in degrees
|
|
inline void dolly_zoom(const double da);
|
|
// Turn around eye so that rotation is now q
|
|
//
|
|
// Inputs:
|
|
// q new rotation as quaternion
|
|
inline void turn_eye(const Eigen::Quaterniond & q);
|
|
// Orbit around at so that rotation is now q
|
|
//
|
|
// Inputs:
|
|
// q new rotation as quaternion
|
|
inline void orbit(const Eigen::Quaterniond & q);
|
|
// Rotate and translate so that camera is situated at "eye" looking at "at"
|
|
// with "up" pointing up.
|
|
//
|
|
// Inputs:
|
|
// eye (x,y,z) coordinates of eye position
|
|
// at (x,y,z) coordinates of at position
|
|
// up (x,y,z) coordinates of up vector
|
|
inline void look_at(
|
|
const Eigen::Vector3d & eye,
|
|
const Eigen::Vector3d & at,
|
|
const Eigen::Vector3d & up);
|
|
// Needed any time Eigen Structures are used as class members
|
|
// http://eigen.tuxfamily.org/dox-devel/group__TopicStructHavingEigenMembers.html
|
|
public:
|
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
|
};
|
|
}
|
|
|
|
// Implementation
|
|
#include "PI.h"
|
|
#include "EPS.h"
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <cassert>
|
|
|
|
inline igl::Camera::Camera():
|
|
m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1),
|
|
m_orthographic(false),
|
|
m_rotation_conj(1,0,0,0),
|
|
m_translation(0,0,1)
|
|
{
|
|
}
|
|
|
|
inline Eigen::Matrix4d igl::Camera::projection() const
|
|
{
|
|
Eigen::Matrix4d P;
|
|
using namespace std;
|
|
const double far = m_at_dist + m_far;
|
|
const double near = m_near;
|
|
// http://stackoverflow.com/a/3738696/148668
|
|
if(m_orthographic)
|
|
{
|
|
const double f = 0.5;
|
|
const double left = -f*m_aspect;
|
|
const double right = f*m_aspect;
|
|
const double bottom = -f;
|
|
const double top = f;
|
|
const double tx = (right+left)/(right-left);
|
|
const double ty = (top+bottom)/(top-bottom);
|
|
const double tz = (far+near)/(far-near);
|
|
const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (M_PI/180.) );
|
|
P<<
|
|
z_fix*2./(right-left), 0, 0, -tx,
|
|
0, z_fix*2./(top-bottom), 0, -ty,
|
|
0, 0, -z_fix*2./(far-near), -tz,
|
|
0, 0, 0, 1;
|
|
}else
|
|
{
|
|
const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
|
|
// http://stackoverflow.com/a/14975139/148668
|
|
const double xScale = yScale/m_aspect;
|
|
P<<
|
|
xScale, 0, 0, 0,
|
|
0, yScale, 0, 0,
|
|
0, 0, -(far+near)/(far-near), -1,
|
|
0, 0, -2.*near*far/(far-near), 0;
|
|
P = P.transpose().eval();
|
|
}
|
|
return P;
|
|
}
|
|
|
|
inline Eigen::Affine3d igl::Camera::affine() const
|
|
{
|
|
using namespace Eigen;
|
|
Affine3d t = Affine3d::Identity();
|
|
t.rotate(m_rotation_conj.conjugate());
|
|
t.translate(m_translation);
|
|
return t;
|
|
}
|
|
|
|
inline Eigen::Affine3d igl::Camera::inverse() const
|
|
{
|
|
using namespace Eigen;
|
|
Affine3d t = Affine3d::Identity();
|
|
t.translate(-m_translation);
|
|
t.rotate(m_rotation_conj);
|
|
return t;
|
|
}
|
|
|
|
inline Eigen::Vector3d igl::Camera::eye() const
|
|
{
|
|
using namespace Eigen;
|
|
return affine() * Vector3d(0,0,0);
|
|
}
|
|
|
|
inline Eigen::Vector3d igl::Camera::at() const
|
|
{
|
|
using namespace Eigen;
|
|
return affine() * (Vector3d(0,0,-1)*m_at_dist);
|
|
}
|
|
|
|
inline Eigen::Vector3d igl::Camera::up() const
|
|
{
|
|
using namespace Eigen;
|
|
Affine3d t = Affine3d::Identity();
|
|
t.rotate(m_rotation_conj.conjugate());
|
|
return t * Vector3d(0,1,0);
|
|
}
|
|
|
|
inline Eigen::Vector3d igl::Camera::unit_plane() const
|
|
{
|
|
// Distance of center pixel to eye
|
|
const double d = 1.0;
|
|
const double a = m_aspect;
|
|
const double theta = m_angle*PI/180.;
|
|
const double w =
|
|
2.*sqrt(-d*d/(a*a*pow(tan(0.5*theta),2.)-1.))*a*tan(0.5*theta);
|
|
const double h = w/a;
|
|
return Eigen::Vector3d(w*0.5,h*0.5,-d);
|
|
}
|
|
|
|
inline void igl::Camera::dolly(const Eigen::Vector3d & dv)
|
|
{
|
|
m_translation += dv;
|
|
}
|
|
|
|
inline void igl::Camera::push_away(const double s)
|
|
{
|
|
using namespace Eigen;
|
|
#ifndef NDEBUG
|
|
Vector3d old_at = at();
|
|
#endif
|
|
const double old_at_dist = m_at_dist;
|
|
m_at_dist = old_at_dist * s;
|
|
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
|
|
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
|
|
}
|
|
|
|
inline void igl::Camera::dolly_zoom(const double da)
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
#ifndef NDEBUG
|
|
Vector3d old_at = at();
|
|
#endif
|
|
const double old_angle = m_angle;
|
|
if(old_angle + da < IGL_CAMERA_MIN_ANGLE)
|
|
{
|
|
m_orthographic = true;
|
|
}else if(old_angle + da > IGL_CAMERA_MIN_ANGLE)
|
|
{
|
|
m_orthographic = false;
|
|
}
|
|
if(!m_orthographic)
|
|
{
|
|
m_angle += da;
|
|
m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle));
|
|
// change in distance
|
|
const double s =
|
|
(2.*tan(old_angle/2./180.*M_PI)) /
|
|
(2.*tan(m_angle/2./180.*M_PI)) ;
|
|
const double old_at_dist = m_at_dist;
|
|
m_at_dist = old_at_dist * s;
|
|
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
|
|
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
|
|
}
|
|
}
|
|
|
|
inline void igl::Camera::turn_eye(const Eigen::Quaterniond & q)
|
|
{
|
|
using namespace Eigen;
|
|
Vector3d old_eye = eye();
|
|
// eye should be fixed
|
|
//
|
|
// eye_1 = R_1 * t_1 = eye_0
|
|
// t_1 = R_1' * eye_0
|
|
m_rotation_conj = q.conjugate();
|
|
m_translation = m_rotation_conj * old_eye;
|
|
assert((old_eye - eye()).squaredNorm() < DOUBLE_EPS);
|
|
}
|
|
|
|
inline void igl::Camera::orbit(const Eigen::Quaterniond & q)
|
|
{
|
|
using namespace Eigen;
|
|
Vector3d old_at = at();
|
|
// at should be fixed
|
|
//
|
|
// at_1 = R_1 * t_1 - R_1 * z = at_0
|
|
// t_1 = R_1' * (at_0 + R_1 * z)
|
|
m_rotation_conj = q.conjugate();
|
|
m_translation =
|
|
m_rotation_conj *
|
|
(old_at +
|
|
m_rotation_conj.conjugate() * Vector3d(0,0,1) * m_at_dist);
|
|
assert((old_at - at()).squaredNorm() < DOUBLE_EPS);
|
|
}
|
|
|
|
inline void igl::Camera::look_at(
|
|
const Eigen::Vector3d & eye,
|
|
const Eigen::Vector3d & at,
|
|
const Eigen::Vector3d & up)
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
// http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
|
|
// Normalize vector from at to eye
|
|
Vector3d F = eye-at;
|
|
m_at_dist = F.norm();
|
|
F.normalize();
|
|
// Project up onto plane orthogonal to F and normalize
|
|
assert(up.cross(F).norm() > DOUBLE_EPS && "(eye-at) x up ≈ 0");
|
|
const Vector3d proj_up = (up-(up.dot(F))*F).normalized();
|
|
Quaterniond a,b;
|
|
a.setFromTwoVectors(Vector3d(0,0,-1),-F);
|
|
b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up);
|
|
m_rotation_conj = (b*a).conjugate();
|
|
m_translation = m_rotation_conj * eye;
|
|
//cout<<"m_at_dist: "<<m_at_dist<<endl;
|
|
//cout<<"proj_up: "<<proj_up.transpose()<<endl;
|
|
//cout<<"F: "<<F.transpose()<<endl;
|
|
//cout<<"eye(): "<<this->eye().transpose()<<endl;
|
|
//cout<<"at(): "<<this->at().transpose()<<endl;
|
|
//cout<<"eye()-at(): "<<(this->eye()-this->at()).normalized().transpose()<<endl;
|
|
//cout<<"eye-this->eye(): "<<(eye-this->eye()).squaredNorm()<<endl;
|
|
assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS);
|
|
assert((F-(this->eye()-this->at()).normalized()).squaredNorm() <
|
|
DOUBLE_EPS);
|
|
assert( (at-this->at()).squaredNorm() < DOUBLE_EPS);
|
|
assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS);
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_canonical_quaternions = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CANONICAL_QUATERNIONS_H
|
|
#define IGL_CANONICAL_QUATERNIONS_H
|
|
#include "igl_inline.h"
|
|
// Define some canonical quaternions for floats and doubles
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
namespace igl
|
|
{
|
|
// Float versions
|
|
#define SQRT_2_OVER_2 0.707106781f
|
|
// Identity
|
|
const float IDENTITY_QUAT_F[4] = {0,0,0,1};
|
|
// The following match the Matlab canonical views
|
|
// X point right, Y pointing up and Z point out
|
|
const float XY_PLANE_QUAT_F[4] = {0,0,0,1};
|
|
// X points right, Y points *in* and Z points up
|
|
const float XZ_PLANE_QUAT_F[4] = {-SQRT_2_OVER_2,0,0,SQRT_2_OVER_2};
|
|
// X points out, Y points right, and Z points up
|
|
const float YZ_PLANE_QUAT_F[4] = {-0.5,-0.5,-0.5,0.5};
|
|
const float CANONICAL_VIEW_QUAT_F[][4] =
|
|
{
|
|
{ 0, 0, 0, 1}, // 0
|
|
{ 0, 0, SQRT_2_OVER_2, SQRT_2_OVER_2}, // 1
|
|
{ 0, 0, 1, 0}, // 2
|
|
{ 0, 0, SQRT_2_OVER_2,-SQRT_2_OVER_2}, // 3
|
|
|
|
{ 0, -1, 0, 0}, // 4
|
|
{-SQRT_2_OVER_2, SQRT_2_OVER_2, 0, 0}, // 5
|
|
{ -1, 0, 0, 0}, // 6
|
|
{-SQRT_2_OVER_2,-SQRT_2_OVER_2, 0, 0}, // 7
|
|
|
|
{ -0.5, -0.5, -0.5, 0.5}, // 8
|
|
{ 0,-SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, // 9
|
|
{ 0.5, -0.5, 0.5, 0.5}, // 10
|
|
{ SQRT_2_OVER_2, 0, SQRT_2_OVER_2, 0}, // 11
|
|
|
|
{ SQRT_2_OVER_2, 0,-SQRT_2_OVER_2, 0}, // 12
|
|
{ 0.5, 0.5, -0.5, 0.5}, // 13
|
|
{ 0, SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, // 14
|
|
{ -0.5, 0.5, 0.5, 0.5}, // 15
|
|
|
|
{ 0, SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, // 16
|
|
{ -0.5, 0.5, 0.5, -0.5}, // 17
|
|
{-SQRT_2_OVER_2, 0, 0,-SQRT_2_OVER_2}, // 18
|
|
{ -0.5, -0.5, -0.5, -0.5}, // 19
|
|
|
|
{-SQRT_2_OVER_2, 0, 0, SQRT_2_OVER_2}, // 20
|
|
{ -0.5, -0.5, 0.5, 0.5}, // 21
|
|
{ 0,-SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, // 22
|
|
{ 0.5, -0.5, 0.5, -0.5} // 23
|
|
};
|
|
#undef SQRT_2_OVER_2
|
|
// Double versions
|
|
#define SQRT_2_OVER_2 0.70710678118654757
|
|
// Identity
|
|
const double IDENTITY_QUAT_D[4] = {0,0,0,1};
|
|
// The following match the Matlab canonical views
|
|
// X point right, Y pointing up and Z point out
|
|
const double XY_PLANE_QUAT_D[4] = {0,0,0,1};
|
|
// X points right, Y points *in* and Z points up
|
|
const double XZ_PLANE_QUAT_D[4] = {-SQRT_2_OVER_2,0,0,SQRT_2_OVER_2};
|
|
// X points out, Y points right, and Z points up
|
|
const double YZ_PLANE_QUAT_D[4] = {-0.5,-0.5,-0.5,0.5};
|
|
const double CANONICAL_VIEW_QUAT_D[][4] =
|
|
{
|
|
{ 0, 0, 0, 1},
|
|
{ 0, 0, SQRT_2_OVER_2, SQRT_2_OVER_2},
|
|
{ 0, 0, 1, 0},
|
|
{ 0, 0, SQRT_2_OVER_2,-SQRT_2_OVER_2},
|
|
|
|
{ 0, -1, 0, 0},
|
|
{-SQRT_2_OVER_2, SQRT_2_OVER_2, 0, 0},
|
|
{ -1, 0, 0, 0},
|
|
{-SQRT_2_OVER_2,-SQRT_2_OVER_2, 0, 0},
|
|
|
|
{ -0.5, -0.5, -0.5, 0.5},
|
|
{ 0,-SQRT_2_OVER_2, 0, SQRT_2_OVER_2},
|
|
{ 0.5, -0.5, 0.5, 0.5},
|
|
{ SQRT_2_OVER_2, 0, SQRT_2_OVER_2, 0},
|
|
|
|
{ SQRT_2_OVER_2, 0,-SQRT_2_OVER_2, 0},
|
|
{ 0.5, 0.5, -0.5, 0.5},
|
|
{ 0, SQRT_2_OVER_2, 0, SQRT_2_OVER_2},
|
|
{ -0.5, 0.5, 0.5, 0.5},
|
|
|
|
{ 0, SQRT_2_OVER_2, SQRT_2_OVER_2, 0},
|
|
{ -0.5, 0.5, 0.5, -0.5},
|
|
{-SQRT_2_OVER_2, 0, 0,-SQRT_2_OVER_2},
|
|
{ -0.5, -0.5, -0.5, -0.5},
|
|
|
|
{-SQRT_2_OVER_2, 0, 0, SQRT_2_OVER_2},
|
|
{ -0.5, -0.5, 0.5, 0.5},
|
|
{ 0,-SQRT_2_OVER_2, SQRT_2_OVER_2, 0},
|
|
{ 0.5, -0.5, 0.5, -0.5}
|
|
};
|
|
#undef SQRT_2_OVER_2
|
|
#define NUM_CANONICAL_VIEW_QUAT 24
|
|
|
|
// NOTE: I want to rather be able to return a Q_type[][] but C++ is not
|
|
// making it easy. So instead I've written a per-element accessor
|
|
|
|
// Return element [i][j] of the corresponding CANONICAL_VIEW_QUAT_* of the
|
|
// given templated type
|
|
// Inputs:
|
|
// i index of quaternion
|
|
// j index of coordinate in quaternion i
|
|
// Returns values of CANONICAL_VIEW_QUAT_*[i][j]
|
|
template <typename Q_type>
|
|
IGL_INLINE Q_type CANONICAL_VIEW_QUAT(int i, int j);
|
|
// Template specializations for float and double
|
|
template <>
|
|
IGL_INLINE float CANONICAL_VIEW_QUAT<float>(int i, int j);
|
|
template <>
|
|
IGL_INLINE double CANONICAL_VIEW_QUAT<double>(int i, int j);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "canonical_quaternions.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CAT_H
|
|
#define IGL_CAT_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Sparse>
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// If you're using Dense matrices you might be better off using the << operator
|
|
|
|
// This is an attempt to act like matlab's cat function.
|
|
|
|
// Perform concatenation of a two matrices along a single dimension
|
|
// If dim == 1, then C = [A;B]. If dim == 2 then C = [A B]
|
|
//
|
|
// Template:
|
|
// Scalar scalar data type for sparse matrices like double or int
|
|
// Mat matrix type for all matrices (e.g. MatrixXd, SparseMatrix)
|
|
// MatC matrix type for ouput matrix (e.g. MatrixXd) needs to support
|
|
// resize
|
|
// Inputs:
|
|
// A first input matrix
|
|
// B second input matrix
|
|
// dim dimension along which to concatenate, 0 or 1
|
|
// Outputs:
|
|
// C output matrix
|
|
//
|
|
template <typename Scalar>
|
|
IGL_INLINE void cat(
|
|
const int dim,
|
|
const Eigen::SparseMatrix<Scalar> & A,
|
|
const Eigen::SparseMatrix<Scalar> & B,
|
|
Eigen::SparseMatrix<Scalar> & C);
|
|
template <typename Derived, class MatC>
|
|
IGL_INLINE void cat(
|
|
const int dim,
|
|
const Eigen::MatrixBase<Derived> & A,
|
|
const Eigen::MatrixBase<Derived> & B,
|
|
MatC & C);
|
|
// Wrapper that returns C
|
|
template <class Mat>
|
|
IGL_INLINE Mat cat(const int dim, const Mat & A, const Mat & B);
|
|
|
|
// Note: Maybe we can autogenerate a bunch of overloads D = cat(int,A,B,C),
|
|
// E = cat(int,A,B,C,D), etc.
|
|
|
|
// Concatenate a "matrix" of blocks
|
|
// C = [A0;A1;A2;...;An] where Ai = [A[i][0] A[i][1] ... A[i][m]];
|
|
//
|
|
// Inputs:
|
|
// A a matrix (vector of row vectors)
|
|
// Output:
|
|
// C
|
|
template <class Mat>
|
|
IGL_INLINE void cat(const std::vector<std::vector< Mat > > & A, Mat & C);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "cat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ceil = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CEIL_H
|
|
#define IGL_CEIL_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Ceil a given matrix to nearest integers
|
|
//
|
|
// Inputs:
|
|
// X m by n matrix of scalars
|
|
// Outputs:
|
|
// Y m by n matrix of ceiled integers
|
|
template < typename DerivedX, typename DerivedY>
|
|
IGL_INLINE void ceil(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
Eigen::PlainObjectBase<DerivedY>& Y);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "ceil.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_centroid = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CENTROID_H
|
|
#define IGL_CENTROID_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// CENTROID Computes the centroid of a closed mesh using a surface integral.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of rest domain positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// Outputs:
|
|
// c dim vector of centroid coordinates
|
|
// vol total volume of solid.
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename Derivedc,
|
|
typename Derivedvol>
|
|
IGL_INLINE void centroid(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<Derivedc>& c,
|
|
Derivedvol & vol);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename Derivedc>
|
|
IGL_INLINE void centroid(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<Derivedc>& c);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "centroid.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_circulation = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CIRCULATION_H
|
|
#define IGL_CIRCULATION_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Return list of faces around the end point of an edge. Assumes
|
|
// data-structures are built from an edge-manifold **closed** mesh.
|
|
//
|
|
// Inputs:
|
|
// e index into E of edge to circulate
|
|
// ccw whether to _continue_ in ccw direction of edge (circulate around
|
|
// E(e,1))
|
|
// F #F by 3 list of face indices
|
|
// E #E by 2 list of edge indices
|
|
// EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
|
// unique edge in E
|
|
// EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
|
|
// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
|
|
// e=(j->i)
|
|
// EI #E by 2 list of edge flap corners (see above).
|
|
// Returns list of faces touched by circulation.
|
|
//
|
|
IGL_INLINE std::vector<int> circulation(
|
|
const int e,
|
|
const bool ccw,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXi & E,
|
|
const Eigen::VectorXi & EMAP,
|
|
const Eigen::MatrixXi & EF,
|
|
const Eigen::MatrixXi & EI);
|
|
// Wrapper with VectorXi output.
|
|
IGL_INLINE void circulation(
|
|
const int e,
|
|
const bool ccw,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXi & E,
|
|
const Eigen::VectorXi & EMAP,
|
|
const Eigen::MatrixXi & EF,
|
|
const Eigen::MatrixXi & EI,
|
|
Eigen::VectorXi & vN);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "circulation.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_collapse_edge = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COLLAPSE_EDGE_H
|
|
#define IGL_COLLAPSE_EDGE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
#include <set>
|
|
namespace igl
|
|
{
|
|
// Assumes (V,F) is a closed manifold mesh (except for previouslly collapsed
|
|
// faces which should be set to:
|
|
// [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL].
|
|
// Collapses exactly two faces and exactly 3 edges from E (e and one side of
|
|
// each face gets collapsed to the other). This is implemented in a way that
|
|
// it can be repeatedly called until satisfaction and then the garbage in F
|
|
// can be collected by removing NULL faces.
|
|
//
|
|
// Inputs:
|
|
// e index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so
|
|
// that s<d, then d is collapsed to s.
|
|
/// p dim list of vertex position where to place merged vertex
|
|
// Inputs/Outputs:
|
|
// V #V by dim list of vertex positions, lesser index of E(e,:) will be set
|
|
// to midpoint of edge.
|
|
// F #F by 3 list of face indices into V.
|
|
// E #E by 2 list of edge indices into V.
|
|
// EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
|
// unique edge in E
|
|
// EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
|
|
// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
|
|
// e=(j->i)
|
|
// EI #E by 2 list of edge flap corners (see above).
|
|
// e1 index into E of edge collpased on left
|
|
// e2 index into E of edge collpased on left
|
|
// f1 index into E of edge collpased on left
|
|
// f2 index into E of edge collpased on left
|
|
// Returns true if edge was collapsed
|
|
#define IGL_COLLAPSE_EDGE_NULL 0
|
|
IGL_INLINE bool collapse_edge(
|
|
const int e,
|
|
const Eigen::RowVectorXd & p,
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & E,
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EI,
|
|
int & e1,
|
|
int & e2,
|
|
int & f1,
|
|
int & f2);
|
|
IGL_INLINE bool collapse_edge(
|
|
const int e,
|
|
const Eigen::RowVectorXd & p,
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & E,
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EI);
|
|
// Collapse least-cost edge from a priority queue and update queue
|
|
//
|
|
// Inputs/Outputs:
|
|
// cost_and_placement function computing cost of collapsing an edge and 3d
|
|
// position where it should be placed:
|
|
// cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
|
|
// Q queue containing pairs of costs and edge indices
|
|
// Qit list of iterators so that Qit[e] --> iterator of edge e in Q
|
|
// C #E by dim list of stored placements
|
|
IGL_INLINE bool collapse_edge(
|
|
const std::function<void(
|
|
const int,
|
|
const Eigen::MatrixXd &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::VectorXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
double &,
|
|
Eigen::RowVectorXd &)> & cost_and_placement,
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & E,
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EI,
|
|
std::set<std::pair<double,int> > & Q,
|
|
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
|
Eigen::MatrixXd & C);
|
|
IGL_INLINE bool collapse_edge(
|
|
const std::function<void(
|
|
const int,
|
|
const Eigen::MatrixXd &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::VectorXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
double &,
|
|
Eigen::RowVectorXd &)> & cost_and_placement,
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & E,
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EI,
|
|
std::set<std::pair<double,int> > & Q,
|
|
std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
|
|
Eigen::MatrixXd & C,
|
|
int & e,
|
|
int & e1,
|
|
int & e2,
|
|
int & f1,
|
|
int & f2);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "collapse_edge.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_collapse_small_triangles = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COLLAPSE_SMALL_TRIANGLES_H
|
|
#define IGL_COLLAPSE_SMALL_TRIANGLES_H
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Given a triangle mesh (V,F) compute a new mesh (VV,FF) which contains the
|
|
// original faces and vertices of (V,F) except any small triangles have been
|
|
// removed via collapse.
|
|
//
|
|
// We are *not* following the rules in "Mesh Optimization" [Hoppe et al]
|
|
// Section 4.2. But for our purposes we don't care about this criteria.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// eps epsilon for smallest allowed area treated as fraction of squared bounding box
|
|
// diagonal
|
|
// Outputs:
|
|
// FF #FF by 3 list of triangle indices into V
|
|
//
|
|
//
|
|
void collapse_small_triangles(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const double eps,
|
|
Eigen::MatrixXi & FF);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "collapse_small_triangles.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_colon = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COLON_H
|
|
#define IGL_COLON_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Note:
|
|
// This should be potentially replaced with eigen's LinSpaced() function
|
|
//
|
|
// If step = 1, it's about 5 times faster to use:
|
|
// X = Eigen::VectorXi::LinSpaced(n,0,n-1);
|
|
// than
|
|
// X = igl::colon<int>(0,n-1);
|
|
//
|
|
|
|
// Colon operator like matlab's colon operator. Enumerats values between low
|
|
// and hi with step step.
|
|
// Templates:
|
|
// L should be a eigen matrix primitive type like int or double
|
|
// S should be a eigen matrix primitive type like int or double
|
|
// H should be a eigen matrix primitive type like int or double
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// low starting value if step is valid then this is *always* the first
|
|
// element of I
|
|
// step step difference between sequential elements returned in I,
|
|
// remember this will be cast to template T at compile time. If low<hi
|
|
// then step must be positive. If low>hi then step must be negative.
|
|
// Otherwise I will be set to empty.
|
|
// hi ending value, if (hi-low)%step is zero then this will be the last
|
|
// element in I. If step is positive there will be no elements greater
|
|
// than hi, vice versa if hi<low
|
|
// Output:
|
|
// I list of values from low to hi with step size step
|
|
template <typename L,typename S,typename H,typename T>
|
|
IGL_INLINE void colon(
|
|
const L low,
|
|
const S step,
|
|
const H hi,
|
|
Eigen::Matrix<T,Eigen::Dynamic,1> & I);
|
|
// Same as above but step == (T)1
|
|
template <typename L,typename H,typename T>
|
|
IGL_INLINE void colon(
|
|
const L low,
|
|
const H hi,
|
|
Eigen::Matrix<T,Eigen::Dynamic,1> & I);
|
|
// Return output rather than set in reference
|
|
template <typename T,typename L,typename H>
|
|
IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> colon(
|
|
const L low,
|
|
const H hi);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "colon.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_column_to_quats = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COLUMN_TO_QUATS_H
|
|
#define IGL_COLUMN_TO_QUATS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/StdVector>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// "Columnize" a list of quaternions (q1x,q1y,q1z,q1w,q2x,q2y,q2z,q2w,...)
|
|
//
|
|
// Inputs:
|
|
// Q n*4-long list of coefficients
|
|
// Outputs:
|
|
// vQ n-long list of quaternions
|
|
// Returns false if n%4!=0
|
|
IGL_INLINE bool column_to_quats(
|
|
const Eigen::VectorXd & Q,
|
|
std::vector<
|
|
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "column_to_quats.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_columnize = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COLUMNIZE_H
|
|
#define IGL_COLUMNIZE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// "Columnize" a stack of block matrices. If A = [A1,A2,A3,...,Ak] with each A*
|
|
// an m by n block then this produces the column vector whose entries are
|
|
// B(j*m*k+i*k+b) = A(i,b*n+j);
|
|
// or if A = [A1;A2;...;Ak] then
|
|
// B(j*m*k+i*k+b) = A(i+b*m,j);
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// A m*k by n (dim: 1) or m by n*k (dim: 2) eigen Matrix of type T values
|
|
// k number of blocks
|
|
// dim dimension in which blocks are stacked
|
|
// Output
|
|
// B m*n*k eigen vector of type T values,
|
|
//
|
|
// See also: transpose_blocks
|
|
template <typename DerivedA, typename DerivedB>
|
|
IGL_INLINE void columnize(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const int k,
|
|
const int dim,
|
|
Eigen::PlainObjectBase<DerivedB> & B);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "columnize.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_comb_cross_field = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_COMB_CROSS_FIELD_H
|
|
#define IGL_COMB_CROSS_FIELD_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Computes principal matchings of the vectors of a cross field across face edges,
|
|
// and generates a combed cross field defined on the mesh faces
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 4 eigen Matrix of face (quad) indices
|
|
// PD1in #F by 3 eigen Matrix of the first per face cross field vector
|
|
// PD2in #F by 3 eigen Matrix of the second per face cross field vector
|
|
// Output:
|
|
// PD1out #F by 3 eigen Matrix of the first combed cross field vector
|
|
// PD2out #F by 3 eigen Matrix of the second combed cross field vector
|
|
//
|
|
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void comb_cross_field(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD1in,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD2in,
|
|
Eigen::PlainObjectBase<DerivedV> &PD1out,
|
|
Eigen::PlainObjectBase<DerivedV> &PD2out);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "comb_cross_field.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_comb_frame_field = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_COMB_FRAME_FIELD_H
|
|
#define IGL_COMB_FRAME_FIELD_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Computes principal matchings of the vectors of a frame field across face edges,
|
|
// and generates a combed frame field defined on the mesh faces. This makes use of a
|
|
// combed cross field generated by combing the field created by the bisectors of the
|
|
// frame field.
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 4 eigen Matrix of face (quad) indices
|
|
// PD1 #F by 3 eigen Matrix of the first per face cross field vector
|
|
// PD2 #F by 3 eigen Matrix of the second per face cross field vector
|
|
// BIS1_combed #F by 3 eigen Matrix of the first combed bisector field vector
|
|
// BIS2_combed #F by 3 eigen Matrix of the second combed bisector field vector
|
|
// Output:
|
|
// PD1_combed #F by 3 eigen Matrix of the first combed cross field vector
|
|
// PD2_combed #F by 3 eigen Matrix of the second combed cross field vector
|
|
//
|
|
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedP>
|
|
IGL_INLINE void comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedP> &PD1,
|
|
const Eigen::PlainObjectBase<DerivedP> &PD2,
|
|
const Eigen::PlainObjectBase<DerivedP> &BIS1_combed,
|
|
const Eigen::PlainObjectBase<DerivedP> &BIS2_combed,
|
|
Eigen::PlainObjectBase<DerivedP> &PD1_combed,
|
|
Eigen::PlainObjectBase<DerivedP> &PD2_combed);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "comb_frame_field.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_comb_line_field = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Nico Pietroni <nico.pietroni@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_COMB_LINE_FIELD_H
|
|
#define IGL_COMB_LINE_FIELD_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Computes principal matchings of the vectors of a cross field across face edges,
|
|
// and generates a combed cross field defined on the mesh faces
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 4 eigen Matrix of face (quad) indices
|
|
// PD1in #F by 3 eigen Matrix of the first per face cross field vector
|
|
// PD2in #F by 3 eigen Matrix of the second per face cross field vector
|
|
// Output:
|
|
// PD1out #F by 3 eigen Matrix of the first combed cross field vector
|
|
// PD2out #F by 3 eigen Matrix of the second combed cross field vector
|
|
//
|
|
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void comb_line_field(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD1in,
|
|
Eigen::PlainObjectBase<DerivedV> &PD1out);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "comb_line_field.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_components = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COMPONENTS_H
|
|
#define IGL_COMPONENTS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Compute connected components of a graph represented by an adjacency
|
|
// matrix. This version is faster than the previous version using boost.
|
|
//
|
|
// Inputs:
|
|
// A n by n adjacency matrix
|
|
// Outputs:
|
|
// C n list of component ids (starting with 0)
|
|
// counts #components list of counts for each component
|
|
//
|
|
template <typename AScalar, typename DerivedC, typename Derivedcounts>
|
|
IGL_INLINE void components(
|
|
const Eigen::SparseMatrix<AScalar> & A,
|
|
Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::PlainObjectBase<Derivedcounts> & counts);
|
|
template <typename AScalar, typename DerivedC>
|
|
IGL_INLINE void components(
|
|
const Eigen::SparseMatrix<AScalar> & A,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
// Ditto but for mesh faces as input. This computes connected components of
|
|
// **vertices** where **edges** establish connectivity.
|
|
//
|
|
// Inputs:
|
|
// F n by 3 list of triangle indices
|
|
// Outputs:
|
|
// C max(F) list of component ids
|
|
template <typename DerivedF, typename DerivedC>
|
|
IGL_INLINE void components(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "components.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_compute_frame_field_bisectors = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_COMPUTE_FRAME_FIELD_BISECTORS_H
|
|
#define IGL_COMPUTE_FRAME_FIELD_BISECTORS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute bisectors of a frame field defined on mesh faces
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (triangle) indices
|
|
// B1 #F by 3 eigen Matrix of face (triangle) base vector 1
|
|
// B2 #F by 3 eigen Matrix of face (triangle) base vector 2
|
|
// PD1 #F by 3 eigen Matrix of the first per face frame field vector
|
|
// PD2 #F by 3 eigen Matrix of the second per face frame field vector
|
|
// Output:
|
|
// BIS1 #F by 3 eigen Matrix of the first per face frame field bisector
|
|
// BIS2 #F by 3 eigen Matrix of the second per face frame field bisector
|
|
//
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void compute_frame_field_bisectors(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedV>& B1,
|
|
const Eigen::PlainObjectBase<DerivedV>& B2,
|
|
const Eigen::PlainObjectBase<DerivedV>& PD1,
|
|
const Eigen::PlainObjectBase<DerivedV>& PD2,
|
|
Eigen::PlainObjectBase<DerivedV>& BIS1,
|
|
Eigen::PlainObjectBase<DerivedV>& BIS2);
|
|
|
|
// Wrapper without given basis vectors.
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void compute_frame_field_bisectors(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedV>& PD1,
|
|
const Eigen::PlainObjectBase<DerivedV>& PD2,
|
|
Eigen::PlainObjectBase<DerivedV>& BIS1,
|
|
Eigen::PlainObjectBase<DerivedV>& BIS2);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "compute_frame_field_bisectors.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_conjugate_frame_fields = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_CONJUGATE_FRAME_FIELDS
|
|
#define IGL_CONJUGATE_FRAME_FIELDS
|
|
#include "igl_inline.h"
|
|
#include "ConjugateFFSolverData.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
//todo
|
|
// TODO: isConstrained should become a list of indices for consistency with
|
|
// n_polyvector
|
|
/// Given 2 vectors centered on origin calculate the rotation matrix from first to the second
|
|
|
|
// Inputs:
|
|
// v0, v1 the two #3 by 1 vectors
|
|
// normalized boolean, if false, then the vectors are normalized prior to the calculation
|
|
// Output:
|
|
// 3 by 3 rotation matrix that takes v0 to v1
|
|
//
|
|
template <typename DerivedV, typename DerivedF>
|
|
class ConjugateFFSolverData;
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedO>
|
|
IGL_INLINE void conjugate_frame_fields(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::VectorXi &isConstrained,
|
|
const Eigen::PlainObjectBase<DerivedO> &initialSolution,
|
|
Eigen::PlainObjectBase<DerivedO> &output,
|
|
int _maxIter = 50,
|
|
const typename DerivedV::Scalar &_lambdaOrtho = .1,
|
|
const typename DerivedV::Scalar &_lambdaInit = 100,
|
|
const typename DerivedV::Scalar &_lambdaMultFactor = 1.01,
|
|
bool _doHardConstraints = true);
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedO>
|
|
IGL_INLINE void conjugate_frame_fields(const ConjugateFFSolverData<DerivedV, DerivedF> &csdata,
|
|
const Eigen::VectorXi &isConstrained,
|
|
const Eigen::PlainObjectBase<DerivedO> &initialSolution,
|
|
Eigen::PlainObjectBase<DerivedO> &output,
|
|
int _maxIter = 50,
|
|
const typename DerivedV::Scalar &_lambdaOrtho = .1,
|
|
const typename DerivedV::Scalar &_lambdaInit = 100,
|
|
const typename DerivedV::Scalar &_lambdaMultFactor = 1.01,
|
|
bool _doHardConstraints = true,
|
|
typename DerivedV::Scalar *lambdaOut = NULL);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "conjugate_frame_fields.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_CONJUGATE_FRAME_FIELDS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ConjugateFFSolverData = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Olga Diamanti, 2015 Alec Jacobson
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CONJUGATE_FF_SOLVER_DATA_H
|
|
#define IGL_CONJUGATE_FF_SOLVER_DATA_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl {
|
|
template <typename DerivedV, typename DerivedF>
|
|
class ConjugateFFSolverData
|
|
{
|
|
public:
|
|
const Eigen::PlainObjectBase<DerivedV> &V; int numV;
|
|
const Eigen::PlainObjectBase<DerivedF> &F; int numF;
|
|
|
|
Eigen::MatrixXi EV; int numE;
|
|
Eigen::MatrixXi F2E;
|
|
Eigen::MatrixXi E2F;
|
|
Eigen::VectorXd K;
|
|
|
|
Eigen::VectorXi isBorderEdge;
|
|
int numInteriorEdges;
|
|
Eigen::Matrix<int,Eigen::Dynamic,2> E2F_int;
|
|
Eigen::VectorXi indInteriorToFull;
|
|
Eigen::VectorXi indFullToInterior;
|
|
|
|
Eigen::PlainObjectBase<DerivedV> B1, B2, FN;
|
|
|
|
|
|
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic,1> kmin, kmax;
|
|
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic,2> dmin, dmax;
|
|
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic,3> dmin3, dmax3;
|
|
|
|
Eigen::VectorXd nonPlanarityMeasure;
|
|
Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > planarityWeight;
|
|
|
|
//conjugacy matrix
|
|
std::vector<Eigen::Matrix<typename DerivedV::Scalar, 4,4> > H;
|
|
|
|
//conjugacy matrix eigenvectors and (scaled) eigenvalues
|
|
std::vector<Eigen::Matrix<typename DerivedV::Scalar, 4,4> > UH;
|
|
std::vector<Eigen::Matrix<typename DerivedV::Scalar, 4,1> > s;
|
|
|
|
//laplacians
|
|
Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> DDA, DDB;
|
|
|
|
private:
|
|
IGL_INLINE void computeCurvatureAndPrincipals();
|
|
IGL_INLINE void precomputeConjugacyStuff();
|
|
IGL_INLINE void computeLaplacians();
|
|
IGL_INLINE void computek();
|
|
IGL_INLINE void computeCoefficientLaplacian(int n, Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &D);
|
|
|
|
IGL_INLINE void precomputeInteriorEdges();
|
|
|
|
public:
|
|
IGL_INLINE ConjugateFFSolverData(const Eigen::PlainObjectBase<DerivedV> &_V,
|
|
const Eigen::PlainObjectBase<DerivedF> &_F);
|
|
IGL_INLINE void evaluateConjugacy(const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvU,
|
|
const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvV,
|
|
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &conjValues) const ;
|
|
};
|
|
}
|
|
|
|
#include <igl/colon.h>
|
|
#include <igl/edge_topology.h>
|
|
#include <igl/false_barycentric_subdivision.h>
|
|
#include <igl/local_basis.h>
|
|
#include <igl/principal_curvature.h>
|
|
#include <igl/sparse.h>
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE igl::ConjugateFFSolverData<DerivedV, DerivedF>::
|
|
ConjugateFFSolverData(const Eigen::PlainObjectBase<DerivedV> &_V,
|
|
const Eigen::PlainObjectBase<DerivedF> &_F):
|
|
V(_V),
|
|
numV(_V.rows()),
|
|
F(_F),
|
|
numF(_F.rows())
|
|
{
|
|
igl::edge_topology(V,F,EV,F2E,E2F);
|
|
numE = EV.rows();
|
|
|
|
precomputeInteriorEdges();
|
|
|
|
igl::local_basis(V,F,B1,B2,FN);
|
|
|
|
computek();
|
|
|
|
computeLaplacians();
|
|
|
|
computeCurvatureAndPrincipals();
|
|
precomputeConjugacyStuff();
|
|
|
|
};
|
|
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::computeCurvatureAndPrincipals()
|
|
{
|
|
Eigen::MatrixXd VCBary;
|
|
Eigen::MatrixXi FCBary;
|
|
|
|
VCBary.setZero(numV+numF,3);
|
|
FCBary.setZero(3*numF,3);
|
|
igl::false_barycentric_subdivision(V, F, VCBary, FCBary);
|
|
|
|
Eigen::MatrixXd dmax3_,dmin3_;
|
|
igl::principal_curvature(VCBary, FCBary, dmax3_, dmin3_, kmax, kmin, 5,true);
|
|
|
|
dmax3 = dmax3_.bottomRows(numF);
|
|
dmin3 = dmin3_.bottomRows(numF);
|
|
|
|
kmax = kmax.bottomRows(numF);
|
|
kmin = kmin.bottomRows(numF);
|
|
|
|
// kmax = dmax3.rowwise().norm();
|
|
// kmin = dmin3.rowwise().norm();
|
|
|
|
dmin3.rowwise().normalize();
|
|
dmax3.rowwise().normalize();
|
|
dmax.setZero(numF,2);
|
|
dmin.setZero(numF,2);
|
|
for (int i= 0; i <numF; ++i)
|
|
{
|
|
if(kmin[i] != kmin[i] || kmax[i] != kmax[i] || (dmin3.row(i).array() != dmin3.row(i).array()).any() || (dmax3.row(i).array() != dmax3.row(i).array()).any())
|
|
{
|
|
kmin[i] = 0;
|
|
kmax[i] = 0;
|
|
dmin3.row(i) = B1.row(i);
|
|
dmax3.row(i) = B2.row(i);
|
|
}
|
|
else
|
|
{
|
|
dmax3.row(i) = (dmax3.row(i) - (dmax3.row(i).dot(FN.row(i)))*FN.row(i)).normalized();
|
|
dmin3.row(i) = dmin3.row(i) - (dmin3.row(i).dot(FN.row(i)))*FN.row(i);
|
|
dmin3.row(i) = (dmin3.row(i) - (dmin3.row(i).dot(dmax3.row(i)))*dmax3.row(i)).normalized();
|
|
if ((dmin3.row(i).cross(dmax3.row(i))).dot(FN.row(i))<0)
|
|
dmin3.row(i) = -dmin3.row(i);
|
|
}
|
|
dmax.row(i) << dmax3.row(i).dot(B1.row(i)), dmax3.row(i).dot(B2.row(i));
|
|
dmax.row(i).normalize();
|
|
dmin.row(i) << dmin3.row(i).dot(B1.row(i)), dmin3.row(i).dot(B2.row(i));
|
|
dmin.row(i).normalize();
|
|
|
|
}
|
|
|
|
nonPlanarityMeasure = kmax.cwiseAbs().array()*kmin.cwiseAbs().array();
|
|
typename DerivedV::Scalar minP = nonPlanarityMeasure.minCoeff();
|
|
typename DerivedV::Scalar maxP = nonPlanarityMeasure.maxCoeff();
|
|
nonPlanarityMeasure = (nonPlanarityMeasure.array()-minP)/(maxP-minP);
|
|
Eigen::VectorXi I = igl::colon<typename DerivedF::Scalar>(0, numF-1);
|
|
igl::sparse(I, I, nonPlanarityMeasure, numF, numF, planarityWeight);
|
|
|
|
}
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::precomputeConjugacyStuff()
|
|
{
|
|
H.resize(numF);
|
|
UH.resize(numF);
|
|
s.resize(numF);
|
|
|
|
for (int i = 0; i<numF; ++i)
|
|
{
|
|
//compute conjugacy matrix
|
|
typename DerivedV::Scalar e1x = dmin(i,0), e1y = dmin(i,1), e2x = dmax(i,0), e2y = dmax(i,1), k1 = kmin[i], k2 = kmax[i];
|
|
|
|
H[i]<<
|
|
0, 0, k1*e1x*e1x, k1*e1x*e1y,
|
|
0, 0, k1*e1x*e1y, k1*e1y*e1y,
|
|
k2*e2x*e2x, k2*e2x*e2y, 0, 0,
|
|
k2*e2x*e2y, k2*e2y*e2y, 0, 0;
|
|
Eigen::Matrix<typename DerivedV::Scalar, 4, 4> Ht = H[i].transpose();
|
|
H[i] = .5*(H[i]+Ht);
|
|
|
|
Eigen::EigenSolver<Eigen::Matrix<typename DerivedV::Scalar, 4, 4> > es(H[i]);
|
|
s[i] = es.eigenvalues().real();//ok to do this because H symmetric
|
|
//scale
|
|
s[i] = s[i]/(s[i].cwiseAbs().minCoeff());
|
|
UH[i] = es.eigenvectors().real();
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::computeLaplacians()
|
|
{
|
|
computeCoefficientLaplacian(2, DDA);
|
|
|
|
computeCoefficientLaplacian(4, DDB);
|
|
}
|
|
|
|
template<typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
|
|
precomputeInteriorEdges()
|
|
{
|
|
// Flag border edges
|
|
numInteriorEdges = 0;
|
|
isBorderEdge.setZero(numE,1);
|
|
indFullToInterior = -1*Eigen::VectorXi::Ones(numE,1);
|
|
|
|
for(unsigned i=0; i<numE; ++i)
|
|
{
|
|
if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
|
|
isBorderEdge[i] = 1;
|
|
else
|
|
{
|
|
indFullToInterior[i] = numInteriorEdges;
|
|
numInteriorEdges++;
|
|
}
|
|
}
|
|
|
|
E2F_int.resize(numInteriorEdges, 2);
|
|
indInteriorToFull.setZero(numInteriorEdges,1);
|
|
int ii = 0;
|
|
for (int k=0; k<numE; ++k)
|
|
{
|
|
if (isBorderEdge[k])
|
|
continue;
|
|
E2F_int.row(ii) = E2F.row(k);
|
|
indInteriorToFull[ii] = k;
|
|
ii++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
|
|
computeCoefficientLaplacian(int n, Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &D)
|
|
{
|
|
std::vector<Eigen::Triplet<std::complex<typename DerivedV::Scalar> >> tripletList;
|
|
|
|
// For every non-border edge
|
|
for (unsigned eid=0; eid<numE; ++eid)
|
|
{
|
|
if (!isBorderEdge[eid])
|
|
{
|
|
int fid0 = E2F(eid,0);
|
|
int fid1 = E2F(eid,1);
|
|
|
|
tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0,
|
|
fid0,
|
|
std::complex<typename DerivedV::Scalar>(1.)));
|
|
tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1,
|
|
fid1,
|
|
std::complex<typename DerivedV::Scalar>(1.)));
|
|
tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0,
|
|
fid1,
|
|
-1.*std::polar(1.,-1.*n*K[eid])));
|
|
tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1,
|
|
fid0,
|
|
-1.*std::polar(1.,1.*n*K[eid])));
|
|
|
|
}
|
|
}
|
|
D.resize(numF,numF);
|
|
D.setFromTriplets(tripletList.begin(), tripletList.end());
|
|
|
|
|
|
}
|
|
|
|
template<typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
|
|
computek()
|
|
{
|
|
K.setZero(numE);
|
|
// For every non-border edge
|
|
for (unsigned eid=0; eid<numE; ++eid)
|
|
{
|
|
if (!isBorderEdge[eid])
|
|
{
|
|
int fid0 = E2F(eid,0);
|
|
int fid1 = E2F(eid,1);
|
|
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N0 = FN.row(fid0);
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N1 = FN.row(fid1);
|
|
|
|
// find common edge on triangle 0 and 1
|
|
int fid0_vc = -1;
|
|
int fid1_vc = -1;
|
|
for (unsigned i=0;i<3;++i)
|
|
{
|
|
if (F2E(fid0,i) == eid)
|
|
fid0_vc = i;
|
|
if (F2E(fid1,i) == eid)
|
|
fid1_vc = i;
|
|
}
|
|
assert(fid0_vc != -1);
|
|
assert(fid1_vc != -1);
|
|
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 3> common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
|
|
common_edge.normalize();
|
|
|
|
// Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
|
|
Eigen::Matrix<typename DerivedV::Scalar, 3, 3> P;
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 3> o = V.row(F(fid0,fid0_vc));
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 3> tmp = -N0.cross(common_edge);
|
|
P << common_edge, tmp, N0;
|
|
// P.transposeInPlace();
|
|
|
|
|
|
Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V0;
|
|
V0.row(0) = V.row(F(fid0,0)) -o;
|
|
V0.row(1) = V.row(F(fid0,1)) -o;
|
|
V0.row(2) = V.row(F(fid0,2)) -o;
|
|
|
|
V0 = (P*V0.transpose()).transpose();
|
|
|
|
Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V1;
|
|
V1.row(0) = V.row(F(fid1,0)) -o;
|
|
V1.row(1) = V.row(F(fid1,1)) -o;
|
|
V1.row(2) = V.row(F(fid1,2)) -o;
|
|
V1 = (P*V1.transpose()).transpose();
|
|
|
|
// compute rotation R such that R * N1 = N0
|
|
// i.e. map both triangles to the same plane
|
|
double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
|
|
|
|
Eigen::Matrix<typename DerivedV::Scalar, 3, 3> R;
|
|
R << 1, 0, 0,
|
|
0, cos(alpha), -sin(alpha) ,
|
|
0, sin(alpha), cos(alpha);
|
|
V1 = (R*V1.transpose()).transpose();
|
|
|
|
// measure the angle between the reference frames
|
|
// k_ij is the angle between the triangle on the left and the one on the right
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref0 = V0.row(1) - V0.row(0);
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref1 = V1.row(1) - V1.row(0);
|
|
|
|
ref0.normalize();
|
|
ref1.normalize();
|
|
|
|
double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
|
|
|
|
// just to be sure, rotate ref0 using angle ktemp...
|
|
Eigen::Matrix<typename DerivedV::Scalar, 2, 2> R2;
|
|
R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
|
|
|
|
Eigen::Matrix<typename DerivedV::Scalar, 1, 2> tmp1 = R2*(ref0.head(2)).transpose();
|
|
|
|
K[eid] = ktemp;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
template<typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
|
|
evaluateConjugacy(const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvU,
|
|
const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvV,
|
|
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &conjValues) const
|
|
{
|
|
conjValues.resize(numF,1);
|
|
for (int j =0; j<numF; ++j)
|
|
{
|
|
Eigen::Matrix<typename DerivedV::Scalar, 4, 1> x; x<<pvU.row(j).transpose(), pvV.row(j).transpose();
|
|
conjValues[j] = x.transpose()*H[j]*x;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cotmatrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COTMATRIX_H
|
|
#define IGL_COTMATRIX_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
// History:
|
|
// Used const references rather than copying the entire mesh
|
|
// Alec 9 October 2011
|
|
// removed cotan (uniform weights) optional parameter it was building a buggy
|
|
// half of the uniform laplacian, please see adjacency_matrix istead
|
|
// Alec 9 October 2011
|
|
|
|
namespace igl
|
|
{
|
|
// Constructs the cotangent stiffness matrix (discrete laplacian) for a given
|
|
// mesh (V,F).
|
|
//
|
|
// Templates:
|
|
// DerivedV derived type of eigen matrix for V (e.g. derived from
|
|
// MatrixXd)
|
|
// DerivedF derived type of eigen matrix for F (e.g. derived from
|
|
// MatrixXi)
|
|
// Scalar scalar type for eigen sparse matrix (e.g. double)
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by simplex_size list of mesh faces (must be triangles)
|
|
// Outputs:
|
|
// L #V by #V cotangent matrix, each row i corresponding to V(i,:)
|
|
//
|
|
// See also: adjacency_matrix
|
|
//
|
|
// Note: This Laplacian uses the convention that diagonal entries are
|
|
// **minus** the sum of off-diagonal entries. The diagonal entries are
|
|
// therefore in general negative and the matrix is **negative** semi-definite
|
|
// (immediately, -L is **positive** semi-definite)
|
|
//
|
|
// Known bugs: off by 1e-16 on regular grid. I think its a problem of
|
|
// arithmetic order in cotmatrix_entries.h: C(i,e) = (arithmetic)/dblA/4
|
|
template <typename DerivedV, typename DerivedF, typename Scalar>
|
|
IGL_INLINE void cotmatrix(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::SparseMatrix<Scalar>& L);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "cotmatrix.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cotmatrix_entries = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COTMATRIX_ENTRIES_H
|
|
#define IGL_COTMATRIX_ENTRIES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// COTMATRIX_ENTRIES compute the cotangents of each angle in mesh (V,F)
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of rest domain positions
|
|
// F #F by {3|4} list of {triangle|tetrahedra} indices into V
|
|
// Outputs:
|
|
// C #F by 3 list of 1/2*cotangents corresponding angles
|
|
// for triangles, columns correspond to edges [1,2],[2,0],[0,1]
|
|
// OR
|
|
// C #F by 6 list of 1/6*cotangents of dihedral angles*edge lengths
|
|
// for tets, columns along edges [1,2],[2,0],[0,1],[3,0],[3,1],[3,2]
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedC>
|
|
IGL_INLINE void cotmatrix_entries(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedC>& C);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "cotmatrix_entries.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_covariance_scatter_matrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COVARIANCE_SCATTER_MATRIX_H
|
|
#define IGL_COVARIANCE_SCATTER_MATRIX_H
|
|
|
|
#include "igl_inline.h"
|
|
#include "ARAPEnergyType.h"
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Construct the covariance scatter matrix for a given arap energy
|
|
// Inputs:
|
|
// V #V by Vdim list of initial domain positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// energy ARAPEnergyType enum value defining which energy is being used.
|
|
// See ARAPEnergyType.h for valid options and explanations.
|
|
// Outputs:
|
|
// CSM dim*#V/#F by dim*#V sparse matrix containing special laplacians along
|
|
// the diagonal so that when multiplied by V gives covariance matrix
|
|
// elements, can be used to speed up covariance matrix computation
|
|
IGL_INLINE void covariance_scatter_matrix(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const ARAPEnergyType energy,
|
|
Eigen::SparseMatrix<double>& CSM);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "covariance_scatter_matrix.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cross = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CROSS_H
|
|
#define IGL_CROSS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Computes out = cross(a,b)
|
|
// Inputs:
|
|
// a left 3d vector
|
|
// b right 3d vector
|
|
// Outputs:
|
|
// out result 3d vector
|
|
IGL_INLINE void cross( const double *a, const double *b, double *out);
|
|
// Computes C = cross(A,B,2);
|
|
//
|
|
// Inputs:
|
|
// A #A by 3 list of row-vectors
|
|
// B #A by 3 list of row-vectors
|
|
// Outputs:
|
|
// C #A by 3 list of row-vectors
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedB,
|
|
typename DerivedC>
|
|
IGL_INLINE void cross(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "cross.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cross_field_missmatch = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_CROSS_FIELD_MISSMATCH_H
|
|
#define IGL_CROSS_FIELD_MISSMATCH_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Calculates the missmatch (integer), at each face edge, of a cross field defined on the mesh faces.
|
|
// The integer missmatch is a multiple of pi/2 that transforms the cross on one side of the edge to
|
|
// the cross on the other side. It represents the deviation from a Lie connection across the edge.
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (quad) indices
|
|
// PD1 #F by 3 eigen Matrix of the first per face cross field vector
|
|
// PD2 #F by 3 eigen Matrix of the second per face cross field vector
|
|
// isCombed boolean, specifying whether the field is combed (i.e. matching has been precomputed.
|
|
// If not, the field is combed first.
|
|
// Output:
|
|
// Handle_MMatch #F by 3 eigen Matrix containing the integer missmatch of the cross field
|
|
// across all face edges
|
|
//
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void cross_field_missmatch(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD1,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD2,
|
|
const bool isCombed,
|
|
Eigen::PlainObjectBase<DerivedF> &missmatch);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "cross_field_missmatch.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_crouzeix_raviart_massmatrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef CROUZEIX_RAVIART_MASSMATRIX_H
|
|
#define CROUZEIX_RAVIART_MASSMATRIX_H
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// CROUZEIX_RAVIART_MASSMATRIX Compute the Crouzeix-Raviart mass matrix where
|
|
// M(e,e) is just the sum of the areas of the triangles on either side of an
|
|
// edge e.
|
|
//
|
|
// See for example "Discrete Quadratic Curvature Energies" [Wardetzky, Bergou,
|
|
// Harmon, Zorin, Grinspun 2007]
|
|
//
|
|
// Templates:
|
|
// MT type of eigen sparse matrix for M (e.g. double for
|
|
// SparseMatrix<double>)
|
|
// DerivedV derived type of eigen matrix for V (e.g. derived from
|
|
// MatrixXd)
|
|
// DerivedF derived type of eigen matrix for F (e.g. derived from
|
|
// MatrixXi)
|
|
// DerivedE derived type of eigen matrix for E (e.g. derived from
|
|
// MatrixXi)
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// Outputs:
|
|
// M #E by #E edge-based diagonal mass matrix
|
|
// E #E by 2 list of edges
|
|
// EMAP #F*3 list of indices mapping allE to E
|
|
//
|
|
//
|
|
template <typename MT, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP>
|
|
void crouzeix_raviart_massmatrix(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::SparseMatrix<MT> & M,
|
|
Eigen::PlainObjectBase<DerivedE> & E,
|
|
Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
|
|
// wrapper if E and EMAP are already computed (better match!)
|
|
template <typename MT, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP>
|
|
void crouzeix_raviart_massmatrix(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedE> & E,
|
|
const Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
|
|
Eigen::SparseMatrix<MT> & M);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "crouzeix_raviart_massmatrix.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cumsum = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CUMSUM_H
|
|
#define IGL_CUMSUM_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Computes a cumulative sum of the columns of X, like matlab's `cumsum`.
|
|
//
|
|
// Templates:
|
|
// DerivedX Type of matrix X
|
|
// DerivedY Type of matrix Y
|
|
// Inputs:
|
|
// X m by n Matrix to be cumulatively summed.
|
|
// dim dimension to take cumlative sum (1 or 2)
|
|
// Output:
|
|
// Y m by n Matrix containing cumulative sum.
|
|
//
|
|
template <typename DerivedX, typename DerivedY>
|
|
IGL_INLINE void cumsum(
|
|
const Eigen::PlainObjectBase<DerivedX > & X,
|
|
const int dim,
|
|
Eigen::PlainObjectBase<DerivedY > & Y);
|
|
//template <typename DerivedX, typename DerivedY>
|
|
//IGL_INLINE void cumsum(
|
|
// const Eigen::PlainObjectBase<DerivedX > & X,
|
|
// Eigen::PlainObjectBase<DerivedY > & Y);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "cumsum.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cut_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_CUT_MESH
|
|
#define IGL_CUT_MESH
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
// Given a mesh and a list of edges that are to be cut, the function generates a
|
|
// new disk-topology mesh that has the cuts at its boundary.
|
|
// Inputs:
|
|
// V #V by 3 list of the vertex positions
|
|
// F #F by 3 list of the faces (must be triangles)
|
|
// VF #V list of lists of incident faces (adjacency list), e.g.
|
|
// as returned by igl::vertex_triangle_adjacency
|
|
// VFi #V list of lists of index of incidence within incident faces listed
|
|
// in VF, e.g. as returned by igl::vertex_triangle_adjacency
|
|
// TT #F by 3 triangle to triangle adjacent matrix (e.g. computed
|
|
// via igl:triangle_triangle_adjacency)
|
|
// TTi #F by 3 adjacent matrix, the element i,j is the id of edge of the
|
|
// triangle TT(i,j) that is adjacent with triangle i (e.g. computed
|
|
// via igl:triangle_triangle_adjacency)
|
|
// V_border #V by 1 list of booleans, indicating if the corresponging vertex is
|
|
// at the mesh boundary, e.g. as returned by igl::is_border_vertex
|
|
// cuts #F by 3 list of boolean flags, indicating the edges that need to be cut
|
|
// Outputs:
|
|
// (has 1 at the face edges that are to be cut, 0 otherwise)
|
|
// Vcut #V by 3 list of the vertex positions of the cut mesh. This matrix will be
|
|
// similar to the original vertices except some rows will be duplicated.
|
|
// Fcut #F by 3 list of the faces of the cut mesh(must be triangles). This matrix
|
|
// will be similar to the original face matrix except some indices will be
|
|
// redirected to point to the newly duplicated vertices.
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
|
|
IGL_INLINE void cut_mesh(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const std::vector<std::vector<VFType> >& VF,
|
|
const std::vector<std::vector<VFType> >& VFi,
|
|
const Eigen::PlainObjectBase<DerivedTT>& TT,
|
|
const Eigen::PlainObjectBase<DerivedTT>& TTi,
|
|
const std::vector<bool> &V_border,
|
|
const Eigen::PlainObjectBase<DerivedC> &cuts,
|
|
Eigen::PlainObjectBase<DerivedV> &Vcut,
|
|
Eigen::PlainObjectBase<DerivedF> &Fcut);
|
|
|
|
|
|
//Wrapper of the above with only vertices and faces as mesh input
|
|
template <typename DerivedV, typename DerivedF, typename DerivedC>
|
|
IGL_INLINE void cut_mesh(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedC> &cuts,
|
|
Eigen::PlainObjectBase<DerivedV> &Vcut,
|
|
Eigen::PlainObjectBase<DerivedF> &Fcut);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "cut_mesh.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_CUT_MESH) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cut_mesh_from_singularities = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_CUT_MESH_FROM_SINGULARITIES_H
|
|
#define IGL_CUT_MESH_FROM_SINGULARITIES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Given a mesh (V,F) and the integer mismatch of a cross field per edge (MMatch),
|
|
// finds the cut_graph connecting the singularities (seams) and the degree of the singularities
|
|
// singularity_index
|
|
//
|
|
// Input:
|
|
// V: #V by 3 list of mesh vertex positions
|
|
// F: #F by 3 list of faces
|
|
// MMatch: #F by 3 list of per corner integer mismatch
|
|
// seams: #F by 3 list of per corner booleans that denotes if an edge is a seam or not
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedO>
|
|
IGL_INLINE void cut_mesh_from_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedM> &MMatch,
|
|
Eigen::PlainObjectBase<DerivedO> &seams);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "cut_mesh_from_singularities.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_dated_copy = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
// Known issues: This function does not work under windows
|
|
|
|
#ifndef IGL_DATED_COPY_H
|
|
#define IGL_DATED_COPY_H
|
|
#include "igl_inline.h"
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
// Copy the given file to a new file with the same basename in `dir`
|
|
// directory with the current date and time as a suffix.
|
|
//
|
|
// Inputs:
|
|
// src_path path to source file
|
|
// dir directory of destination file
|
|
// Example:
|
|
// dated_copy("/path/to/foo","/bar/");
|
|
// // copies /path/to/foo to /bar/foo-2013-12-12T18-10-56
|
|
IGL_INLINE bool dated_copy(const std::string & src_path, const std::string & dir);
|
|
// Wrapper using directory of source file
|
|
IGL_INLINE bool dated_copy(const std::string & src_path);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "dated_copy.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_decimate = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DECIMATE_H
|
|
#define IGL_DECIMATE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
#include <set>
|
|
namespace igl
|
|
{
|
|
// Assumes (V,F) is a closed manifold mesh
|
|
// Collapses edges until desired number of faces is achieved. This uses
|
|
// default edge cost and merged vertex placement functions {edge length, edge
|
|
// midpoint}.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// F #F by 3 list of face indices into V.
|
|
// max_m desired number of output faces
|
|
// Outputs:
|
|
// U #U by dim list of output vertex posistions (can be same ref as V)
|
|
// G #G by 3 list of output face indices into U (can be same ref as G)
|
|
// Returns true if m was reached (otherwise #G > m)
|
|
IGL_INLINE bool decimate(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const size_t max_m,
|
|
Eigen::MatrixXd & U,
|
|
Eigen::MatrixXi & G);
|
|
// Inputs:
|
|
// cost_and_placement function computing cost of collapsing an edge and 3d
|
|
// position where it should be placed:
|
|
// cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
|
|
// stopping_condition function returning whether to stop collapsing edges
|
|
// based on current state. Guaranteed to be called after _successfully_
|
|
// collapsing edge e removing edges (e,e1,e2) and faces (f1,f2):
|
|
// bool should_stop =
|
|
// stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
|
|
IGL_INLINE bool decimate(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const std::function<void(
|
|
const int,
|
|
const Eigen::MatrixXd &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::VectorXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
double &,
|
|
Eigen::RowVectorXd &)> & cost_and_placement,
|
|
const std::function<bool(
|
|
const Eigen::MatrixXd &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::VectorXi &,
|
|
const Eigen::MatrixXi &,
|
|
const Eigen::MatrixXi &,
|
|
const std::set<std::pair<double,int> > &,
|
|
const std::vector<std::set<std::pair<double,int> >::iterator > &,
|
|
const Eigen::MatrixXd &,
|
|
const int,
|
|
const int,
|
|
const int,
|
|
const int,
|
|
const int)> & stopping_condition,
|
|
Eigen::MatrixXd & U,
|
|
Eigen::MatrixXi & G);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "decimate.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_deform_skeleton = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DEFORM_SKELETON_H
|
|
#define IGL_DEFORM_SKELETON_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Deform a skeleton.
|
|
//
|
|
// Inputs:
|
|
// C #C by 3 list of joint positions
|
|
// BE #BE by 2 list of bone edge indices
|
|
// vA #BE list of bone transformations
|
|
// Outputs
|
|
// CT #BE*2 by 3 list of deformed joint positions
|
|
// BET #BE by 2 list of bone edge indices (maintains order)
|
|
//
|
|
IGL_INLINE void deform_skeleton(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const std::vector<
|
|
Eigen::Affine3d,Eigen::aligned_allocator<Eigen::Affine3d> > & vA,
|
|
Eigen::MatrixXd & CT,
|
|
Eigen::MatrixXi & BET);
|
|
// Inputs:
|
|
// T #BE*4 by 3 list of stacked transformation matrix
|
|
IGL_INLINE void deform_skeleton(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::MatrixXd & T,
|
|
Eigen::MatrixXd & CT,
|
|
Eigen::MatrixXi & BET);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "deform_skeleton.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_deprecated = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DEPRECATED_H
|
|
#define IGL_DEPRECATED_H
|
|
// Macro for marking a function as deprecated.
|
|
//
|
|
// http://stackoverflow.com/a/295229/148668
|
|
#ifdef __GNUC__
|
|
#define IGL_DEPRECATED(func) func __attribute__ ((deprecated))
|
|
#elif defined(_MSC_VER)
|
|
#define IGL_DEPRECATED(func) __declspec(deprecated) func
|
|
#else
|
|
#pragma message("WARNING: You need to implement IGL_DEPRECATED for this compiler")
|
|
#define IGL_DEPRECATED(func) func
|
|
#endif
|
|
// Usage:
|
|
//
|
|
// template <typename T> IGL_INLINE void my_func(Arg1 a);
|
|
//
|
|
// becomes
|
|
//
|
|
// template <typename T> IGL_INLINE IGL_DEPRECATED(void my_func(Arg1 a));
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_diag = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DIAG_H
|
|
#define IGL_DIAG_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// http://forum.kde.org/viewtopic.php?f=74&t=117476&p=292388#p292388
|
|
//
|
|
// This is superceded by
|
|
// VectorXd V = X.diagonal() and
|
|
// SparseVector<double> V = X.diagonal().sparseView()
|
|
// SparseMatrix<double> X = V.asDiagonal().sparseView()
|
|
//
|
|
//
|
|
// Either extracts the main diagonal of a matrix as a vector OR converts a
|
|
// vector into a matrix with vector along the main diagonal. Like matlab's
|
|
// diag function
|
|
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// X an m by n sparse matrix
|
|
// Outputs:
|
|
// V a min(m,n) sparse vector
|
|
template <typename T>
|
|
IGL_INLINE void diag(
|
|
const Eigen::SparseMatrix<T>& X,
|
|
Eigen::SparseVector<T>& V);
|
|
template <typename T,typename DerivedV>
|
|
IGL_INLINE void diag(
|
|
const Eigen::SparseMatrix<T>& X,
|
|
Eigen::MatrixBase<DerivedV>& V);
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// V a m sparse vector
|
|
// Outputs:
|
|
// X a m by m sparse matrix
|
|
template <typename T>
|
|
IGL_INLINE void diag(
|
|
const Eigen::SparseVector<T>& V,
|
|
Eigen::SparseMatrix<T>& X);
|
|
template <typename T, typename DerivedV>
|
|
IGL_INLINE void diag(
|
|
const Eigen::MatrixBase<DerivedV>& V,
|
|
Eigen::SparseMatrix<T>& X);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "diag.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_dihedral_angles = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DIHEDRAL_ANGLES_H
|
|
#define IGL_DIHEDRAL_ANGLES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// DIHEDRAL_ANGLES Compute dihedral angles for all tets of a given tet mesh
|
|
// (V,T)
|
|
//
|
|
// theta = dihedral_angles(V,T)
|
|
// theta = dihedral_angles(V,T,'ParameterName',parameter_value,...)
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// T #V by 4 list of tet indices
|
|
// Outputs:
|
|
// theta #T by 6 list of dihedral angles (in radians)
|
|
// cos_theta #T by 6 list of cosine of dihedral angles (in radians)
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedT,
|
|
typename Derivedtheta,
|
|
typename Derivedcos_theta>
|
|
IGL_INLINE void dihedral_angles(
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedT>& T,
|
|
Eigen::PlainObjectBase<Derivedtheta>& theta,
|
|
Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
|
|
template <
|
|
typename DerivedL,
|
|
typename DerivedA,
|
|
typename Derivedtheta,
|
|
typename Derivedcos_theta>
|
|
IGL_INLINE void dihedral_angles_intrinsic(
|
|
Eigen::PlainObjectBase<DerivedL>& L,
|
|
Eigen::PlainObjectBase<DerivedA>& A,
|
|
Eigen::PlainObjectBase<Derivedtheta>& theta,
|
|
Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "dihedral_angles.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_dijkstra = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_DIJKSTRA
|
|
#define IGL_DIJKSTRA
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
#include <set>
|
|
|
|
namespace igl {
|
|
|
|
// Dijstra's algorithm for shortest paths, with multiple targets.
|
|
// Adapted from http://rosettacode.org/wiki/Dijkstra%27s_algorithm .
|
|
//
|
|
// Inputs:
|
|
// source index of source vertex
|
|
// targets target vector set
|
|
// VV #V list of lists of incident vertices (adjacency list), e.g.
|
|
// as returned by igl::adjacency_list
|
|
//
|
|
// Output:
|
|
// min_distance #V by 1 list of the minimum distances from source to all vertices
|
|
// previous #V by 1 list of the previous visited vertices (for each vertex) - used for backtracking
|
|
//
|
|
template <typename IndexType, typename DerivedD, typename DerivedP>
|
|
IGL_INLINE int dijkstra_compute_paths(const IndexType &source,
|
|
const std::set<IndexType> &targets,
|
|
const std::vector<std::vector<IndexType> >& VV,
|
|
Eigen::PlainObjectBase<DerivedD> &min_distance,
|
|
Eigen::PlainObjectBase<DerivedP> &previous);
|
|
|
|
// Backtracking after Dijstra's algorithm, to find shortest path.
|
|
//
|
|
// Inputs:
|
|
// vertex vertex to which we want the shortest path (from same source as above)
|
|
// previous #V by 1 list of the previous visited vertices (for each vertex) - result of Dijkstra's algorithm
|
|
//
|
|
// Output:
|
|
// path #P by 1 list of vertex indices in the shortest path from source to vertex
|
|
//
|
|
template <typename IndexType, typename DerivedP>
|
|
IGL_INLINE void dijkstra_get_shortest_path_to(const IndexType &vertex,
|
|
const Eigen::PlainObjectBase<DerivedP> &previous,
|
|
std::vector<IndexType> &path);
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "dijkstra.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_DIJKSTRA) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_directed_edge_orientations = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DIRECTED_EDGE_ORIENTATIONS_H
|
|
#define IGL_DIRECTED_EDGE_ORIENTATIONS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/StdVector>
|
|
|
|
namespace igl
|
|
{
|
|
// Determine rotations that take each edge from the x-axis to its given rest
|
|
// orientation.
|
|
//
|
|
// Inputs:
|
|
// C #C by 3 list of edge vertex positions
|
|
// E #E by 2 list of directed edges
|
|
// Outputs:
|
|
// Q #E list of quaternions
|
|
//
|
|
template <typename DerivedC, typename DerivedE>
|
|
IGL_INLINE void directed_edge_orientations(
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedE> & E,
|
|
std::vector<
|
|
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & Q);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "directed_edge_orientations.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_directed_edge_parents = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DIRECTED_EDGE_PARENTS_H
|
|
#define IGL_DIRECTED_EDGE_PARENTS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Recover "parents" (preceeding edges) in a tree given just directed edges.
|
|
//
|
|
// Inputs:
|
|
// E #E by 2 list of directed edges
|
|
// Outputs:
|
|
// P #E list of parent indices into E (-1) means root
|
|
//
|
|
template <typename DerivedE, typename DerivedP>
|
|
IGL_INLINE void directed_edge_parents(
|
|
const Eigen::PlainObjectBase<DerivedE> & E,
|
|
Eigen::PlainObjectBase<DerivedP> & P);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "directed_edge_parents.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_dirname = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DIRNAME_H
|
|
#define IGL_DIRNAME_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// Function like PHP's dirname: /etc/passwd --> /etc,
|
|
// Input:
|
|
// path string containing input path
|
|
// Returns string containing dirname (see php's dirname)
|
|
//
|
|
// See also: basename, pathinfo
|
|
IGL_INLINE std::string dirname(const std::string & path);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "dirname.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_dot = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DOT_H
|
|
#define IGL_DOT_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Computes out = dot(a,b)
|
|
// Inputs:
|
|
// a left 3d vector
|
|
// b right 3d vector
|
|
// Returns scalar dot product
|
|
IGL_INLINE double dot(
|
|
const double *a,
|
|
const double *b);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "dot.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_dot_row = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DOT_ROW_H
|
|
#define IGL_DOT_ROW_H
|
|
|
|
#include "igl/igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Compute the dot product between each row of A and B
|
|
// Templates:
|
|
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
|
|
// Inputs:
|
|
// A eigen matrix r by c
|
|
// B eigen matrix r by c
|
|
// Returns:
|
|
// d a column vector with r entries that contains the dot product of each corresponding row of A and B
|
|
//
|
|
template <typename DerivedV>
|
|
IGL_INLINE Eigen::PlainObjectBase<DerivedV> dot_row(
|
|
const Eigen::PlainObjectBase<DerivedV>& A,
|
|
const Eigen::PlainObjectBase<DerivedV>& B);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "dot_row.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_doublearea = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DOUBLEAREA_H
|
|
#define IGL_DOUBLEAREA_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// DOUBLEAREA computes twice the area for each input triangle[quad]
|
|
//
|
|
// Templates:
|
|
// DerivedV derived type of eigen matrix for V (e.g. derived from
|
|
// MatrixXd)
|
|
// DerivedF derived type of eigen matrix for F (e.g. derived from
|
|
// MatrixXi)
|
|
// DeriveddblA derived type of eigen matrix for dblA (e.g. derived from
|
|
// MatrixXd)
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by simplex_size list of mesh faces (must be triangles or quads)
|
|
// Outputs:
|
|
// dblA #F list of triangle[quad] double areas (SIGNED only for 2D input)
|
|
//
|
|
// Known bug: For dim==3 complexity is O(#V + #F)!! Not just O(#F). This is a big deal
|
|
// if you have 1million unreferenced vertices and 1 face
|
|
template <typename DerivedV, typename DerivedF, typename DeriveddblA>
|
|
IGL_INLINE void doublearea(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DeriveddblA> & dblA);
|
|
// Stream of triangles
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedB,
|
|
typename DerivedC,
|
|
typename DerivedD>
|
|
IGL_INLINE void doublearea(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::PlainObjectBase<DerivedD> & D);
|
|
// Single triangle in 2D!
|
|
//
|
|
// This should handle streams of corners not just single corners
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedB,
|
|
typename DerivedC>
|
|
IGL_INLINE typename DerivedA::Scalar doublearea_single(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<DerivedC> & C);
|
|
// Same as above but use instrinsic edge lengths rather than (V,F) mesh
|
|
// Templates:
|
|
// DerivedV derived type of eigen matrix for V (e.g. derived from
|
|
// MatrixXd)
|
|
// DerivedF derived type of eigen matrix for F (e.g. derived from
|
|
// MatrixXi)
|
|
// DeriveddblA derived type of eigen matrix for dblA (e.g. derived from
|
|
// MatrixXd)
|
|
// Inputs:
|
|
// l #F by dim list of edge lengths using
|
|
// for triangles, columns correspond to edges 23,31,12
|
|
// Outputs:
|
|
// dblA #F list of triangle double areas
|
|
template <typename Derivedl, typename DeriveddblA>
|
|
IGL_INLINE void doublearea(
|
|
const Eigen::PlainObjectBase<Derivedl> & l,
|
|
Eigen::PlainObjectBase<DeriveddblA> & dblA);
|
|
|
|
// DOUBLEAREA_QUAD computes twice the area for each input quadrilateral
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by simplex_size list of mesh faces (must be quadrilaterals)
|
|
// Outputs:
|
|
// dblA #F list of quadrilateral double areas
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DeriveddblA>
|
|
IGL_INLINE void doublearea_quad(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DeriveddblA> & dblA);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "doublearea.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_dqs = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_DQS_H
|
|
#define IGL_DQS_H
|
|
#include "igl_inline.h"
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Dual quaternion skinning
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of rest positions
|
|
// W #W by #C list of weights
|
|
// vQ #C list of rotation quaternions
|
|
// vT #C list of translation vectors
|
|
// Outputs:
|
|
// U #V by 3 list of new positions
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedW,
|
|
typename Q,
|
|
typename QAlloc,
|
|
typename T,
|
|
typename DerivedU>
|
|
IGL_INLINE void dqs(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedW> & W,
|
|
const std::vector<Q,QAlloc> & vQ,
|
|
const std::vector<T> & vT,
|
|
Eigen::PlainObjectBase<DerivedU> & U);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "dqs.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_edge_collapse_is_valid = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EDGE_COLLAPSE_IS_VALID_H
|
|
#define IGL_EDGE_COLLAPSE_IS_VALID_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Assumes (V,F) is a closed manifold mesh (except for previouslly collapsed
|
|
// faces which should be set to:
|
|
// [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL].
|
|
// Tests whether collapsing exactly two faces and exactly 3 edges from E (e
|
|
// and one side of each face gets collapsed to the other) will result in a
|
|
// mesh with the same topology.
|
|
//
|
|
// Inputs:
|
|
// e index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so
|
|
// that s<d, then d is collapsed to s.
|
|
// F #F by 3 list of face indices into V.
|
|
// E #E by 2 list of edge indices into V.
|
|
// EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
|
// unique edge in E
|
|
// EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
|
|
// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
|
|
// e=(j->i)
|
|
// EI #E by 2 list of edge flap corners (see above).
|
|
// Returns true if edge collapse is valid
|
|
IGL_INLINE bool edge_collapse_is_valid(
|
|
const int e,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXi & E,
|
|
const Eigen::VectorXi & EMAP,
|
|
const Eigen::MatrixXi & EF,
|
|
const Eigen::MatrixXi & EI);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "edge_collapse_is_valid.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_edge_flaps = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EDGE_FLAPS_H
|
|
#define IGL_EDGE_FLAPS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Determine "edge flaps": two faces on either side of a unique edge (assumes
|
|
// edge-manifold mesh)
|
|
//
|
|
// Inputs:
|
|
// F #F by 3 list of face indices
|
|
// E #E by 2 list of edge indices into V.
|
|
// EMAP #F*3 list of indices into E, mapping each directed edge to unique
|
|
// unique edge in E
|
|
// Outputs:
|
|
// EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
|
|
// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
|
|
// e=(j->i)
|
|
// EI #E by 2 list of edge flap corners (see above).
|
|
IGL_INLINE void edge_flaps(
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXi & E,
|
|
const Eigen::VectorXi & EMAP,
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EI);
|
|
// Only faces as input
|
|
IGL_INLINE void edge_flaps(
|
|
const Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & E,
|
|
Eigen::VectorXi & EMAP,
|
|
Eigen::MatrixXi & EF,
|
|
Eigen::MatrixXi & EI);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "edge_flaps.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_edge_lengths = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EDGE_LENGTHS_H
|
|
#define IGL_EDGE_LENGTHS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Constructs a list of lengths of edges opposite each index in a face
|
|
// (triangle/tet) list
|
|
//
|
|
// Templates:
|
|
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
|
|
// DerivedF derived from face indices matrix type: i.e. MatrixXi
|
|
// DerivedL derived from edge lengths matrix type: i.e. MatrixXd
|
|
// Inputs:
|
|
// V eigen matrix #V by 3
|
|
// F #F by 2 list of mesh edges
|
|
// or
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// or
|
|
// T #T by 4 list of mesh elements (must be tets)
|
|
// Outputs:
|
|
// L #F by {1|3|6} list of edge lengths
|
|
// for edges, column of lengths
|
|
// for triangles, columns correspond to edges [1,2],[2,0],[0,1]
|
|
// for tets, columns correspond to edges
|
|
// [1,2],[2,0],[0,1],[3,0],[3,1],[3,2]
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedL>
|
|
IGL_INLINE void edge_lengths(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedL>& L);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "edge_lengths.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_edge_topology = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EDGE_TOPOLOGY_H
|
|
#define IGL_EDGE_TOPOLOGY_H
|
|
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Initialize Edges and their topological relations
|
|
|
|
// Output:
|
|
// EV : #Ex2, Stores the edge description as pair of indices to vertices
|
|
// FE : #Fx3, Stores the Triangle-Edge relation
|
|
// EF : #Ex2: Stores the Edge-Triangle relation
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void edge_topology(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::MatrixXi& EV,
|
|
Eigen::MatrixXi& FE,
|
|
Eigen::MatrixXi& EF);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "edge_topology.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_edges = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EDGES_H
|
|
#define IGL_EDGES_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Constructs a list of unique edges represented in a given mesh (V,F)
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// or
|
|
// T #T x 4 matrix of indices of tet corners
|
|
// Outputs:
|
|
// E #E by 2 list of edges in no particular order
|
|
//
|
|
// See also: adjacency_matrix
|
|
IGL_INLINE void edges( const Eigen::MatrixXi& F, Eigen::MatrixXi& E);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "edges.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_eigs = R"igl_Qu8mg5v7(#ifndef IGL_EIGS_H
|
|
#define IGL_EIGS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Act like MATLAB's eigs function. Compute the first/last k eigen pairs of
|
|
// the generalized eigen value problem:
|
|
//
|
|
// A u = s B u
|
|
//
|
|
// Solutions are approximate and sorted.
|
|
//
|
|
// Ideally one should use ARPACK and the Eigen unsupported ARPACK module.
|
|
// This implementation does simple, naive power iterations.
|
|
//
|
|
// Inputs:
|
|
// A #A by #A symmetric matrix
|
|
// B #A by #A symmetric positive-definite matrix
|
|
// k number of eigen pairs to compute
|
|
// Outputs:
|
|
// sU #A by k list of sorted eigen vectors (descending)
|
|
// sS k list of sorted eigen values (descending)
|
|
//
|
|
// Known issues:
|
|
// - only one pair per eigen value is found (no multiples)
|
|
// - only the 'sm' small magnitude eigen values are well supported
|
|
//
|
|
enum EigsType
|
|
{
|
|
EIGS_TYPE_SM = 0,
|
|
EIGS_TYPE_LM = 1,
|
|
NUM_EIGS_TYPES = 2
|
|
};
|
|
template <
|
|
typename Atype,
|
|
typename Btype,
|
|
typename DerivedU,
|
|
typename DerivedS>
|
|
IGL_INLINE bool eigs(
|
|
const Eigen::SparseMatrix<Atype> & A,
|
|
const Eigen::SparseMatrix<Btype> & B,
|
|
const size_t k,
|
|
const EigsType type,
|
|
Eigen::PlainObjectBase<DerivedU> & sU,
|
|
Eigen::PlainObjectBase<DerivedS> & sS);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "eigs.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_EPS = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EPS_H
|
|
#define IGL_EPS_H
|
|
#include "igl_inline.h"
|
|
// Define a standard value for double epsilon
|
|
namespace igl
|
|
{
|
|
const double DOUBLE_EPS = 1.0e-14;
|
|
const double DOUBLE_EPS_SQ = 1.0e-28;
|
|
const float FLOAT_EPS = 1.0e-7;
|
|
const float FLOAT_EPS_SQ = 1.0e-14;
|
|
// Function returning EPS for corresponding type
|
|
template <typename S_type> IGL_INLINE S_type EPS();
|
|
template <typename S_type> IGL_INLINE S_type EPS_SQ();
|
|
// Template specializations for float and double
|
|
template <> IGL_INLINE float EPS<float>();
|
|
template <> IGL_INLINE double EPS<double>();
|
|
template <> IGL_INLINE float EPS_SQ<float>();
|
|
template <> IGL_INLINE double EPS_SQ<double>();
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "EPS.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_example_fun = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EXAMPLE_FUN_H
|
|
#define IGL_EXAMPLE_FUN_H
|
|
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// This is an example of a function, it takes a templated parameter and
|
|
// shovels it into cout
|
|
//
|
|
// Templates:
|
|
// T type that supports
|
|
// Input:
|
|
// input some input of a Printable type
|
|
// Returns true for the sake of returning something
|
|
template <typename Printable>
|
|
IGL_INLINE bool example_fun(const Printable & input);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "example_fun.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_exterior_edges = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EXTERIOR_EDGES_H
|
|
#define IGL_EXTERIOR_EDGES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// EXTERIOR_EDGES Determines boundary "edges" and also edges with an
|
|
// odd number of occurances where seeing edge (i,j) counts as +1 and seeing
|
|
// the opposite edge (j,i) counts as -1
|
|
//
|
|
// Inputs:
|
|
// F #F by simplex_size list of "faces"
|
|
// Outputs:
|
|
// E #E by simplex_size-1 list of exterior edges
|
|
//
|
|
IGL_INLINE void exterior_edges(
|
|
const Eigen::MatrixXi & F,
|
|
Eigen::MatrixXi & E);
|
|
// Inline version
|
|
IGL_INLINE Eigen::MatrixXi exterior_edges( const Eigen::MatrixXi & F);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "exterior_edges.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_face_areas = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FACE_AREAS_H
|
|
#define IGL_FACE_AREAS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Constructs a list of face areas of faces opposite each index in a tet list
|
|
//
|
|
// Templates:
|
|
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
|
|
// DerivedT derived from face indices matrix type: i.e. MatrixXi
|
|
// DerivedL derived from edge lengths matrix type: i.e. MatrixXd
|
|
// Inputs:
|
|
// V eigen matrix #V by 3
|
|
// T #T by 3 list of mesh faces (must be triangles)
|
|
// Outputs:
|
|
// E #E by 2 list of edges in no particular order
|
|
//
|
|
// See also: adjacency_matrix
|
|
template <typename DerivedV, typename DerivedT, typename DerivedA>
|
|
IGL_INLINE void face_areas(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedT>& T,
|
|
Eigen::PlainObjectBase<DerivedA>& A);
|
|
template <typename DerivedL, typename DerivedA>
|
|
IGL_INLINE void face_areas(
|
|
const Eigen::PlainObjectBase<DerivedL>& L,
|
|
Eigen::PlainObjectBase<DerivedA>& A);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "face_areas.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_face_occurrences = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FACE_OCCURRENCES
|
|
#define IGL_FACE_OCCURRENCES
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Count the occruances of each face (row) in a list of face indices
|
|
// (irrespecitive of order)
|
|
// Inputs:
|
|
// F #F by simplex-size
|
|
// Outputs
|
|
// C #F list of counts
|
|
// Known bug: triangles/tets only (where ignoring order still gives simplex)
|
|
template <typename IntegerF, typename IntegerC>
|
|
IGL_INLINE void face_occurrences(
|
|
const std::vector<std::vector<IntegerF> > & F,
|
|
std::vector<IntegerC> & C);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "face_occurrences.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_faces_first = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FACES_FIRST_H
|
|
#define IGL_FACES_FIRST_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// FACES_FIRST Reorder vertices so that vertices in face list come before
|
|
// vertices that don't appear in the face list. This is especially useful if
|
|
// the face list contains only surface faces and you want surface vertices
|
|
// listed before internal vertices
|
|
//
|
|
// [RV,RT,RF,IM] = faces_first(V,T,F);
|
|
//
|
|
// Templates:
|
|
// MatV matrix for vertex positions, e.g. MatrixXd
|
|
// MatF matrix for face indices, e.g. MatrixXi
|
|
// VecI vector for index map, e.g. VectorXi
|
|
// Input:
|
|
// V # vertices by 3 vertex positions
|
|
// F # faces by 3 list of face indices
|
|
// Output:
|
|
// RV # vertices by 3 vertex positions, order such that if the jth vertex is
|
|
// some face in F, and the kth vertex is not then j comes before k
|
|
// RF # faces by 3 list of face indices, reindexed to use RV
|
|
// IM #V by 1 list of indices such that: RF = IM(F) and RT = IM(T)
|
|
// and RV(IM,:) = V
|
|
//
|
|
//
|
|
// Example:
|
|
// // Tet mesh in (V,T,F)
|
|
// faces_first(V,F,IM);
|
|
// T = T.unaryExpr(bind1st(mem_fun( static_cast<VectorXi::Scalar&
|
|
// (VectorXi::*)(VectorXi::Index)>(&VectorXi::operator())),
|
|
// &IM)).eval();
|
|
template <typename MatV, typename MatF, typename VecI>
|
|
IGL_INLINE void faces_first(
|
|
const MatV & V,
|
|
const MatF & F,
|
|
MatV & RV,
|
|
MatF & RF,
|
|
VecI & IM);
|
|
// Virtual "in place" wrapper
|
|
template <typename MatV, typename MatF, typename VecI>
|
|
IGL_INLINE void faces_first(
|
|
MatV & V,
|
|
MatF & F,
|
|
VecI & IM);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "faces_first.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_facet_components = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef FACET_COMPONENTS_H
|
|
#define FACET_COMPONENTS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Compute connected components of facets based on edge-edge adjacency.
|
|
//
|
|
// Inputs:
|
|
// F #F by 3 list of triangle indices
|
|
// Ouputs:
|
|
// C #F list of connected component ids
|
|
template <typename DerivedF, typename DerivedC>
|
|
IGL_INLINE void facet_components(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
// Inputs:
|
|
// TT #TT by 3 list of list of adjacency triangles (see
|
|
// triangle_triangle_adjacency.h)
|
|
// Ouputs:
|
|
// C #F list of connected component ids
|
|
template <
|
|
typename TTIndex,
|
|
typename DerivedC,
|
|
typename Derivedcounts>
|
|
IGL_INLINE void facet_components(
|
|
const std::vector<std::vector<std::vector<TTIndex > > > & TT,
|
|
Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::PlainObjectBase<Derivedcounts> & counts);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "facet_components.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_false_barycentric_subdivision = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ADD_BARYCENTER_H
|
|
#define IGL_ADD_BARYCENTER_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Refine the mesh by adding the barycenter of each face
|
|
// Inputs:
|
|
// V #V by 3 coordinates of the vertices
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// Outputs:
|
|
// VD #V + #F by 3 coordinate of the vertices of the dual mesh
|
|
// The added vertices are added at the end of VD (should not be
|
|
// same references as (V,F)
|
|
// FD #F*3 by 3 faces of the dual mesh
|
|
//
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE void false_barycentric_subdivision(
|
|
const Eigen::PlainObjectBase<Scalar> & V,
|
|
const Eigen::PlainObjectBase<Index> & F,
|
|
Eigen::PlainObjectBase<Scalar> & VD,
|
|
Eigen::PlainObjectBase<Index> & FD);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "false_barycentric_subdivision.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_field_local_global_conversions = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS
|
|
#define IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
// Converts a face-based polyvector field consisting of n vectors per face
|
|
// from its 3D coordinates to its local 2D representation (with respect to the
|
|
// local bases of each triangle)
|
|
|
|
// Inputs:
|
|
// B1 #F by 3 list of the first basis vector of each triangle
|
|
// B2 #F by 3 list of the second basis vector of each triangle
|
|
// global #F by 3n list of the 3D coordinates of the per-face vectors
|
|
// (stacked horizontally for each triangle)
|
|
// Output:
|
|
// local #F by 2n list of the 2D representation of the per-face vectors
|
|
// (stacked horizontally for each triangle)
|
|
//
|
|
template <typename DerivedG, typename DerivedL, typename DerivedB>
|
|
IGL_INLINE void global2local(
|
|
const Eigen::PlainObjectBase<DerivedB>& B1,
|
|
const Eigen::PlainObjectBase<DerivedB>& B2,
|
|
const Eigen::PlainObjectBase<DerivedG>& global,
|
|
Eigen::PlainObjectBase<DerivedL>& local);
|
|
|
|
// Converts a face-based polyvector field consisting of n vectors per face
|
|
// from its local 2D representation (with respect to the local bases of each
|
|
// triangle) to its 3D coordinates
|
|
|
|
// Inputs:
|
|
// B1 #F by 3 list of the first basis vector of each triangle
|
|
// B2 #F by 3 list of the second basis vector of each triangle
|
|
// local #F by 2n list of the 2D representation of the per-face vectors
|
|
// (stacked horizontally for each triangle)
|
|
// Output:
|
|
// global #F by 3n list of the 3D coordinates of the per-face vectors
|
|
// (stacked horizontally for each triangle)
|
|
//
|
|
template <typename DerivedG, typename DerivedL, typename DerivedB>
|
|
IGL_INLINE void local2global(
|
|
const Eigen::PlainObjectBase<DerivedB>& B1,
|
|
const Eigen::PlainObjectBase<DerivedB>& B2,
|
|
const Eigen::PlainObjectBase<DerivedL>& local,
|
|
Eigen::PlainObjectBase<DerivedG>& global);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "field_local_global_conversions.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_file_contents_as_string = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FILE_CONTENTS_AS_STRING_H
|
|
#define IGL_FILE_CONTENTS_AS_STRING_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
// Read a files contents as plain text into a given string
|
|
// Inputs:
|
|
// file_name path to file to be read
|
|
// Outputs:
|
|
// content output string containing contents of the given file
|
|
// Returns true on succes, false on error
|
|
IGL_INLINE bool file_contents_as_string(
|
|
const std::string file_name,
|
|
std::string & content);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "file_contents_as_string.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_file_dialog_open = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FILE_DIALOG_OPEN_H
|
|
#define IGL_FILE_DIALOG_OPEN_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// Returns a string with a path to an existing file
|
|
// The string is returned empty if no file is selected
|
|
// (on Linux machines, it assumes that Zenity is installed)
|
|
//
|
|
// Usage:
|
|
// std::string str = get_open_file_path();
|
|
IGL_INLINE std::string file_dialog_open();
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "file_dialog_open.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_file_dialog_save = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FILE_DIALOG_SAVE_H
|
|
#define IGL_FILE_DIALOG_SAVE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// Returns a string with a path to a new/existing file
|
|
// The string is returned empty if no file is selected
|
|
// (on Linux machines, it assumes that Zenity is installed)
|
|
//
|
|
// Usage:
|
|
// char buffer[FILE_DIALOG_MAX_BUFFER];
|
|
// get_save_file_path(buffer);
|
|
IGL_INLINE std::string file_dialog_save();
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "file_dialog_save.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_file_exists = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FILE_EXISTS_H
|
|
#define IGL_FILE_EXISTS_H
|
|
#include "igl_inline.h"
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
// Check if a file or directory exists like PHP's file_exists function:
|
|
// http://php.net/manual/en/function.file-exists.php
|
|
// Input:
|
|
// filename path to file
|
|
// Returns true if file exists and is readable and false if file doesn't
|
|
// exist or *is not readable*
|
|
IGL_INLINE bool file_exists(const std::string filename);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "file_exists.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_find = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FIND_H
|
|
#define IGL_FIND_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Find the non-zero entries and there respective indices in a sparse matrix.
|
|
// Like matlab's [I,J,V] = find(X)
|
|
//
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Input:
|
|
// X m by n matrix whose entries are to be found
|
|
// Outputs:
|
|
// I nnz vector of row indices of non zeros entries in X
|
|
// J nnz vector of column indices of non zeros entries in X
|
|
// V nnz vector of type T non-zeros entries in X
|
|
//
|
|
template <
|
|
typename T,
|
|
typename DerivedI,
|
|
typename DerivedJ,
|
|
typename DerivedV>
|
|
IGL_INLINE void find(
|
|
const Eigen::SparseMatrix<T>& X,
|
|
Eigen::MatrixBase<DerivedI> & I,
|
|
Eigen::MatrixBase<DerivedJ> & J,
|
|
Eigen::MatrixBase<DerivedV> & V);
|
|
template <
|
|
typename DerivedX,
|
|
typename DerivedI,
|
|
typename DerivedJ,
|
|
typename DerivedV>
|
|
IGL_INLINE void find(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedJ> & J,
|
|
Eigen::PlainObjectBase<DerivedV> & V);
|
|
template <
|
|
typename DerivedX,
|
|
typename DerivedI>
|
|
IGL_INLINE void find(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
Eigen::PlainObjectBase<DerivedI> & I);
|
|
// Find the non-zero entries and there respective indices in a sparse vector.
|
|
// Similar to matlab's [I,J,V] = find(X), but instead of [I,J] being
|
|
// subscripts into X, since X is a vector we just return I, a list of indices
|
|
// into X
|
|
//
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Input:
|
|
// X vector whose entries are to be found
|
|
// Outputs:
|
|
// I nnz vector of indices of non zeros entries in X
|
|
// V nnz vector of type T non-zeros entries in X
|
|
template <typename T>
|
|
IGL_INLINE void find(
|
|
const Eigen::SparseVector<T>& X,
|
|
Eigen::Matrix<int,Eigen::Dynamic,1> & I,
|
|
Eigen::Matrix<T,Eigen::Dynamic,1> & V);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "find.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_find_cross_field_singularities = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_FIND_CROSS_FIELD_SINGULARITIES_H
|
|
#define IGL_FIND_CROSS_FIELD_SINGULARITIES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Computes singularities of a cross field, assumed combed
|
|
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (quad) indices
|
|
// Handle_MMatch #F by 3 eigen Matrix containing the integer missmatch of the cross field
|
|
// across all face edges
|
|
// Output:
|
|
// isSingularity #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex
|
|
// singularityIndex #V by 1 integer eigen Vector containing the singularity indices
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedO>
|
|
IGL_INLINE void find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch,
|
|
Eigen::PlainObjectBase<DerivedO> &isSingularity,
|
|
Eigen::PlainObjectBase<DerivedO> &singularityIndex);
|
|
|
|
// Wrapper that calculates the missmatch if it is not provided.
|
|
// Note that the field in PD1 and PD2 MUST BE combed (see igl::comb_cross_field).
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (quad) indices
|
|
// PD1 #F by 3 eigen Matrix of the first per face cross field vector
|
|
// PD2 #F by 3 eigen Matrix of the second per face cross field vector
|
|
// Output:
|
|
// isSingularity #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex
|
|
// singularityIndex #V by 1 integer eigen Vector containing the singularity indices
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedO>
|
|
IGL_INLINE void find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD1,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD2,
|
|
Eigen::PlainObjectBase<DerivedO> &isSingularity,
|
|
Eigen::PlainObjectBase<DerivedO> &singularityIndex,
|
|
bool isCombed = false);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "find_cross_field_singularities.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_fit_plane = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FIT_PLANE_H
|
|
#define IGL_FIT_PLANE_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// This function fits a plane to a point cloud.
|
|
//
|
|
// Input:
|
|
// V #Vx3 matrix. The 3D point cloud, one row for each vertex.
|
|
// Output:
|
|
// N 1x3 Vector. The normal of the fitted plane.
|
|
// C 1x3 Vector. A point that lies in the fitted plane.
|
|
// From http://missingbytes.blogspot.com/2012/06/fitting-plane-to-point-cloud.html
|
|
|
|
IGL_INLINE void fit_plane(
|
|
const Eigen::MatrixXd & V,
|
|
Eigen::RowVector3d & N,
|
|
Eigen::RowVector3d & C);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "fit_plane.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_fit_rigid = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FIT_RIGID_H
|
|
#define IGL_FIT_RIGID_H
|
|
|
|
#if defined(_WIN32)
|
|
#pragma message("Deprecated. Use igl/procrustes.h instead")
|
|
#else
|
|
#warning "Deprecated. Use igl/procrustes.h instead"
|
|
#endif
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
|
|
namespace igl
|
|
{
|
|
// Deprecated: please use procrustes(...) instead.
|
|
// Fit a rigid
|
|
IGL_INLINE void fit_rigid(
|
|
const Eigen::MatrixXd & A,
|
|
const Eigen::MatrixXd & B,
|
|
Eigen::Rotation2Dd & R,
|
|
Eigen::RowVector2d & t);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "fit_rigid.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_fit_rotations = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FIT_ROTATIONS_H
|
|
#define IGL_FIT_ROTATIONS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Known issues: This seems to be implemented in Eigen/Geometry:
|
|
// Eigen::umeyama
|
|
//
|
|
// FIT_ROTATIONS Given an input mesh and new positions find rotations for
|
|
// every covariance matrix in a stack of covariance matrices
|
|
//
|
|
// Inputs:
|
|
// S nr*dim by dim stack of covariance matrices
|
|
// single_precision whether to use single precision (faster)
|
|
// Outputs:
|
|
// R dim by dim * nr list of rotations
|
|
//
|
|
template <typename DerivedS, typename DerivedD>
|
|
IGL_INLINE void fit_rotations(
|
|
const Eigen::PlainObjectBase<DerivedS> & S,
|
|
const bool single_precision,
|
|
Eigen::PlainObjectBase<DerivedD> & R);
|
|
|
|
// FIT_ROTATIONS Given an input mesh and new positions find 2D rotations for
|
|
// every vertex that best maps its one ring to the new one ring
|
|
//
|
|
// Inputs:
|
|
// S nr*dim by dim stack of covariance matrices, third column and every
|
|
// third row will be ignored
|
|
// Outputs:
|
|
// R dim by dim * nr list of rotations, third row and third column of each
|
|
// rotation will just be identity
|
|
//
|
|
template <typename DerivedS, typename DerivedD>
|
|
IGL_INLINE void fit_rotations_planar(
|
|
const Eigen::PlainObjectBase<DerivedS> & S,
|
|
Eigen::PlainObjectBase<DerivedD> & R);
|
|
#ifdef __SSE__
|
|
IGL_INLINE void fit_rotations_SSE( const Eigen::MatrixXf & S, Eigen::MatrixXf & R);
|
|
IGL_INLINE void fit_rotations_SSE( const Eigen::MatrixXd & S, Eigen::MatrixXd & R);
|
|
#endif
|
|
#ifdef __AVX__
|
|
IGL_INLINE void fit_rotations_AVX( const Eigen::MatrixXf & S, Eigen::MatrixXf & R);
|
|
#endif
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "fit_rotations.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_floor = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FLOOR_H
|
|
#define IGL_FLOOR_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Floor a given matrix to nearest integers
|
|
//
|
|
// Inputs:
|
|
// X m by n matrix of scalars
|
|
// Outputs:
|
|
// Y m by n matrix of floored integers
|
|
template < typename DerivedX, typename DerivedY>
|
|
IGL_INLINE void floor(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
Eigen::PlainObjectBase<DerivedY>& Y);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "floor.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_forward_kinematics = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FORWARD_KINEMATICS_H
|
|
#define IGL_FORWARD_KINEMATICS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/StdVector>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Given a skeleton and a set of relative bone rotations compute absolute
|
|
// rigid transformations for each bone.
|
|
//
|
|
// Inputs:
|
|
// C #C by dim list of joint positions
|
|
// BE #BE by 2 list of bone edge indices
|
|
// P #BE list of parent indices into BE
|
|
// dQ #BE list of relative rotations
|
|
// Outputs:
|
|
// vQ #BE list of absolute rotations
|
|
// vT #BE list of absolute translations
|
|
IGL_INLINE void forward_kinematics(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::VectorXi & P,
|
|
const std::vector<
|
|
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
|
|
std::vector<
|
|
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ,
|
|
std::vector<Eigen::Vector3d> & vT);
|
|
// Outputs:
|
|
// T #BE*(dim+1) by dim stack of transposed transformation matrices
|
|
IGL_INLINE void forward_kinematics(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::VectorXi & P,
|
|
const std::vector<
|
|
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
|
|
Eigen::MatrixXd & T);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "forward_kinematics.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_frame_field_deformer = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FRAME_FIELD_DEFORMER_H
|
|
#define IGL_FRAME_FIELD_DEFORMER_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Deform a mesh to transform the given per-face frame field to be as close
|
|
// as possible to a cross field, in the least square sense.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 coordinates of the vertices
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// FF1 #F by 3 first representative vector of the frame field
|
|
// FF2 #F by 3 second representative vector of the frame field
|
|
// lambda laplacian regularization parameter 0=no regularization 1=full regularization
|
|
//
|
|
// Outputs:
|
|
// V_d #F by 3 deformed, first representative vector
|
|
// V_d #F by 3 deformed, first representative vector
|
|
// V_d #F by 3 deformed, first representative vector
|
|
//
|
|
IGL_INLINE void frame_field_deformer(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::MatrixXd& FF1,
|
|
const Eigen::MatrixXd& FF2,
|
|
Eigen::MatrixXd& V_d,
|
|
Eigen::MatrixXd& FF1_d,
|
|
Eigen::MatrixXd& FF2_d,
|
|
const int iterations = 50,
|
|
const double lambda = 0.1,
|
|
const bool perturb_initial_guess = true);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "frame_field_deformer.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_frame_to_cross_field = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FRAME_TO_CROSS_FIELD_H
|
|
#define IGL_FRAME_TO_CROSS_FIELD_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Convert a frame field into its closest cross field
|
|
// Inputs:
|
|
// V #V by 3 coordinates of the vertices
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// FF1 #F by 3 the first representative vector of the frame field (up to permutation and sign)
|
|
// FF2 #F by 3 the second representative vector of the frame field (up to permutation and sign)
|
|
//
|
|
// Outputs:
|
|
// X #F by 3 representative vector of the closest cross field
|
|
//
|
|
IGL_INLINE void frame_to_cross_field(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::MatrixXd& FF1,
|
|
const Eigen::MatrixXd& FF2,
|
|
Eigen::MatrixXd& X);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "frame_to_cross_field.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_frustum = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FRUSTUM_H
|
|
#define IGL_FRUSTUM_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Implementation of the deprecated glFrustum function.
|
|
//
|
|
// Inputs:
|
|
// left coordinate of left vertical clipping plane
|
|
// right coordinate of right vertical clipping plane
|
|
// bottom coordinate of bottom vertical clipping plane
|
|
// top coordinate of top vertical clipping plane
|
|
// nearVal distance to near plane
|
|
// farVal distance to far plane
|
|
// Outputs:
|
|
// P 4x4 perspective matrix
|
|
template < typename DerivedP>
|
|
IGL_INLINE void frustum(
|
|
const typename DerivedP::Scalar left,
|
|
const typename DerivedP::Scalar right,
|
|
const typename DerivedP::Scalar bottom,
|
|
const typename DerivedP::Scalar top,
|
|
const typename DerivedP::Scalar nearVal,
|
|
const typename DerivedP::Scalar farVal,
|
|
Eigen::PlainObjectBase<DerivedP> & P);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "frustum.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_full = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_FULL_H
|
|
#define IGL_FULL_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// This is totally unnecessary. You can just call MatrixXd B = MatrixXd(A);
|
|
//
|
|
// Convert a sparsematrix into a full one
|
|
//
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Input:
|
|
// A m by n sparse matrix
|
|
// Output:
|
|
// B m by n dense/full matrix
|
|
template <typename T,typename DerivedB>
|
|
IGL_INLINE void full(
|
|
const Eigen::SparseMatrix<T> & A,
|
|
Eigen::PlainObjectBase<DerivedB> & B);
|
|
// If already full then this will just be a copy by assignment
|
|
template <typename DerivedA,typename DerivedB>
|
|
IGL_INLINE void full(
|
|
const Eigen::PlainObjectBase<DerivedA>& A,
|
|
Eigen::PlainObjectBase<DerivedB>& B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "full.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_gaussian_curvature = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_GAUSSIAN_CURVATURE_H
|
|
#define IGL_GAUSSIAN_CURVATURE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute discrete gaussian curvature (angle deficit)
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (triangle) indices
|
|
// Output:
|
|
// K #V by 1 eigen Matrix of discrete gaussian curvature values
|
|
template <typename DerivedV, typename DerivedF, typename DerivedK>
|
|
IGL_INLINE void gaussian_curvature(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedK> & K);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "gaussian_curvature.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_get_seconds = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_GET_SECONDS_H
|
|
#define IGL_GET_SECONDS_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Return the current time in seconds since program start
|
|
//
|
|
// Example:
|
|
// const auto & tictoc = []()
|
|
// {
|
|
// static double t_start = igl::get_seconds();
|
|
// double diff = igl::get_seconds()-t_start;
|
|
// t_start += diff;
|
|
// return diff;
|
|
// };
|
|
// tictoc();
|
|
// ... // part 1
|
|
// cout<<"part 1: "<<tictoc()<<endl;
|
|
// ... // part 2
|
|
// cout<<"part 2: "<<tictoc()<<endl;
|
|
// ... // etc
|
|
IGL_INLINE double get_seconds();
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "get_seconds.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_get_seconds_hires = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_GET_SECONDS_HIRES_H
|
|
#define IGL_GET_SECONDS_HIRES_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Return the current time in seconds using performance counters
|
|
IGL_INLINE double get_seconds_hires();
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "get_seconds_hires.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_grad = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_GRAD_MAT_H
|
|
#define IGL_GRAD_MAT_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl {
|
|
// GRAD
|
|
// G = grad(V,F)
|
|
//
|
|
// Compute the numerical gradient operator
|
|
//
|
|
// Inputs:
|
|
// V #vertices by 3 list of mesh vertex positions
|
|
// F #faces by 3 list of mesh face indices
|
|
// Outputs:
|
|
// G #faces*dim by #V Gradient operator
|
|
//
|
|
|
|
// Gradient of a scalar function defined on piecewise linear elements (mesh)
|
|
// is constant on each triangle i,j,k:
|
|
// grad(Xijk) = (Xj-Xi) * (Vi - Vk)^R90 / 2A + (Xk-Xi) * (Vj - Vi)^R90 / 2A
|
|
// where Xi is the scalar value at vertex i, Vi is the 3D position of vertex
|
|
// i, and A is the area of triangle (i,j,k). ^R90 represent a rotation of
|
|
// 90 degrees
|
|
//
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void grad(const Eigen::PlainObjectBase<DerivedV>&V,
|
|
const Eigen::PlainObjectBase<DerivedF>&F,
|
|
Eigen::SparseMatrix<typename DerivedV::Scalar> &G);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "grad.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_group_sum_matrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_GROUP_SUM_MATRIX_H
|
|
#define IGL_GROUP_SUM_MATRIX_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// GROUP_SUM_MATRIX Builds a matrix A such that A*V computes the sum of
|
|
// vertices in each group specified by G
|
|
//
|
|
// group_sum_matrix(G,k,A);
|
|
//
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// G #V list of group indices (0 to k-1) for each vertex, such that vertex i
|
|
// is assigned to group G(i)
|
|
// k #groups, good choice is max(G)+1
|
|
// Outputs:
|
|
// A #groups by #V sparse matrix such that A*V = group_sums
|
|
//
|
|
template <typename T>
|
|
IGL_INLINE void group_sum_matrix(
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
|
|
const int k,
|
|
Eigen::SparseMatrix<T>& A);
|
|
// Wrapper with k = max(G)+1
|
|
template <typename T>
|
|
IGL_INLINE void group_sum_matrix(
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
|
|
Eigen::SparseMatrix<T>& A);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "group_sum_matrix.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_HalfEdgeIterator = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_HALFEDGEITERATOR_H
|
|
#define IGL_HALFEDGEITERATOR_H
|
|
|
|
#include <Eigen/Core>
|
|
|
|
#include <vector>
|
|
#include <igl/igl_inline.h>
|
|
|
|
namespace igl
|
|
{
|
|
// HalfEdgeIterator - Fake halfedge for fast and easy navigation on triangle meshes with vertex_triangle_adjacency and
|
|
// triangle_triangle adjacency
|
|
template <typename DerivedF>
|
|
class HalfEdgeIterator
|
|
{
|
|
public:
|
|
// Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation
|
|
IGL_INLINE HalfEdgeIterator(
|
|
const Eigen::PlainObjectBase<DerivedF>& _F,
|
|
const Eigen::PlainObjectBase<DerivedF>& _FF,
|
|
const Eigen::PlainObjectBase<DerivedF>& _FFi,
|
|
int _fi,
|
|
int _ei,
|
|
bool _reverse = false
|
|
)
|
|
: fi(_fi), ei(_ei), reverse(_reverse), F(_F), FF(_FF), FFi(_FFi)
|
|
{}
|
|
|
|
// Change Face
|
|
IGL_INLINE void flipF()
|
|
{
|
|
if (isBorder())
|
|
return;
|
|
|
|
int fin = (FF)(fi,ei);
|
|
int ein = (FFi)(fi,ei);
|
|
int reversen = !reverse;
|
|
|
|
fi = fin;
|
|
ei = ein;
|
|
reverse = reversen;
|
|
}
|
|
|
|
// Change Edge
|
|
IGL_INLINE void flipE()
|
|
{
|
|
if (!reverse)
|
|
ei = (ei+2)%3; // ei-1
|
|
else
|
|
ei = (ei+1)%3;
|
|
|
|
reverse = !reverse;
|
|
}
|
|
|
|
// Change Vertex
|
|
IGL_INLINE void flipV()
|
|
{
|
|
reverse = !reverse;
|
|
}
|
|
|
|
IGL_INLINE bool isBorder()
|
|
{
|
|
return (FF)(fi,ei) == -1;
|
|
}
|
|
|
|
/*!
|
|
* Returns the next edge skipping the border
|
|
* _________
|
|
* /\ c | b /\
|
|
* / \ | / \
|
|
* / d \ | / a \
|
|
* /______\|/______\
|
|
* v
|
|
* In this example, if a and d are of-border and the pos is iterating counterclockwise, this method iterate through the faces incident on vertex v,
|
|
* producing the sequence a, b, c, d, a, b, c, ...
|
|
*/
|
|
IGL_INLINE bool NextFE()
|
|
{
|
|
if ( isBorder() ) // we are on a border
|
|
{
|
|
do
|
|
{
|
|
flipF();
|
|
flipE();
|
|
} while (!isBorder());
|
|
flipE();
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
flipF();
|
|
flipE();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Get vertex index
|
|
IGL_INLINE int Vi()
|
|
{
|
|
assert(fi >= 0);
|
|
assert(fi < F.rows());
|
|
assert(ei >= 0);
|
|
assert(ei <= 2);
|
|
|
|
if (!reverse)
|
|
return (*F)(fi,ei);
|
|
else
|
|
return (*F)(fi,(ei+1)%3);
|
|
}
|
|
|
|
// Get face index
|
|
IGL_INLINE int Fi()
|
|
{
|
|
return fi;
|
|
}
|
|
|
|
// Get edge index
|
|
IGL_INLINE int Ei()
|
|
{
|
|
return ei;
|
|
}
|
|
|
|
|
|
IGL_INLINE bool operator==(HalfEdgeIterator& p2)
|
|
{
|
|
return
|
|
(
|
|
(fi == p2.fi) &&
|
|
(ei == p2.ei) &&
|
|
(reverse == p2.reverse) &&
|
|
(F == p2.F) &&
|
|
(FF == p2.FF) &&
|
|
(FFi == p2.FFi)
|
|
);
|
|
}
|
|
|
|
private:
|
|
int fi;
|
|
int ei;
|
|
bool reverse;
|
|
|
|
const Eigen::PlainObjectBase<DerivedF>& F;
|
|
const Eigen::PlainObjectBase<DerivedF>& FF;
|
|
const Eigen::PlainObjectBase<DerivedF>& FFi;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_harmonic = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_HARMONIC_H
|
|
#define IGL_HARMONIC_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute k-harmonic weight functions "coordinates".
|
|
//
|
|
//
|
|
// Inputs:
|
|
// V #V by dim vertex positions
|
|
// F #F by simplex-size list of element indices
|
|
// b #b boundary indices into V
|
|
// bc #b by #W list of boundary values
|
|
// k power of harmonic operation (1: harmonic, 2: biharmonic, etc)
|
|
// Outputs:
|
|
// W #V by #W list of weights
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename Derivedb,
|
|
typename Derivedbc,
|
|
typename DerivedW>
|
|
IGL_INLINE bool harmonic(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<Derivedb> & b,
|
|
const Eigen::PlainObjectBase<Derivedbc> & bc,
|
|
const int k,
|
|
Eigen::PlainObjectBase<DerivedW> & W);
|
|
};
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "harmonic.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_harwell_boeing = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_HARWELL_BOEING_H
|
|
#define IGL_HARWELL_BOEING_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Sparse>
|
|
#include <vector>
|
|
|
|
|
|
namespace igl
|
|
{
|
|
// Convert the matrix to Compressed sparse column (CSC or CCS) format,
|
|
// also known as Harwell Boeing format. As described:
|
|
// http://netlib.org/linalg/html_templates/node92.html
|
|
// or
|
|
// http://en.wikipedia.org/wiki/Sparse_matrix
|
|
// #Compressed_sparse_column_.28CSC_or_CCS.29
|
|
// Templates:
|
|
// Scalar type of sparse matrix like double
|
|
// Inputs:
|
|
// A sparse m by n matrix
|
|
// Outputs:
|
|
// num_rows number of rows
|
|
// V non-zero values, row indices running fastest, size(V) = nnz
|
|
// R row indices corresponding to vals, size(R) = nnz
|
|
// C index in vals of first entry in each column, size(C) = num_cols+1
|
|
//
|
|
// All indices and pointers are 0-based
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE void harwell_boeing(
|
|
const Eigen::SparseMatrix<Scalar> & A,
|
|
int & num_rows,
|
|
std::vector<Scalar> & V,
|
|
std::vector<Index> & R,
|
|
std::vector<Index> & C);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "harwell_boeing.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_histc = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_HISTC_H
|
|
#define IGL_HISTC_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Like matlab's histc. Count occurances of values in X between consecutive
|
|
// entries in E
|
|
//
|
|
// Inputs:
|
|
// X m-long Vector of values
|
|
// E n-long Monotonically increasing vector of edges
|
|
// Outputs:
|
|
// N n-long vector where N(k) reveals how many values in X fall between
|
|
// E(k) <= X < E(k+1)
|
|
// B m-long vector of bin ids so that B(j) = k if E(k) <= X(j) < E(k+1).
|
|
// B(j) = -1 if X(j) is outside of E.
|
|
//
|
|
// O(n+m*log(n))
|
|
template <typename DerivedX, typename DerivedE, typename DerivedN, typename DerivedB>
|
|
IGL_INLINE void histc(
|
|
const Eigen::PlainObjectBase<DerivedX > & X,
|
|
const Eigen::PlainObjectBase<DerivedE > & E,
|
|
Eigen::PlainObjectBase<DerivedN > & N,
|
|
Eigen::PlainObjectBase<DerivedB > & B);
|
|
// Truly O(m*log(n))
|
|
template <typename DerivedX, typename DerivedE, typename DerivedB>
|
|
IGL_INLINE void histc(
|
|
const Eigen::PlainObjectBase<DerivedX > & X,
|
|
const Eigen::PlainObjectBase<DerivedE > & E,
|
|
Eigen::PlainObjectBase<DerivedB > & B);
|
|
// Scalar search wrapper
|
|
template <typename DerivedE>
|
|
IGL_INLINE void histc(
|
|
const typename DerivedE::Scalar & x,
|
|
const Eigen::PlainObjectBase<DerivedE > & E,
|
|
typename DerivedE::Index & b);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "histc.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_hsv_to_rgb = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_HSV_TO_RGB_H
|
|
#define IGL_HSV_TO_RGB_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Convert RGB to HSV
|
|
//
|
|
// Inputs:
|
|
// h hue value (degrees: [0,360])
|
|
// s saturation value ([0,1])
|
|
// v value value ([0,1])
|
|
// Outputs:
|
|
// r red value ([0,1])
|
|
// g green value ([0,1])
|
|
// b blue value ([0,1])
|
|
template <typename T>
|
|
IGL_INLINE void hsv_to_rgb(const T * hsv, T * rgb);
|
|
template <typename T>
|
|
IGL_INLINE void hsv_to_rgb(
|
|
const T & h, const T & s, const T & v,
|
|
T & r, T & g, T & b);
|
|
template <typename DerivedH, typename DerivedR>
|
|
void hsv_to_rgb(
|
|
const Eigen::PlainObjectBase<DerivedH> & H,
|
|
Eigen::PlainObjectBase<DerivedR> & R);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "hsv_to_rgb.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_igl_inline = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
// This should *NOT* be contained in a IGL_*_H ifdef, since it may be defined
|
|
// differently based on when it is included
|
|
#ifdef IGL_INLINE
|
|
#undef IGL_INLINE
|
|
#endif
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# define IGL_INLINE inline
|
|
#else
|
|
# define IGL_INLINE
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_in_element = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IN_ELEMENT_H
|
|
#define IGL_IN_ELEMENT_H
|
|
|
|
#include "igl_inline.h"
|
|
#include "AABB.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Determine whether each point in a list of points is in the elements of a
|
|
// mesh.
|
|
//
|
|
// templates:
|
|
// DIM dimension of vertices in V (# of columns)
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions.
|
|
// Ele #Ele by dim+1 list of mesh indices into #V.
|
|
// Q #Q by dim list of query point positions
|
|
// aabb axis-aligned bounding box tree object (see AABB.h)
|
|
// Outputs:
|
|
// I #Q list of indices into Ele of first containing element (-1 means no
|
|
// containing element)
|
|
template <typename DerivedV, typename DerivedQ, int DIM>
|
|
IGL_INLINE void in_element(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<DerivedQ> & Q,
|
|
const AABB<DerivedV,DIM> & aabb,
|
|
Eigen::VectorXi & I);
|
|
// Outputs:
|
|
// I #Q by #Ele sparse matrix revealing whether each element contains each
|
|
// point: I(q,e) means point q is in element e
|
|
template <typename DerivedV, typename DerivedQ, int DIM, typename Scalar>
|
|
IGL_INLINE void in_element(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
const Eigen::PlainObjectBase<DerivedQ> & Q,
|
|
const AABB<DerivedV,DIM> & aabb,
|
|
Eigen::SparseMatrix<Scalar> & I);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "in_element.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_IndexComparison = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_INDEXCOMPARISON_H
|
|
#define IGL_INDEXCOMPARISON_H
|
|
#include <iostream>
|
|
// Comparison struct used by sort
|
|
// http://bytes.com/topic/c/answers/132045-sort-get-index
|
|
namespace igl{
|
|
|
|
// For use with functions like std::sort
|
|
template<class T> struct IndexLessThan
|
|
{
|
|
IndexLessThan(const T arr) : arr(arr) {}
|
|
bool operator()(const size_t a, const size_t b) const
|
|
{
|
|
return arr[a] < arr[b];
|
|
}
|
|
const T arr;
|
|
};
|
|
|
|
// For use with functions like std::unique
|
|
template<class T> struct IndexEquals
|
|
{
|
|
IndexEquals(const T arr) : arr(arr) {}
|
|
bool operator()(const size_t a, const size_t b) const
|
|
{
|
|
return arr[a] == arr[b];
|
|
}
|
|
const T arr;
|
|
};
|
|
|
|
// For use with functions like std::sort
|
|
template<class T> struct IndexVectorLessThan
|
|
{
|
|
IndexVectorLessThan(const T & vec) : vec ( vec) {}
|
|
bool operator()(const size_t a, const size_t b) const
|
|
{
|
|
return vec(a) < vec(b);
|
|
}
|
|
const T & vec;
|
|
};
|
|
|
|
// For use with functions like std::sort
|
|
template<class T> struct IndexDimLessThan
|
|
{
|
|
IndexDimLessThan(const T & mat,const int & dim, const int & j) :
|
|
mat(mat),
|
|
dim(dim),
|
|
j(j)
|
|
{}
|
|
bool operator()(const size_t a, const size_t b) const
|
|
{
|
|
if(dim == 1)
|
|
{
|
|
return mat(a,j) < mat(b,j);
|
|
}else
|
|
{
|
|
return mat(j,a) < mat(j,b);
|
|
}
|
|
}
|
|
const T & mat;
|
|
const int & dim;
|
|
const int & j;
|
|
};
|
|
|
|
// For use with functions like std::sort
|
|
template<class T> struct IndexRowLessThan
|
|
{
|
|
IndexRowLessThan(const T & mat) : mat ( mat) {}
|
|
bool operator()(const size_t a, const size_t b) const
|
|
{
|
|
const int cols = mat.cols();
|
|
// Lexicographical order
|
|
for(int j = 0;j<cols;j++)
|
|
{
|
|
if(mat(a,j) > mat(b,j))
|
|
{
|
|
return false;
|
|
} else if(mat(a,j) < mat(b,j))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
// equality is false
|
|
return false;
|
|
}
|
|
const T & mat;
|
|
};
|
|
|
|
// For use with functions like std::sort
|
|
template<class T> struct IndexRowEquals
|
|
{
|
|
IndexRowEquals(const T & mat) : mat ( mat) {}
|
|
bool operator()(const size_t a, const size_t b) const
|
|
{
|
|
const int cols = mat.cols();
|
|
// Lexicographical order
|
|
for(int j = 0;j<cols;j++)
|
|
{
|
|
if(mat(a,j) != mat(b,j))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
const T & mat;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_integrable_polyvector_fields = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_INTEGRABLE_POLYVECTOR_FIELDS
|
|
#define IGL_INTEGRABLE_POLYVECTOR_FIELDS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl {
|
|
// Compute a curl-free frame field from user constraints, optionally starting
|
|
// from a gived frame field (assumed to be interpolating the constraints).
|
|
// Implementation of the paper "Integrable PolyVector Fields", SIGGRAPH 2015.
|
|
|
|
// Set of parameters used during solve
|
|
struct integrable_polyvector_fields_parameters;
|
|
|
|
// All data necessary for solving. Gets initialized from the original field
|
|
// and gets updated during each solve.
|
|
template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC> class IntegrableFieldSolverData;
|
|
|
|
|
|
// Precomputes matrices and necessary initial variables from the mesh and the
|
|
// original field. This function is meant to be called before solve().
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex coordinates
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// b #B by 1 list of constrained face indices
|
|
// bc #B by 6 list of the representative vectors at the constrained faces
|
|
// constraint_level #B by 1 list of "constraint level" flag (level=2 indicates that both directions are constrained,
|
|
// level = 1 indicates a partially constrained face, i.e. only the first vector will be constrained)
|
|
// original_field #F by 6 list of the representative vectors of the frame field to be used as a starting point
|
|
// (up to permutation and sign, stacked horizontally for each face)
|
|
// Returns:
|
|
// data an IntegrableFieldSolverData object that holds all intermediate
|
|
// data needed by the solve routine, with correctly initialized values.
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
|
|
IGL_INLINE void integrable_polyvector_fields_precompute(const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::PlainObjectBase<DerivedC>& bc,
|
|
const Eigen::VectorXi& constraint_level,
|
|
const Eigen::PlainObjectBase<DerivedFF>& original_field,
|
|
igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data);
|
|
|
|
|
|
// Given the current estimate of the field, performes one round of optimization
|
|
// iterations and updates the current estimate. The intermediate data is saved
|
|
// and returned for the next iteration.
|
|
// Inputs:
|
|
// data an IntegrableFieldSolverData object that holds all intermediate
|
|
// data needed by the solve routine, with their values at the current time instance.
|
|
// params solver parameters (see below)
|
|
// current_field #F by 6 list of the representative vectors of the current frame field to be used as a starting point
|
|
// current_field_is_not_ccw boolean, determines whether the representative vectors in the current field are in
|
|
// non- ccw order - if true, they will be corrected before being passed to the solver.
|
|
// The field returned by this routine is always in ccw order, so this flag typically only
|
|
// needs to be set to true during the first call to solve(). If unsure, set to true.
|
|
// Returns:
|
|
// current_field updated estimate for the integrable field
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
|
|
IGL_INLINE void integrable_polyvector_fields_solve(IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata,
|
|
integrable_polyvector_fields_parameters ¶ms,
|
|
Eigen::PlainObjectBase<DerivedFF>& current_field,
|
|
bool current_field_is_not_ccw);
|
|
|
|
|
|
};
|
|
|
|
|
|
//parameters
|
|
struct igl::integrable_polyvector_fields_parameters
|
|
{
|
|
// number of optimization iterations
|
|
int numIter;
|
|
//weight for barrier term (ensuring ccw ordering of the vectors per face)
|
|
double wBarrier;
|
|
//the s-parameter of the barrier term (see Schüller et al. 2013, Locally Injective Mappings)
|
|
double sBarrier;
|
|
//weight for the PolyCurl term of the energy
|
|
double wCurl;
|
|
//weight for the PolyQuotient term of the energy
|
|
double wQuotCurl;
|
|
//weight for the smoothness term of the energy
|
|
double wSmooth;
|
|
//weight for the closeness to the original field, for the unconstrained faces (regularization term)
|
|
double wCloseUnconstrained;
|
|
//weight for the closeness to the original field, for the constrained faces
|
|
double wCloseConstrained;
|
|
//the per-iteration reduction factor the smoothness weight
|
|
double redFactor_wsmooth;
|
|
//the step size for the Gauss-Newton optimization
|
|
double gamma;
|
|
//tikhonov regularization term (typically not needed, default value should suffice)
|
|
double tikh_gamma;
|
|
|
|
IGL_INLINE integrable_polyvector_fields_parameters();
|
|
|
|
};
|
|
|
|
//solver data
|
|
template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
|
|
class igl::IntegrableFieldSolverData
|
|
{
|
|
public:
|
|
//Original field
|
|
Eigen::VectorXd xOriginal;
|
|
|
|
//Constraints
|
|
Eigen::VectorXi constrained;
|
|
Eigen::VectorXi is_constrained_face;//0 for unconstrained, 1 for constrained once (partial) and 2 for fully constrained
|
|
Eigen::VectorXi indInConstrained;
|
|
Eigen::MatrixXd constrained_vec3;
|
|
|
|
//Mesh data
|
|
//edges and normalized edge vectors
|
|
Eigen::MatrixXd EVecNorm;
|
|
Eigen::MatrixXi E, E2F, F2E;
|
|
int numV, numF, numE;
|
|
//interior edge data
|
|
int numInteriorEdges;
|
|
Eigen::Matrix<int,Eigen::Dynamic,2> E2F_int;
|
|
Eigen::VectorXi indInteriorToFull;
|
|
Eigen::VectorXi indFullToInterior;
|
|
//per-edge angles (for parallel transport)
|
|
Eigen::VectorXd K;
|
|
//local bases
|
|
Eigen::PlainObjectBase<DerivedV> B1, B2, FN;
|
|
|
|
//Solver Data
|
|
Eigen::VectorXd residuals;
|
|
Eigen::SparseMatrix<double> Jac;
|
|
Eigen::VectorXi II_Jac, JJ_Jac;
|
|
Eigen::VectorXd SS_Jac;
|
|
int numVariables;
|
|
int num_residuals;
|
|
int num_residuals_smooth;
|
|
int num_residuals_close;
|
|
int num_residuals_polycurl;
|
|
int num_residuals_quotcurl;
|
|
int num_residuals_barrier;
|
|
const int numInnerJacCols_edge = 8;
|
|
const int numInnerJacCols_face = 4;
|
|
const int numInnerJacRows_smooth = 4;
|
|
const int numInnerJacRows_polycurl = 2;
|
|
const int numInnerJacRows_quotcurl = 1;
|
|
const int numInnerJacRows_barrier = 1;
|
|
const int numInnerJacRows_close = 4;
|
|
int numJacElements_smooth;
|
|
int numJacElements_polycurl;
|
|
int numJacElements_quotcurl;
|
|
int numJacElements_barrier;
|
|
int numJacElements_close;
|
|
int numJacElements;
|
|
IGL_INLINE void add_jac_indices_face(const int numInnerRows,
|
|
const int numInnerCols,
|
|
const int startRowInJacobian,
|
|
const int startIndexInVectors,
|
|
Eigen::VectorXi &Rows,
|
|
Eigen::VectorXi &Columns);
|
|
IGL_INLINE void face_Jacobian_indices(const int &startRow,
|
|
const int &toplace,
|
|
const int& fi,
|
|
const int& half_degree,
|
|
const int &numInnerRows,
|
|
const int &numInnerCols,
|
|
Eigen::VectorXi &rows,
|
|
Eigen::VectorXi &columns);
|
|
IGL_INLINE void add_Jacobian_to_svector(const int &toplace,
|
|
const Eigen::MatrixXd &tJac,
|
|
Eigen::VectorXd &SS_Jac);
|
|
|
|
IGL_INLINE void add_jac_indices_edge(const int numInnerRows,
|
|
const int numInnerCols,
|
|
const int startRowInJacobian,
|
|
const int startIndexInVectors,
|
|
Eigen::VectorXi &Rows,
|
|
Eigen::VectorXi &Columns);
|
|
IGL_INLINE void edge_Jacobian_indices(const int &startRow,
|
|
const int &toplace,
|
|
const int& a,
|
|
const int& b,
|
|
const int& half_degree,
|
|
const int &numInnerRows,
|
|
const int &numInnerCols,
|
|
Eigen::VectorXi &rows,
|
|
Eigen::VectorXi &columns);
|
|
std::vector<int> indInSS_Hess_1_vec;
|
|
std::vector<int> indInSS_Hess_2_vec;
|
|
Eigen::SparseMatrix<double> Hess;
|
|
std::vector<Eigen::Triplet<double> > Hess_triplets;
|
|
Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver;
|
|
|
|
IGL_INLINE void precomputeMesh(const Eigen::PlainObjectBase<DerivedV> &_V,
|
|
const Eigen::PlainObjectBase<DerivedF> &_F);
|
|
IGL_INLINE void computeInteriorEdges();
|
|
IGL_INLINE void computeJacobianPattern();
|
|
IGL_INLINE void computeHessianPattern();
|
|
IGL_INLINE void computeNewHessValues();
|
|
IGL_INLINE void initializeOriginalVariable(const Eigen::PlainObjectBase<DerivedFF>& original_field);
|
|
IGL_INLINE void initializeConstraints(const Eigen::VectorXi& b,
|
|
const Eigen::PlainObjectBase<DerivedC>& bc,
|
|
const Eigen::VectorXi& constraint_level);
|
|
IGL_INLINE void makeFieldCCW(Eigen::MatrixXd &sol3D);
|
|
|
|
public:
|
|
IGL_INLINE IntegrableFieldSolverData();
|
|
|
|
IGL_INLINE IntegrableFieldSolverData(
|
|
const Eigen::PlainObjectBase<DerivedV> &_V,
|
|
const Eigen::PlainObjectBase<DerivedF> &_F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::VectorXi& constraint_level,
|
|
const Eigen::PlainObjectBase<DerivedFF>& original_field);
|
|
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "integrable_polyvector_fields.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_INTEGRABLE_POLYVECTOR_FIELDS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_internal_angles = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_INTERNAL_ANGLES_H
|
|
#define IGL_INTERNAL_ANGLES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute internal angles for a triangle mesh
|
|
//
|
|
// Inputs:
|
|
// V #V by dim eigen Matrix of mesh vertex nD positions
|
|
// F #F by poly-size eigen Matrix of face (triangle) indices
|
|
// Output:
|
|
// K #F by poly-size eigen Matrix of internal angles
|
|
// for triangles, columns correspond to edges [1,2],[2,0],[0,1]
|
|
//
|
|
// Known Issues:
|
|
// if poly-size ≠ 3 then dim must equal 3.
|
|
template <typename DerivedV, typename DerivedF, typename DerivedK>
|
|
IGL_INLINE void internal_angles(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedK> & K);
|
|
// Inputs:
|
|
// L #F by 3 list of edge lengths
|
|
template <typename DerivedL, typename DerivedK>
|
|
IGL_INLINE void internal_angles(
|
|
const Eigen::PlainObjectBase<DerivedL>& L,
|
|
Eigen::PlainObjectBase<DerivedK> & K);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "internal_angles.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_intersect = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_INTERSECT_H
|
|
#define IGL_INTERSECT_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Determine the intersect between two sets of coefficients using ==
|
|
// Templates:
|
|
// M matrix type that implements indexing by global index M(i)
|
|
// Inputs:
|
|
// A matrix of coefficients
|
|
// B matrix of coefficients
|
|
// Output:
|
|
// C matrix of elements appearing in both A and B, C is always resized to
|
|
// have a single column
|
|
template <class M>
|
|
IGL_INLINE void intersect(const M & A, const M & B, M & C);
|
|
// Last argument as return
|
|
template <class M>
|
|
IGL_INLINE M intersect(const M & A, const M & B);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "intersect.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_invert_diag = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_INVERT_DIAG_H
|
|
#define IGL_INVERT_DIAG_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Invert the diagonal entries of a matrix (if the matrix is a diagonal
|
|
// matrix then this amounts to inverting the matrix)
|
|
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// X an m by n sparse matrix
|
|
// Outputs:
|
|
// Y an m by n sparse matrix
|
|
template <typename T>
|
|
IGL_INLINE void invert_diag(
|
|
const Eigen::SparseMatrix<T>& X,
|
|
Eigen::SparseMatrix<T>& Y);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "invert_diag.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_border_vertex = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_BORDER_VERTEX_H
|
|
#define IGL_IS_BORDER_VERTEX_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Determine vertices on open boundary of a (manifold) mesh with triangle
|
|
// faces F
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// Returns #V vector of bools revealing whether vertices are on boundary
|
|
//
|
|
// Known Bugs: - does not depend on V
|
|
// - assumes mesh is edge manifold
|
|
//
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE std::vector<bool> is_border_vertex(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_border_vertex.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_boundary_edge = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IS_BOUNDARY_EDGE_H
|
|
#define IS_BOUNDARY_EDGE_H
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// IS_BOUNDARY_EDGE Determine for each edge E if it is a "boundary edge" in F.
|
|
// Boundary edges are undirected edges which occur only once.
|
|
//
|
|
// Inputs:
|
|
// E #E by 2 list of edges
|
|
// F #F by 3 list of triangles
|
|
// Outputs:
|
|
// B #E list bools. true iff unoriented edge occurs exactly once in F
|
|
// (non-manifold and non-existant edges will be false)
|
|
//
|
|
template <
|
|
typename DerivedF,
|
|
typename DerivedE,
|
|
typename DerivedB>
|
|
void is_boundary_edge(
|
|
const Eigen::PlainObjectBase<DerivedE> & E,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedB> & B);
|
|
// Wrapper where Edges should also be computed from F
|
|
// E #E by 2 list of edges
|
|
// EMAP #F*3 list of indices mapping allE to E
|
|
template <
|
|
typename DerivedF,
|
|
typename DerivedE,
|
|
typename DerivedB,
|
|
typename DerivedEMAP>
|
|
void is_boundary_edge(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedB> & B,
|
|
Eigen::PlainObjectBase<DerivedE> & E,
|
|
Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_boundary_edge.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_dir = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_DIR_H
|
|
#define IGL_IS_DIR_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Act like php's is_dir function
|
|
// http://php.net/manual/en/function.is-dir.php
|
|
// Tells whether the given filename is a directory.
|
|
// Input:
|
|
// filename Path to the file. If filename is a relative filename, it will
|
|
// be checked relative to the current working directory.
|
|
// Returns TRUE if the filename exists and is a directory, FALSE
|
|
// otherwise.
|
|
IGL_INLINE bool is_dir(const char * filename);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_dir.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_edge_manifold = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_EDGE_MANIFOLD_H
|
|
#define IGL_IS_EDGE_MANIFOLD_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// check if the mesh is edge-manifold
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions **unneeded**
|
|
// F #F by 3 list of triangle indices
|
|
// Returns whether mesh is edge manifold.
|
|
//
|
|
// Known Bugs:
|
|
// Does not check for non-manifold vertices
|
|
//
|
|
// See also: is_vertex_manifold
|
|
template <
|
|
typename DerivedF,
|
|
typename DerivedBF,
|
|
typename DerivedE,
|
|
typename DerivedEMAP,
|
|
typename DerivedBE>
|
|
IGL_INLINE bool is_edge_manifold(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedBF>& BF,
|
|
Eigen::PlainObjectBase<DerivedE>& E,
|
|
Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
|
Eigen::PlainObjectBase<DerivedBE>& BE);
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool is_edge_manifold(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_edge_manifold.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_file = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_FILE_H
|
|
#define IGL_IS_FILE_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Act like php's is_file function
|
|
// http://php.net/manual/en/function.is-file.php
|
|
// Tells whether the given filename is a regular file.
|
|
// Input:
|
|
// filename Path to the file. If filename is a relative filename, it will
|
|
// be checked relative to the current working directory.
|
|
// Returns TRUE if the filename exists and is a regular file, FALSE
|
|
// otherwise.
|
|
IGL_INLINE bool is_file(const char * filename);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_file.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_irregular_vertex = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_IRREGULAR_VERTEX_H
|
|
#define IGL_IS_IRREGULAR_VERTEX_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Determine if a vertex is irregular, i.e. it has more than 6 (triangles)
|
|
// or 4 (quads) incident edges. Vertices on the boundary are ignored.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// F #F by 3[4] list of triangle[quads] indices
|
|
// Returns #V vector of bools revealing whether vertices are singular
|
|
//
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE std::vector<bool> is_irregular_vertex(const Eigen::PlainObjectBase<DerivedV> &V, const Eigen::PlainObjectBase<DerivedF> &F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_irregular_vertex.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_planar = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_PLANAR_H
|
|
#define IGL_IS_PLANAR_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Determin if a set of points lies on the XY plane
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// Return true if a mesh has constant value of 0 in z coordinate
|
|
//
|
|
// Known bugs: Doesn't determine if vertex is flat if it doesn't lie on the
|
|
// XY plane.
|
|
IGL_INLINE bool is_planar(const Eigen::MatrixXd & V);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_planar.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_readable = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_READABLE_H
|
|
#define IGL_IS_READABLE_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Check if a file is reabable like PHP's is_readable function:
|
|
// http://www.php.net/manual/en/function.is-readable.php
|
|
// Input:
|
|
// filename path to file
|
|
// Returns true if file exists and is readable and false if file doesn't
|
|
// exist or *is not readable*
|
|
//
|
|
// Note: Windows version will not check user or group ids
|
|
IGL_INLINE bool is_readable(const char * filename);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_readable.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_sparse = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_SPARSE_H
|
|
#define IGL_IS_SPARSE_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Determine if a matrix A is sparse
|
|
//
|
|
// Template:
|
|
// T,DerivedA defines scalar type
|
|
// Inputs:
|
|
// A matrix in question
|
|
// Returns true if A is represented with a sparse matrix
|
|
template <typename T>
|
|
IGL_INLINE bool is_sparse(
|
|
const Eigen::SparseMatrix<T> & A);
|
|
template <typename DerivedA>
|
|
IGL_INLINE bool is_sparse(
|
|
const Eigen::PlainObjectBase<DerivedA>& A);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_sparse.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_symmetric = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_SYMMETRIC_H
|
|
#define IGL_IS_SYMMETRIC_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Returns true if the given matrix is symmetric
|
|
// Inputs:
|
|
// A m by m matrix
|
|
// Returns true if the matrix is square and symmetric
|
|
template <typename AT>
|
|
IGL_INLINE bool is_symmetric(const Eigen::SparseMatrix<AT>& A);
|
|
// Inputs:
|
|
// epsilon threshold on L1 difference between A and A'
|
|
template <typename AT, typename epsilonT>
|
|
IGL_INLINE bool is_symmetric(const Eigen::SparseMatrix<AT>& A, const epsilonT epsilon);
|
|
template <typename DerivedA>
|
|
IGL_INLINE bool is_symmetric(
|
|
const Eigen::PlainObjectBase<DerivedA>& A);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_symmetric.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_vertex_manifold = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_VERTEX_MANIFOLD_H
|
|
#define IGL_IS_VERTEX_MANIFOLD_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Check if a mesh is vertex-manifold. This only checks whether the faces
|
|
// incident on each vertex form exactly one connected component. Vertices
|
|
// incident on non-manifold edges are not consider non-manifold by this
|
|
// function (see is_edge_manifold.h). Unreferenced verties are considered
|
|
// non-manifold (zero components).
|
|
//
|
|
// Inputs:
|
|
// F #F by 3 list of triangle indices
|
|
// Outputs:
|
|
// B #V list whether
|
|
// Returns whether mesh is vertex manifold.
|
|
//
|
|
// See also: is_edge_manifold
|
|
template <typename DerivedF,typename DerivedB>
|
|
IGL_INLINE bool is_vertex_manifold(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedB>& B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_vertex_manifold.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_is_writable = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_IS_WRITABLE_H
|
|
#define IGL_IS_WRITABLE_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Check if a file exists *and* is writable like PHP's is_writable function:
|
|
// http://www.php.net/manual/en/function.is-writable.php
|
|
// Input:
|
|
// filename path to file
|
|
// Returns true if file exists and is writable and false if file doesn't
|
|
// exist or *is not writable*
|
|
//
|
|
// Note: Windows version will not test group and user id
|
|
IGL_INLINE bool is_writable(const char * filename);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "is_writable.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_jet = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_JET_H
|
|
#define IGL_JET_H
|
|
#include "igl_inline.h"
|
|
//#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Dense>
|
|
//#endif
|
|
namespace igl
|
|
{
|
|
// JET like MATLAB's jet
|
|
//
|
|
// Inputs:
|
|
// m number of colors
|
|
// Outputs:
|
|
// J m by list of RGB colors between 0 and 1
|
|
//
|
|
//#ifndef IGL_NO_EIGEN
|
|
// void jet(const int m, Eigen::MatrixXd & J);
|
|
//#endif
|
|
// Wrapper for directly computing [r,g,b] values for a given factor f between
|
|
// 0 and 1
|
|
//
|
|
// Inputs:
|
|
// f factor determining color value as if 0 was min and 1 was max
|
|
// Outputs:
|
|
// r red value
|
|
// g green value
|
|
// b blue value
|
|
template <typename T>
|
|
IGL_INLINE void jet(const T f, T * rgb);
|
|
template <typename T>
|
|
IGL_INLINE void jet(const T f, T & r, T & g, T & b);
|
|
// Inputs:
|
|
// Z #Z list of factos
|
|
// normalize whether to normalize Z to be tightly between [0,1]
|
|
// Outputs:
|
|
// C #C by 3 list of rgb colors
|
|
template <typename DerivedZ, typename DerivedC>
|
|
IGL_INLINE void jet(
|
|
const Eigen::PlainObjectBase<DerivedZ> & Z,
|
|
const bool normalize,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
// Inputs:
|
|
// min_z value at blue
|
|
// max_z value at red
|
|
template <typename DerivedZ, typename DerivedC>
|
|
IGL_INLINE void jet(
|
|
const Eigen::PlainObjectBase<DerivedZ> & Z,
|
|
const double min_Z,
|
|
const double max_Z,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "jet.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_launch_medit = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LAUNCH_MEDIT_H
|
|
#define IGL_LAUNCH_MEDIT_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Writes the tetmesh in (V,T,F) to a temporary file, opens it with medit
|
|
// (forking with a system call) and returns
|
|
//
|
|
//
|
|
// Templates:
|
|
// DerivedV real-value: i.e. from MatrixXd
|
|
// DerivedT integer-value: i.e. from MatrixXi
|
|
// DerivedF integer-value: i.e. from MatrixXi
|
|
// Inputs:
|
|
// V double matrix of vertex positions #V by 3
|
|
// T #T list of tet indices into vertex positions
|
|
// F #F list of face indices into vertex positions
|
|
// wait whether to wait for medit process to finish before returning
|
|
// Returns returned value of system call (probably not useful if wait=false
|
|
// because of the fork)
|
|
template <typename DerivedV, typename DerivedT, typename DerivedF>
|
|
IGL_INLINE int launch_medit(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedT> & T,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const bool wait);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "launch_medit.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_lbs_matrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LBS_MATRIX_H
|
|
#define IGL_LBS_MATRIX_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// LBS_MATRIX Linear blend skinning can be expressed by V' = M * T where V' is
|
|
// a #V by dim matrix of deformed vertex positions (one vertex per row), M is a
|
|
// #V by (dim+1)*#T (composed of weights and rest positions) and T is a
|
|
// #T*(dim+1) by dim matrix of #T stacked transposed transformation matrices.
|
|
// See equations (1) and (2) in "Fast Automatic Skinning Transformations"
|
|
// [Jacobson et al 2012]
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of rest positions
|
|
// W #V+ by #T list of weights
|
|
// Outputs:
|
|
// M #V by #T*(dim+1)
|
|
//
|
|
// In MATLAB:
|
|
// kron(ones(1,size(W,2)),[V ones(size(V,1),1)]).*kron(W,ones(1,size(V,2)+1))
|
|
IGL_INLINE void lbs_matrix(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXd & W,
|
|
Eigen::MatrixXd & M);
|
|
// LBS_MATRIX construct a matrix that when multiplied against a column of
|
|
// affine transformation entries computes new coordinates of the vertices
|
|
//
|
|
// I'm not sure it makes since that the result is stored as a sparse matrix.
|
|
// The number of non-zeros per row *is* dependent on the number of mesh
|
|
// vertices and handles.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex rest positions
|
|
// W #V by #handles list of correspondence weights
|
|
// Output:
|
|
// M #V * dim by #handles * dim * (dim+1) matrix such that
|
|
// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
|
|
// vectors formed by the entries in each handle's dim by dim+1
|
|
// transformation matrix. Specifcally, A =
|
|
// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
|
|
// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
|
|
// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
|
|
IGL_INLINE void lbs_matrix_column(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXd & W,
|
|
Eigen::SparseMatrix<double>& M);
|
|
IGL_INLINE void lbs_matrix_column(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXd & W,
|
|
Eigen::MatrixXd & M);
|
|
// Same as LBS_MATRIX above but instead of giving W as a full matrix of weights
|
|
// (each vertex has #handles weights), a constant number of weights are given
|
|
// for each vertex.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex rest positions
|
|
// W #V by k list of k correspondence weights per vertex
|
|
// WI #V by k list of k correspondence weight indices per vertex. Such that
|
|
// W(j,WI(i)) gives the ith most significant correspondence weight on vertex j
|
|
// Output:
|
|
// M #V * dim by #handles * dim * (dim+1) matrix such that
|
|
// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
|
|
// vectors formed by the entries in each handle's dim by dim+1
|
|
// transformation matrix. Specifcally, A =
|
|
// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
|
|
// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
|
|
// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
|
|
//
|
|
IGL_INLINE void lbs_matrix_column(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXd & W,
|
|
const Eigen::MatrixXi & WI,
|
|
Eigen::SparseMatrix<double>& M);
|
|
IGL_INLINE void lbs_matrix_column(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXd & W,
|
|
const Eigen::MatrixXi & WI,
|
|
Eigen::MatrixXd & M);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "lbs_matrix.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_limit_faces = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LIMIT_FACES_H
|
|
#define IGL_LIMIT_FACES_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// LIMIT_FACES limit given faces F to those which contain (only) indices found
|
|
// in L.
|
|
//
|
|
// [LF] = limit_faces(F,L,exclusive);
|
|
// [LF,in] = limit_faces(F,L,exclusive);
|
|
//
|
|
// Templates:
|
|
// MatF matrix type of faces, matrixXi
|
|
// VecL matrix type of vertex indices, VectorXi
|
|
// Inputs:
|
|
// F #F by 3 list of face indices
|
|
// L #L by 1 list of allowed indices
|
|
// exclusive flag specifying whether a face is included only if all its
|
|
// indices are in L, default is false
|
|
// Outputs:
|
|
// LF #LF by 3 list of remaining faces after limiting
|
|
// in #F list of whether given face was included
|
|
//
|
|
template <typename MatF, typename VecL>
|
|
IGL_INLINE void limit_faces(
|
|
const MatF & F,
|
|
const VecL & L,
|
|
const bool exclusive,
|
|
MatF & LF);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "limit_faces.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_line_field_missmatch = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Nico Pietroni <nico.pietroni@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_LINE_FIELD_MISSMATCH_H
|
|
#define IGL_LINE_FIELD_MISSMATCH_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Calculates the missmatch (integer), at each face edge, of a cross field defined on the mesh faces.
|
|
// The integer missmatch is a multiple of pi/2 that transforms the cross on one side of the edge to
|
|
// the cross on the other side. It represents the deviation from a Lie connection across the edge.
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (quad) indices
|
|
// PD1 #F by 3 eigen Matrix of the first per face cross field vector
|
|
// PD2 #F by 3 eigen Matrix of the second per face cross field vector
|
|
// isCombed boolean, specifying whether the field is combed (i.e. matching has been precomputed.
|
|
// If not, the field is combed first.
|
|
// Output:
|
|
// Handle_MMatch #F by 3 eigen Matrix containing the integer missmatch of the cross field
|
|
// across all face edges
|
|
//
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedO>
|
|
IGL_INLINE void line_field_missmatch(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD1,
|
|
const bool isCombed,
|
|
Eigen::PlainObjectBase<DerivedO> &missmatch);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "line_field_missmatch.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_line_segment_in_rectangle = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LINE_SEGMENT_IN_RECTANGLE_H
|
|
#define IGL_LINE_SEGMENT_IN_RECTANGLE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Determine whether a line segment overlaps with a rectangle.
|
|
//
|
|
// Inputs:
|
|
// s source point of line segment
|
|
// d dest point of line segment
|
|
// A first corner of rectangle
|
|
// B opposite corner of rectangle
|
|
// Returns true if line segment is at all inside rectangle
|
|
IGL_INLINE bool line_segment_in_rectangle(
|
|
const Eigen::Vector2d & s,
|
|
const Eigen::Vector2d & d,
|
|
const Eigen::Vector2d & A,
|
|
const Eigen::Vector2d & B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "line_segment_in_rectangle.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_linprog = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LINPROG_H
|
|
#define IGL_LINPROG_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Solve a linear program given in "standard form"
|
|
//
|
|
// min f'x
|
|
// s.t. A( 1:k,:) x <= b(1:k)
|
|
// A(k+1:end,:) x = b(k+1:end)
|
|
// ** x >= 0 **
|
|
//
|
|
// In contrast to other APIs the entries in b may be negative.
|
|
//
|
|
// Inputs:
|
|
// c #x list of linear coefficients
|
|
// A #A by #x matrix of linear constraint coefficients
|
|
// b #A list of linear constraint right-hand sides
|
|
// k number of inequality constraints as first rows of A,b
|
|
// Outputs:
|
|
// x #x solution vector
|
|
//
|
|
IGL_INLINE bool linprog(
|
|
const Eigen::VectorXd & c,
|
|
const Eigen::MatrixXd & A,
|
|
const Eigen::VectorXd & b,
|
|
const int k,
|
|
Eigen::VectorXd & f);
|
|
|
|
// Wrapper in friendlier general form (no implicit bounds on x)
|
|
//
|
|
// min f'x
|
|
// s.t. A x <= b
|
|
// B x = c
|
|
//
|
|
// Inputs:
|
|
// f #x list of linear coefficients
|
|
// A #A by #x matrix of linear inequality constraint coefficients
|
|
// b #A list of linear constraint right-hand sides
|
|
// B #B by #x matrix of linear equality constraint coefficients
|
|
// c #B list of linear constraint right-hand sides
|
|
// Outputs:
|
|
// x #x solution vector
|
|
//
|
|
IGL_INLINE bool linprog(
|
|
const Eigen::VectorXd & f,
|
|
const Eigen::MatrixXd & A,
|
|
const Eigen::VectorXd & b,
|
|
const Eigen::MatrixXd & B,
|
|
const Eigen::VectorXd & c,
|
|
Eigen::VectorXd & x);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "linprog.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_list_to_matrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LIST_TO_MATRIX_H
|
|
#define IGL_LIST_TO_MATRIX_H
|
|
#include "igl_inline.h"
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Convert a list (std::vector) of row vectors of the same length to a matrix
|
|
// Template:
|
|
// T type that can be safely cast to type in Mat via '='
|
|
// Mat Matrix type, must implement:
|
|
// .resize(m,n)
|
|
// .row(i) = Row
|
|
// Inputs:
|
|
// V a m-long list of vectors of size n
|
|
// Outputs:
|
|
// M an m by n matrix
|
|
// Returns true on success, false on errors
|
|
template <typename T, class Mat>
|
|
IGL_INLINE bool list_to_matrix(
|
|
const std::vector<std::vector<T > > & V,
|
|
Mat & M);
|
|
// Convert a list of row vectors of `n` or less to a matrix and pad on
|
|
// the right with `padding`:
|
|
//
|
|
// Inputs:
|
|
// V a m-long list of vectors of size <=n
|
|
// n number of columns
|
|
// padding value to fill in from right for short rows
|
|
// Outputs:
|
|
// M an m by n matrix
|
|
template <typename T, class Mat>
|
|
IGL_INLINE bool list_to_matrix(
|
|
const std::vector<std::vector<T > > & V,
|
|
const int n,
|
|
const T & padding,
|
|
Mat & M);
|
|
// Vector wrapper
|
|
template <typename T, class Mat>
|
|
IGL_INLINE bool list_to_matrix(const std::vector<T > & V,Mat & M);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "list_to_matrix.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_local_basis = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LOCALBASIS_H
|
|
#define IGL_LOCALBASIS_H
|
|
|
|
#include "igl/igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Compute a local orthogonal reference system for each triangle in the given mesh
|
|
// Templates:
|
|
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
|
|
// DerivedF derived from face indices matrix type: i.e. MatrixXi
|
|
// Inputs:
|
|
// V eigen matrix #V by 3
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// Outputs:
|
|
// B1 eigen matrix #F by 3, each vector is tangent to the triangle
|
|
// B2 eigen matrix #F by 3, each vector is tangent to the triangle and perpendicular to B1
|
|
// B3 eigen matrix #F by 3, normal of the triangle
|
|
//
|
|
// See also: adjacency_matrix
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void local_basis(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedV>& B1,
|
|
Eigen::PlainObjectBase<DerivedV>& B2,
|
|
Eigen::PlainObjectBase<DerivedV>& B3
|
|
);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "local_basis.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_look_at = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LOOK_AT_H
|
|
#define IGL_LOOK_AT_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Implementation of the deprecated gluLookAt function.
|
|
//
|
|
// Inputs:
|
|
// eye 3-vector of eye position
|
|
// center 3-vector of center reference point
|
|
// up 3-vector of up vector
|
|
// Outputs:
|
|
// R 4x4 rotation matrix
|
|
//
|
|
template <
|
|
typename Derivedeye,
|
|
typename Derivedcenter,
|
|
typename Derivedup,
|
|
typename DerivedR >
|
|
IGL_INLINE void look_at(
|
|
const Eigen::PlainObjectBase<Derivedeye> & eye,
|
|
const Eigen::PlainObjectBase<Derivedcenter> & center,
|
|
const Eigen::PlainObjectBase<Derivedup> & up,
|
|
Eigen::PlainObjectBase<DerivedR> & R);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "look_at.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_lscm = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LSCM_H
|
|
#define IGL_LSCM_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Compute a Least-squares conformal map parametrization following the
|
|
// algorithm presented in: Spectral Conformal Parameterization, Patrick
|
|
// Mullen, Yiying Tong, Pierre Alliez and Mathieu Desbrun. Input should be a
|
|
// manifold mesh (also no unreferenced vertices) and "boundary" `b` should
|
|
// contain at least two vertices per connected component.
|
|
//
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex positions
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// b #b boundary indices into V
|
|
// bc #b by 3 list of boundary values
|
|
// Outputs:
|
|
// UV #V by 2 list of 2D mesh vertex positions in UV space
|
|
// Returns true only on solver success.
|
|
//
|
|
IGL_INLINE bool lscm(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::MatrixXd& bc,
|
|
Eigen::MatrixXd& V_uv);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "lscm.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_lu_lagrange = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LU_LAGRANGE_H
|
|
#define IGL_LU_LAGRANGE_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// KNOWN BUGS: This does not seem to be correct for non-empty C
|
|
//
|
|
// LU_LAGRANGE Compute a LU decomposition for a special type of
|
|
// matrix Q that is symmetric but not positive-definite:
|
|
// Q = [A'*A C
|
|
// C' 0];
|
|
// where A'*A, or ATA, is given as a symmetric positive definite matrix and C
|
|
// has full column-rank(?)
|
|
//
|
|
// [J] = lu_lagrange(ATA,C)
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// ATA n by n square, symmetric, positive-definite system matrix, usually
|
|
// the quadratic coefficients corresponding to the original unknowns in a
|
|
// system
|
|
// C n by m rectangular matrix corresponding the quadratic coefficients of
|
|
// the original unknowns times the lagrange multipliers enforcing linear
|
|
// equality constraints
|
|
// Outputs:
|
|
// L lower triangular matrix such that Q = L*U
|
|
// U upper triangular matrix such that Q = L*U
|
|
// Returns true on success, false on error
|
|
//
|
|
// Note: C should *not* have any empty columns. Typically C is the slice of
|
|
// the linear constraints matrix Aeq concerning the unknown variables of a
|
|
// quadratic optimization. Generally constraints may deal with unknowns as
|
|
// well as knowns. Each linear constraint corresponds to a column of Aeq. As
|
|
// long as each constraint concerns at least one unknown then the
|
|
// corresponding column in C will have at least one non zero entry. If a
|
|
// constraint concerns *no* unknowns, you should double check that this is a
|
|
// valid constraint. How can you constrain known values to each other? This
|
|
// is either a contradiction to the knowns' values or redundent. In either
|
|
// case, it's not this functions responsiblilty to handle empty constraints
|
|
// so you will get an error.
|
|
//
|
|
template <typename T>
|
|
IGL_INLINE bool lu_lagrange(
|
|
const Eigen::SparseMatrix<T> & ATA,
|
|
const Eigen::SparseMatrix<T> & C,
|
|
Eigen::SparseMatrix<T> & L,
|
|
Eigen::SparseMatrix<T> & U);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "lu_lagrange.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_map_vertices_to_circle = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MAP_VERTICES_TO_CIRCLE_H
|
|
#define IGL_MAP_VERTICES_TO_CIRCLE_H
|
|
#include <igl/igl_inline.h>
|
|
|
|
#include <Eigen/Dense>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
|
|
// Map the vertices whose indices are in a given boundary loop (bnd) on the
|
|
// unit circle with spacing proportional to the original boundary edge
|
|
// lengths.
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// b #W list of vertex ids
|
|
// Outputs:
|
|
// UV #W by 2 list of 2D position on the unit circle for the vertices in b
|
|
IGL_INLINE void map_vertices_to_circle(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::VectorXi& bnd,
|
|
Eigen::MatrixXd& UV);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "map_vertices_to_circle.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_marching_cubes = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MARCHINGCUBES_H
|
|
#define IGL_MARCHINGCUBES_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// marching_cubes( values, points, x_res, y_res, z_res, vertices, faces )
|
|
//
|
|
// performs marching cubes reconstruction on the grid defined by values, and
|
|
// points, and generates vertices and faces
|
|
//
|
|
// Input:
|
|
// xres, yres, zres resolutions of the grid in x,y,z dimensions
|
|
// values #number_of_grid_points x 1 array -- the scalar values of an
|
|
// implicit function defined on the grid points (<0 in the inside of the
|
|
// surface, 0 on the border, >0 outside)
|
|
// points #number_of_grid_points x 3 array -- 3-D positions of the grid
|
|
// points, ordered in x,y,z order:
|
|
// points[index] = the point at (x,y,z) where :
|
|
// x = (index % (xres -1),
|
|
// y = (index / (xres-1)) %(yres-1),
|
|
// z = index / (xres -1) / (yres -1) ).
|
|
// where x,y,z index x, y, z dimensions
|
|
// i.e. index = x + y*xres + z*xres*yres
|
|
// Output:
|
|
// vertices #V by 3 list of mesh vertex positions
|
|
// faces #F by 3 list of mesh triangle indices
|
|
//
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void marching_cubes(
|
|
const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &values,
|
|
const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> &points,
|
|
const unsigned x_res,
|
|
const unsigned y_res,
|
|
const unsigned z_res,
|
|
Eigen::PlainObjectBase<DerivedV> &vertices,
|
|
Eigen::PlainObjectBase<DerivedF> &faces);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "marching_cubes.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_massmatrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MASSMATRIX_TYPE_H
|
|
#define IGL_MASSMATRIX_TYPE_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
|
|
enum MassMatrixType
|
|
{
|
|
MASSMATRIX_TYPE_BARYCENTRIC = 0,
|
|
MASSMATRIX_TYPE_VORONOI = 1,
|
|
MASSMATRIX_TYPE_FULL = 2,
|
|
MASSMATRIX_TYPE_DEFAULT = 3,
|
|
NUM_MASSMATRIX_TYPE = 4
|
|
};
|
|
|
|
// Constructs the mass (area) matrix for a given mesh (V,F).
|
|
//
|
|
// Templates:
|
|
// DerivedV derived type of eigen matrix for V (e.g. derived from
|
|
// MatrixXd)
|
|
// DerivedF derived type of eigen matrix for F (e.g. derived from
|
|
// MatrixXi)
|
|
// Scalar scalar type for eigen sparse matrix (e.g. double)
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by simplex_size list of mesh faces (must be triangles)
|
|
// type one of the following ints:
|
|
// MASSMATRIX_TYPE_BARYCENTRIC barycentric
|
|
// MASSMATRIX_TYPE_VORONOI voronoi-hybrid {default}
|
|
// MASSMATRIX_TYPE_FULL full {not implemented}
|
|
// Outputs:
|
|
// M #V by #V mass matrix
|
|
//
|
|
// See also: adjacency_matrix
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename Scalar>
|
|
IGL_INLINE void massmatrix(
|
|
const Eigen::MatrixBase<DerivedV> & V,
|
|
const Eigen::MatrixBase<DerivedF> & F,
|
|
const MassMatrixType type,
|
|
Eigen::SparseMatrix<Scalar>& M);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "massmatrix.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mat_max = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MAT_MAX_H
|
|
#define IGL_MAT_MAX_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Ideally this becomes a super overloaded function supporting everything
|
|
// that matlab's max supports
|
|
|
|
// Max function for matrices to act like matlab's max function. Specifically
|
|
// like [Y,I] = max(X,[],dim);
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// X m by n matrix
|
|
// dim dimension along which to take max
|
|
// Outputs:
|
|
// Y n-long vector (if dim == 1)
|
|
// or
|
|
// Y m-long vector (if dim == 2)
|
|
// I vector the same size as Y containing the indices along dim of maximum
|
|
// entries
|
|
template <typename T>
|
|
IGL_INLINE void mat_max(
|
|
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
|
|
const int dim,
|
|
Eigen::Matrix<T,Eigen::Dynamic,1> & Y,
|
|
Eigen::Matrix<int,Eigen::Dynamic,1> & I);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mat_max.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mat_min = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MAT_MIN_H
|
|
#define IGL_MAT_MIN_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Ideally this becomes a super overloaded function supporting everything
|
|
// that matlab's min supports
|
|
|
|
// Min function for matrices to act like matlab's min function. Specifically
|
|
// like [Y,I] = min(X,[],dim);
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// X m by n matrix
|
|
// dim dimension along which to take min
|
|
// Outputs:
|
|
// Y n-long sparse vector (if dim == 1)
|
|
// or
|
|
// Y m-long sparse vector (if dim == 2)
|
|
// I vector the same size as Y containing the indices along dim of minimum
|
|
// entries
|
|
//
|
|
// See also: mat_max
|
|
template <typename T>
|
|
IGL_INLINE void mat_min(
|
|
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
|
|
const int dim,
|
|
Eigen::Matrix<T,Eigen::Dynamic,1> & Y,
|
|
Eigen::Matrix<int,Eigen::Dynamic,1> & I);
|
|
// Use Y = X.colwise().minCoeff() instead
|
|
//// In-line wrapper
|
|
//template <typename T>
|
|
//IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> mat_min(
|
|
// const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
|
|
// const int dim);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mat_min.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mat_to_quat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MAT_TO_QUAT_H
|
|
#define IGL_MAT_TO_QUAT_H
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Convert a OpenGL (rotation) matrix to a quaternion
|
|
//
|
|
// Input:
|
|
// m 16-element opengl rotation matrix
|
|
// Output:
|
|
// q 4-element quaternion (not normalized)
|
|
template <typename Q_type>
|
|
IGL_INLINE void mat4_to_quat(const Q_type * m, Q_type * q);
|
|
// Input:
|
|
// m 9-element opengl rotation matrix
|
|
template <typename Q_type>
|
|
IGL_INLINE void mat3_to_quat(const Q_type * m, Q_type * q);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mat_to_quat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_material_colors = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATERIAL_COLORS_H
|
|
#define IGL_MATERIAL_COLORS_H
|
|
#include <Eigen/Core>
|
|
// Define constant material colors for use with opengl glMaterialfv
|
|
// Most of these colors come from IGL publications
|
|
namespace igl
|
|
{
|
|
// Gold/Silver used in BBW/MONO/STBS/FAST
|
|
const float GOLD_AMBIENT[4] = { 51.0/255.0, 43.0/255.0,33.3/255.0,1.0f };
|
|
const float GOLD_DIFFUSE[4] = { 255.0/255.0,228.0/255.0,58.0/255.0,1.0f };
|
|
const float GOLD_SPECULAR[4] = { 255.0/255.0,235.0/255.0,80.0/255.0,1.0f };
|
|
const float SILVER_AMBIENT[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
|
|
const float SILVER_DIFFUSE[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
const float SILVER_SPECULAR[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
// Blue/Cyan more similar to Jovan Popovic's blue than to Mario Botsch's blue
|
|
const float CYAN_AMBIENT[4] = { 59.0/255.0, 68.0/255.0,255.0/255.0,1.0f };
|
|
const float CYAN_DIFFUSE[4] = { 94.0/255.0,185.0/255.0,238.0/255.0,1.0f };
|
|
const float CYAN_SPECULAR[4] = { 163.0/255.0,221.0/255.0,255.0/255.0,1.0f };
|
|
const float DENIS_PURPLE_DIFFUSE[4] = { 80.0/255.0,64.0/255.0,255.0/255.0,1.0f };
|
|
const float LADISLAV_ORANGE_DIFFUSE[4] = {1.0f, 125.0f / 255.0f, 19.0f / 255.0f, 0.0f};
|
|
// FAST armadillos colors
|
|
const float FAST_GREEN_DIFFUSE[4] = { 113.0f/255.0f, 239.0f/255.0f, 46.0f/255.0f, 1.0f};
|
|
const float FAST_RED_DIFFUSE[4] = { 255.0f/255.0f, 65.0f/255.0f, 46.0f/255.0f, 1.0f};
|
|
const float FAST_BLUE_DIFFUSE[4] = { 106.0f/255.0f, 106.0f/255.0f, 255.0f/255.0f, 1.0f};
|
|
const float FAST_GRAY_DIFFUSE[4] = { 150.0f/255.0f, 150.0f/255.0f, 150.0f/255.0f, 1.0f};
|
|
// Basic colors
|
|
const float WHITE[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
|
|
const float BLACK[4] = { 0.0/255.0,0.0/255.0,0.0/255.0,1.0f };
|
|
const float WHITE_AMBIENT[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
|
|
const float WHITE_DIFFUSE[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
|
|
const float WHITE_SPECULAR[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
|
|
const float BBW_POINT_COLOR[4] = {239./255.,213./255.,46./255.,255.0/255.0};
|
|
const float BBW_LINE_COLOR[4] = {106./255.,106./255.,255./255.,255./255.};
|
|
const float MIDNIGHT_BLUE_DIFFUSE[4] = { 21.0f/255.0f, 27.0f/255.0f, 84.0f/255.0f, 1.0f};
|
|
// Winding number colors
|
|
const float EASTER_RED_DIFFUSE[4] = {0.603922,0.494118f,0.603922f,1.0f};
|
|
const float WN_OPEN_BOUNDARY_COLOR[4] = {154./255.,0./255.,0./255.,1.0f};
|
|
const float WN_NON_MANIFOLD_EDGE_COLOR[4] = {201./255., 51./255.,255./255.,1.0f};
|
|
const Eigen::Vector4f
|
|
MAYA_GREEN(128./255.,242./255.,0./255.,1.),
|
|
MAYA_YELLOW(255./255.,247./255.,50./255.,1.),
|
|
MAYA_RED(234./255.,63./255.,52./255.,1.),
|
|
MAYA_BLUE(0./255.,73./255.,252./255.,1.),
|
|
MAYA_PURPLE(180./255.,73./255.,200./255.,1.),
|
|
MAYA_VIOLET(31./255.,15./255.,66./255.,1.),
|
|
MAYA_GREY(0.5,0.5,0.5,1.0),
|
|
MAYA_CYAN(131./255.,219./255.,252./255.,1.),
|
|
MAYA_SEA_GREEN(70./255.,252./255.,167./255.,1.);
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matlab_format = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATLAB_FORMAT_H
|
|
#define IGL_MATLAB_FORMAT_H
|
|
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// This is a routine to print a matrix using format suitable for pasting into
|
|
// the matlab IDE
|
|
//
|
|
// Templates:
|
|
// DerivedM e.g. derived from MatrixXd
|
|
// Input:
|
|
// input some matrix to be formated
|
|
// name name of matrix
|
|
// Returns Formated matrix
|
|
//
|
|
// Example:
|
|
// // M := [1 2 3;4 5 6];
|
|
// cout<<matlab_format(M)<<endl;
|
|
// // Prints:
|
|
// // [
|
|
// // 1 2 3
|
|
// // 4 5 6
|
|
// // ];
|
|
// cout<<matlab_format(M,"M")<<endl;
|
|
// // Prints:
|
|
// // M = [
|
|
// // 1 2 3
|
|
// // 4 5 6
|
|
// // ];
|
|
template <typename DerivedM>
|
|
IGL_INLINE const Eigen::WithFormat< DerivedM > matlab_format(
|
|
const Eigen::PlainObjectBase<DerivedM> & M,
|
|
const std::string name = "");
|
|
// Same but for sparse matrices. Print IJV format into an auxillary variable
|
|
// and then print a call to sparse which will construct the sparse matrix
|
|
// Example:
|
|
// // S := [0 2 3;4 5 0];
|
|
// cout<<matlab_format(S,"S")<<endl;
|
|
// // Prints:
|
|
// // SIJV = [
|
|
// // 2 1 4
|
|
// // 1 2 2
|
|
// // 2 2 5
|
|
// // 1 3 3
|
|
// // ];
|
|
// // S = sparse(SIJV(:,1),SIJV(:,2),SIJV(:,3));
|
|
//
|
|
template <typename DerivedS>
|
|
IGL_INLINE const std::string matlab_format(
|
|
const Eigen::SparseMatrix<DerivedS> & S,
|
|
const std::string name = "");
|
|
// Return just IOFormat
|
|
//
|
|
// Example:
|
|
// // M := [1 2 3;4 5 6];
|
|
// cout<<M.format(matlab_format())<<endl;
|
|
// // Prints:
|
|
// // [
|
|
// // 1 2 3
|
|
// // 4 5 6
|
|
// // ];
|
|
IGL_INLINE Eigen::IOFormat matlab_format();
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "matlab_format.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matrix_to_list = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATRIX_TO_LIST_H
|
|
#define IGL_MATRIX_TO_LIST_H
|
|
#include "igl_inline.h"
|
|
#include <vector>
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Convert a matrix to a list (std::vector) of row vectors of the same size
|
|
// Template:
|
|
// Mat Matrix type, must implement:
|
|
// .resize(m,n)
|
|
// .row(i) = Row
|
|
// T type that can be safely cast to type in Mat via '='
|
|
// Inputs:
|
|
// V a m-long list of vectors of size n
|
|
// Outputs:
|
|
// M an m by n matrix
|
|
//
|
|
// See also: list_to_matrix
|
|
template <typename DerivedM>
|
|
IGL_INLINE void matrix_to_list(
|
|
const Eigen::MatrixBase<DerivedM> & M,
|
|
std::vector<std::vector<typename DerivedM::Scalar > > & V);
|
|
// For vector input
|
|
template <typename DerivedM>
|
|
IGL_INLINE void matrix_to_list(
|
|
const Eigen::MatrixBase<DerivedM> & M,
|
|
std::vector<typename DerivedM::Scalar > & V);
|
|
// Return wrapper
|
|
template <typename DerivedM>
|
|
IGL_INLINE std::vector<typename DerivedM::Scalar > matrix_to_list(
|
|
const Eigen::MatrixBase<DerivedM> & M);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "matrix_to_list.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_max_size = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MAX_SIZE_H
|
|
#define IGL_MAX_SIZE_H
|
|
#include "igl_inline.h"
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Determine max size of lists in a vector
|
|
// Template:
|
|
// T some list type object that implements .size()
|
|
// Inputs:
|
|
// V vector of list types T
|
|
// Returns max .size() found in V, returns -1 if V is empty
|
|
template <typename T>
|
|
IGL_INLINE int max_size(const std::vector<T> & V);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "max_size.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_median = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MEDIAN_H
|
|
#define IGL_MEDIAN_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Compute the median of an eigen vector
|
|
//
|
|
// Inputs:
|
|
// V #V list of unsorted values
|
|
// Outputs:
|
|
// m median of those values
|
|
// Returns true on success, false on failure
|
|
IGL_INLINE bool median(const Eigen::VectorXd & V, double & m);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "median.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_min_quad_dense = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MIN_QUAD_DENSE_H
|
|
#define IGL_MIN_QUAD_DENSE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
//// debug
|
|
//#include <matlabinterface.h>
|
|
//Engine *g_pEngine;
|
|
|
|
|
|
namespace igl
|
|
{
|
|
// MIN_QUAD_WITH_FIXED Minimize quadratic energy Z'*A*Z + Z'*B + C
|
|
// subject to linear constraints Aeq*Z = Beq
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like float or double
|
|
// Inputs:
|
|
// A n by n matrix of quadratic coefficients
|
|
// B n by 1 column of linear coefficients
|
|
// Aeq m by n list of linear equality constraint coefficients
|
|
// Beq m by 1 list of linear equality constraint constant values
|
|
// use_lu_decomposition use lu rather than SVD
|
|
// Outputs:
|
|
// S n by (n + m) "solve" matrix, such that S*[B', Beq'] is a solution
|
|
// Returns true on success, false on error
|
|
template <typename T>
|
|
IGL_INLINE void min_quad_dense_precompute(
|
|
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& A,
|
|
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& Aeq,
|
|
const bool use_lu_decomposition,
|
|
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& S);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "min_quad_dense.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_min_quad_with_fixed = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MIN_QUAD_WITH_FIXED_H
|
|
#define IGL_MIN_QUAD_WITH_FIXED_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
// Bug in unsupported/Eigen/SparseExtra needs iostream first
|
|
#include <iostream>
|
|
#include <unsupported/Eigen/SparseExtra>
|
|
|
|
namespace igl
|
|
{
|
|
template <typename T>
|
|
struct min_quad_with_fixed_data;
|
|
// Known Bugs: rows of Aeq **should probably** be linearly independent.
|
|
// During precomputation, the rows of a Aeq are checked via QR. But in case
|
|
// they're not then resulting probably will no longer be sparse: it will be
|
|
// slow.
|
|
//
|
|
// MIN_QUAD_WITH_FIXED Minimize quadratic energy
|
|
//
|
|
// 0.5*Z'*A*Z + Z'*B + C with
|
|
//
|
|
// constraints that Z(known) = Y, optionally also subject to the constraints
|
|
// Aeq*Z = Beq
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// A n by n matrix of quadratic coefficients
|
|
// known list of indices to known rows in Z
|
|
// Y list of fixed values corresponding to known rows in Z
|
|
// Aeq m by n list of linear equality constraint coefficients
|
|
// pd flag specifying whether A(unknown,unknown) is positive definite
|
|
// Outputs:
|
|
// data factorization struct with all necessary information to solve
|
|
// using min_quad_with_fixed_solve
|
|
// Returns true on success, false on error
|
|
//
|
|
// Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
|
|
// secs, igl/min_quad_with_fixed.h 7.1 secs
|
|
//
|
|
template <typename T, typename Derivedknown>
|
|
IGL_INLINE bool min_quad_with_fixed_precompute(
|
|
const Eigen::SparseMatrix<T>& A,
|
|
const Eigen::PlainObjectBase<Derivedknown> & known,
|
|
const Eigen::SparseMatrix<T>& Aeq,
|
|
const bool pd,
|
|
min_quad_with_fixed_data<T> & data
|
|
);
|
|
|
|
// Solves a system previously factored using min_quad_with_fixed_precompute
|
|
//
|
|
// Template:
|
|
// T type of sparse matrix (e.g. double)
|
|
// DerivedY type of Y (e.g. derived from VectorXd or MatrixXd)
|
|
// DerivedZ type of Z (e.g. derived from VectorXd or MatrixXd)
|
|
// Inputs:
|
|
// data factorization struct with all necessary precomputation to solve
|
|
// B n by 1 column of linear coefficients
|
|
// Y b by 1 list of constant fixed values
|
|
// Beq m by 1 list of linear equality constraint constant values
|
|
// Outputs:
|
|
// Z n by cols solution
|
|
// sol #unknowns+#lagrange by cols solution to linear system
|
|
// Returns true on success, false on error
|
|
template <
|
|
typename T,
|
|
typename DerivedB,
|
|
typename DerivedY,
|
|
typename DerivedBeq,
|
|
typename DerivedZ,
|
|
typename Derivedsol>
|
|
IGL_INLINE bool min_quad_with_fixed_solve(
|
|
const min_quad_with_fixed_data<T> & data,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<DerivedY> & Y,
|
|
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
|
|
Eigen::PlainObjectBase<DerivedZ> & Z,
|
|
Eigen::PlainObjectBase<Derivedsol> & sol);
|
|
// Wrapper without sol
|
|
template <
|
|
typename T,
|
|
typename DerivedB,
|
|
typename DerivedY,
|
|
typename DerivedBeq,
|
|
typename DerivedZ>
|
|
IGL_INLINE bool min_quad_with_fixed_solve(
|
|
const min_quad_with_fixed_data<T> & data,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<DerivedY> & Y,
|
|
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
|
|
Eigen::PlainObjectBase<DerivedZ> & Z);
|
|
template <
|
|
typename T,
|
|
typename Derivedknown,
|
|
typename DerivedB,
|
|
typename DerivedY,
|
|
typename DerivedBeq,
|
|
typename DerivedZ>
|
|
IGL_INLINE bool min_quad_with_fixed(
|
|
const Eigen::SparseMatrix<T>& A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<Derivedknown> & known,
|
|
const Eigen::PlainObjectBase<DerivedY> & Y,
|
|
const Eigen::SparseMatrix<T>& Aeq,
|
|
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
|
|
const bool pd,
|
|
Eigen::PlainObjectBase<DerivedZ> & Z);
|
|
}
|
|
|
|
template <typename T>
|
|
struct igl::min_quad_with_fixed_data
|
|
{
|
|
// Size of original system: number of unknowns + number of knowns
|
|
int n;
|
|
// Whether A(unknown,unknown) is positive definite
|
|
bool Auu_pd;
|
|
// Whether A(unknown,unknown) is symmetric
|
|
bool Auu_sym;
|
|
// Indices of known variables
|
|
Eigen::VectorXi known;
|
|
// Indices of unknown variables
|
|
Eigen::VectorXi unknown;
|
|
// Indices of lagrange variables
|
|
Eigen::VectorXi lagrange;
|
|
// Indices of unknown variable followed by Indices of lagrange variables
|
|
Eigen::VectorXi unknown_lagrange;
|
|
// Matrix multiplied against Y when constructing right hand side
|
|
Eigen::SparseMatrix<T> preY;
|
|
enum SolverType
|
|
{
|
|
LLT = 0,
|
|
LDLT = 1,
|
|
LU = 2,
|
|
QR_LLT = 3,
|
|
NUM_SOLVER_TYPES = 4
|
|
} solver_type;
|
|
// Solvers
|
|
Eigen::SimplicialLLT <Eigen::SparseMatrix<T > > llt;
|
|
Eigen::SimplicialLDLT<Eigen::SparseMatrix<T > > ldlt;
|
|
Eigen::SparseLU<Eigen::SparseMatrix<T, Eigen::ColMajor>, Eigen::COLAMDOrdering<int> > lu;
|
|
// QR factorization
|
|
// Are rows of Aeq linearly independent?
|
|
bool Aeq_li;
|
|
// Columns of Aeq corresponding to unknowns
|
|
int neq;
|
|
Eigen::SparseQR<Eigen::SparseMatrix<T>, Eigen::COLAMDOrdering<int> > AeqTQR;
|
|
Eigen::SparseMatrix<T> Aeqk;
|
|
Eigen::SparseMatrix<T> Aequ;
|
|
Eigen::SparseMatrix<T> Auu;
|
|
Eigen::SparseMatrix<T> AeqTQ1;
|
|
Eigen::SparseMatrix<T> AeqTQ1T;
|
|
Eigen::SparseMatrix<T> AeqTQ2;
|
|
Eigen::SparseMatrix<T> AeqTQ2T;
|
|
Eigen::SparseMatrix<T> AeqTR1;
|
|
Eigen::SparseMatrix<T> AeqTR1T;
|
|
Eigen::SparseMatrix<T> AeqTE;
|
|
Eigen::SparseMatrix<T> AeqTET;
|
|
// Debug
|
|
Eigen::SparseMatrix<T> NA;
|
|
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> NB;
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "min_quad_with_fixed.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_min_size = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MIN_SIZE_H
|
|
#define IGL_MIN_SIZE_H
|
|
#include "igl_inline.h"
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Determine min size of lists in a vector
|
|
// Template:
|
|
// T some list type object that implements .size()
|
|
// Inputs:
|
|
// V vector of list types T
|
|
// Returns min .size() found in V, returns -1 if V is empty
|
|
template <typename T>
|
|
IGL_INLINE int min_size(const std::vector<T> & V);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "min_size.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mod = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MOD_H
|
|
#define IGL_MOD_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute elementwise mod: B = A % base
|
|
//
|
|
// Inputs:
|
|
// A m by n matrix
|
|
// base number to mod against
|
|
// Outputs:
|
|
// B m by n matrix
|
|
template <typename DerivedA, typename DerivedB>
|
|
IGL_INLINE void mod(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const int base,
|
|
Eigen::PlainObjectBase<DerivedB> & B);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "mod.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mode = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MODE_H
|
|
#define IGL_MODE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Takes mode of coefficients in a matrix along a given dension
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// X m by n original matrix
|
|
// d dension along which to take mode, m or n
|
|
// Outputs:
|
|
// M vector containing mode along dension d, if d==1 then this will be a
|
|
// n-long vector if d==2 then this will be a m-long vector
|
|
template <typename T>
|
|
IGL_INLINE void mode(
|
|
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
|
|
const int d,
|
|
Eigen::Matrix<T,Eigen::Dynamic,1> & M);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mode.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mvc = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MVC_H
|
|
#define IGL_MVC_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// MVC - MEAN VALUE COORDINATES
|
|
//
|
|
// mvc(V,C,W)
|
|
//
|
|
// Inputs:
|
|
// V #V x dim list of vertex positions (dim = 2 or dim = 3)
|
|
// C #C x dim list of polygon vertex positions in counter-clockwise order
|
|
// (dim = 2 or dim = 3)
|
|
//
|
|
// Outputs:
|
|
// W weights, #V by #C matrix of weights
|
|
//
|
|
// Known Bugs: implementation is listed as "Broken"
|
|
IGL_INLINE void mvc(
|
|
const Eigen::MatrixXd &V,
|
|
const Eigen::MatrixXd &C,
|
|
Eigen::MatrixXd &W);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mvc.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_n_polyvector = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_N_POLYVECTOR
|
|
#define IGL_N_POLYVECTOR
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
//todo
|
|
/// Given 2 vectors centered on origin calculate the rotation matrix from first to the second
|
|
|
|
// Inputs:
|
|
// v0, v1 the two #3 by 1 vectors
|
|
// normalized boolean, if false, then the vectors are normalized prior to the calculation
|
|
// Output:
|
|
// 3 by 3 rotation matrix that takes v0 to v1
|
|
//
|
|
|
|
IGL_INLINE void n_polyvector(const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::MatrixXd& bc,
|
|
Eigen::MatrixXd &output);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "n_polyvector.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_N_POLYVECTOR) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_n_polyvector_general = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_N_POLYVECTOR_GENERAL
|
|
#define IGL_N_POLYVECTOR_GENERAL
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl {
|
|
//todo
|
|
/// Given 2 vectors centered on origin calculate the rotation matrix from first to the second
|
|
|
|
// Inputs:
|
|
// v0, v1 the two #3 by 1 vectors
|
|
// normalized boolean, if false, then the vectors are normalized prior to the calculation
|
|
// Output:
|
|
// 3 by 3 rotation matrix that takes v0 to v1
|
|
//
|
|
|
|
IGL_INLINE void n_polyvector_general(const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::MatrixXd& bc,
|
|
const Eigen::VectorXi &I,
|
|
Eigen::MatrixXd &output);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "n_polyvector_general.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_N_POLYVECTOR) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_nchoosek = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti, Alec Jacobson
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_NCHOOSEK
|
|
#define IGL_NCHOOSEK
|
|
#include "igl_inline.h"
|
|
#include "deprecated.h"
|
|
#include <vector>
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// NCHOOSEK Like matlab's nchoosek.
|
|
//
|
|
// Inputs:
|
|
// n total number elements
|
|
// k size of sub-set to consider
|
|
// Returns number of k-size combinations out of the set [1,...,n]
|
|
IGL_INLINE double nchoosek(const int n, const int k);
|
|
//
|
|
// Inputs:
|
|
// V n-long vector of elements
|
|
// k size of sub-set to consider
|
|
// Outputs:
|
|
// U nchoosek by k long matrix where each row is a unique k-size
|
|
// combination
|
|
template < typename DerivedV, typename DerivedU>
|
|
IGL_INLINE void nchoosek(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const int k,
|
|
Eigen::PlainObjectBase<DerivedU> & U);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "nchoosek.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_NCHOOSEK) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_next_filename = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_NEXT_FILENAME_H
|
|
#define IGL_NEXT_FILENAME_H
|
|
#include "igl_inline.h"
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
// Find the file with the first filename of the form
|
|
// "prefix-%0[zeros]dsuffix"
|
|
//
|
|
// Inputs:
|
|
// prefix path to containing dir and filename prefix
|
|
// zeros number of leading zeros as if digit printed with printf
|
|
// suffix suffix of filename and extension
|
|
// Outputs:
|
|
// next path to next file
|
|
// Returns true if found, false if exceeding range in zeros
|
|
IGL_INLINE bool next_filename(
|
|
const std::string & prefix,
|
|
const int zeros,
|
|
const std::string & suffix,
|
|
std::string & next);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "next_filename.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_normal_derivative = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_NORMAL_DERIVATIVE_H
|
|
#define IGL_NORMAL_DERIVATIVE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// NORMAL_DERIVATIVE Computes the directional derivative **normal** to
|
|
// **all** (half-)edges of a triangle mesh (not just boundary edges). These
|
|
// are integrated along the edge: they're the per-face constant gradient dot
|
|
// the rotated edge vector (unit rotated edge vector for direction then
|
|
// magnitude for integration).
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by 3|4 list of triangle|tetrahedron indices into V
|
|
// Outputs:
|
|
// DD #F*3|4 by #V sparse matrix representing operator to compute
|
|
// directional derivative with respect to each facet of each element.
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedEle,
|
|
typename Scalar>
|
|
IGL_INLINE void normal_derivative(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedEle> & Ele,
|
|
Eigen::SparseMatrix<Scalar>& DD);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "normal_derivative.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_normalize_quat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_NORMALIZE_QUAT_H
|
|
#define IGL_NORMALIZE_QUAT_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Normalize a quaternion
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
// Inputs:
|
|
// q input quaternion
|
|
// Outputs:
|
|
// out result of normalization, allowed to be same as q
|
|
// Returns true on success, false if len(q) < EPS
|
|
template <typename Q_type>
|
|
IGL_INLINE bool normalize_quat(
|
|
const Q_type *q,
|
|
Q_type *out);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "normalize_quat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_normalize_row_lengths = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_NORMALIZE_ROW_LENGTHS_H
|
|
#define IGL_NORMALIZE_ROW_LENGTHS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
// History:
|
|
// March 24, 2012: Alec changed function name from normalize_rows to
|
|
// normalize_row_lengths to avoid confusion with normalize_row_sums
|
|
|
|
namespace igl
|
|
{
|
|
// Obsolete: just use A.rowwise().normalize() or B=A.rowwise().normalized();
|
|
//
|
|
// Normalize the rows in A so that their lengths are each 1 and place the new
|
|
// entries in B
|
|
// Inputs:
|
|
// A #rows by k input matrix
|
|
// Outputs:
|
|
// B #rows by k input matrix, can be the same as A
|
|
template <typename DerivedV>
|
|
IGL_INLINE void normalize_row_lengths(
|
|
const Eigen::PlainObjectBase<DerivedV>& A,
|
|
Eigen::PlainObjectBase<DerivedV> & B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "normalize_row_lengths.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_normalize_row_sums = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_NORMALIZE_ROW_SUMS_H
|
|
#define IGL_NORMALIZE_ROW_SUMS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Normalize the rows in A so that their sums are each 1 and place the new
|
|
// entries in B
|
|
// Inputs:
|
|
// A #rows by k input matrix
|
|
// Outputs:
|
|
// B #rows by k input matrix, can be the same as A
|
|
//
|
|
// Note: This is just calling an Eigen one-liner.
|
|
template <typename DerivedA, typename DerivedB>
|
|
IGL_INLINE void normalize_row_sums(
|
|
const Eigen::MatrixBase<DerivedA>& A,
|
|
Eigen::MatrixBase<DerivedB> & B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "normalize_row_sums.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_NormalType = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_NORMALTYPE_H
|
|
#define IGL_NORMALTYPE_H
|
|
|
|
namespace igl
|
|
{
|
|
enum NormalType
|
|
{
|
|
PER_VERTEX_NORMALS,
|
|
PER_FACE_NORMALS,
|
|
PER_CORNER_NORMALS
|
|
};
|
|
# define NUM_NORMAL_TYPE 3
|
|
}
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_null = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_NULL_H
|
|
#define IGL_NULL_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Like MATLAB's null
|
|
//
|
|
// Compute a basis for the null space for the given matrix A: the columns of
|
|
// the output N form a basis for the space orthogonal to that spanned by the
|
|
// rows of A.
|
|
//
|
|
// Inputs:
|
|
// A m by n matrix
|
|
// Outputs:
|
|
// N n by r matrix, where r is the row rank of A
|
|
template <typename DerivedA, typename DerivedN>
|
|
IGL_INLINE void null(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
Eigen::PlainObjectBase<DerivedN> & N);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "null.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_on_boundary = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ON_BOUNDARY_H
|
|
#define IGL_ON_BOUNDARY_H
|
|
#include "igl_inline.h"
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Dense>
|
|
#endif
|
|
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// ON_BOUNDARY Determine boundary facets of mesh elements stored in T
|
|
//
|
|
// Templates:
|
|
// IntegerT integer-value: i.e. int
|
|
// IntegerF integer-value: i.e. int
|
|
// Input:
|
|
// T triangle|tetrahedron index list, m by 3|4, where m is the number of
|
|
// elements
|
|
// Output:
|
|
// I m long list of bools whether tet is on boundary
|
|
// C m by 3|4 list of bools whether opposite facet is on boundary
|
|
//
|
|
template <typename IntegerT>
|
|
IGL_INLINE void on_boundary(
|
|
const std::vector<std::vector<IntegerT> > & T,
|
|
std::vector<bool> & I,
|
|
std::vector<std::vector<bool> > & C);
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
// Templates:
|
|
// DerivedT integer-value: i.e. from MatrixXi
|
|
// DerivedI bool-value: i.e. from MatrixXi
|
|
// DerivedC bool-value: i.e. from MatrixXi
|
|
template <typename DerivedT, typename DerivedI, typename DerivedC>
|
|
IGL_INLINE void on_boundary(
|
|
const Eigen::PlainObjectBase<DerivedT>& T,
|
|
Eigen::PlainObjectBase<DerivedI>& I,
|
|
Eigen::PlainObjectBase<DerivedC>& C);
|
|
#endif
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "on_boundary.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ONE = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ONE_H
|
|
#define IGL_ONE_H
|
|
// Often one needs a reference to a dummy variable containing one as its
|
|
// value, for example when using AntTweakBar's
|
|
// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ONE);
|
|
namespace igl
|
|
{
|
|
const char CHAR_ONE = 1;
|
|
const int INT_ONE = 1;
|
|
const unsigned int UNSIGNED_INT_ONE = 1;
|
|
const double DOUBLE_ONE = 1;
|
|
const float FLOAT_ONE = 1;
|
|
}
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_orient_outward = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ORIENT_OUTWARD_H
|
|
#define IGL_ORIENT_OUTWARD_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Orient each component (identified by C) of a mesh (V,F) so the normals on
|
|
// average point away from the patch's centroid.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// C #F list of components (output of orientable_patches)
|
|
// Outputs:
|
|
// FF #F by 3 list of new triangle indices such that FF(~I,:) = F(~I,:) and
|
|
// FF(I,:) = fliplr(F(I,:)) (OK if &FF = &F)
|
|
// I max(C)+1 list of whether face has been flipped
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedC,
|
|
typename DerivedFF,
|
|
typename DerivedI>
|
|
IGL_INLINE void orient_outward(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedI> & I);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "orient_outward.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_orientable_patches = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ORIENTABLE_PATCHES_H
|
|
#define IGL_ORIENTABLE_PATCHES_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Compute connected components of facets connected by manifold edges.
|
|
//
|
|
// Known bugs: This will detect a moebius strip as a single patch (manifold,
|
|
// non-orientable) and also non-manfiold, yet orientable patches.
|
|
//
|
|
// Q: Does this find exactly (manifold || orientable) patches?
|
|
//
|
|
// Inputs:
|
|
// F #F by simplex-size list of facets
|
|
// Outputs:
|
|
// C #F list of component ids
|
|
// A #F by #F adjacency matrix
|
|
//
|
|
template <typename DerivedF, typename DerivedC, typename AScalar>
|
|
IGL_INLINE void orientable_patches(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::SparseMatrix<AScalar> & A);
|
|
};
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "orientable_patches.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_orth = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ORTH_H
|
|
#define IGL_ORTH_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// ORTH Orthogonalization.
|
|
// ORTH(A,Q) produces Q as an orthonormal basis for the range of A.
|
|
// That is, Q'*Q = I, the columns of Q span the same space as
|
|
// the columns of A, and the number of columns of Q is the
|
|
// rank of A.
|
|
//
|
|
//
|
|
// The algorithm uses singular value decomposition, SVD, instead of orthogonal
|
|
// factorization, QR. This doubles the computation time, but
|
|
// provides more reliable and consistent rank determination.
|
|
// Closely follows MATLAB implementation in orth.m
|
|
//
|
|
// Inputs:
|
|
// A m by n matrix
|
|
// Outputs:
|
|
// Q m by n matrix with orthonormal columns spanning same column space as
|
|
// A
|
|
//
|
|
// Known bugs: Implementation listed as "Broken"
|
|
IGL_INLINE void orth(const Eigen::MatrixXd &A, Eigen::MatrixXd &Q);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "orth.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ortho = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ORTHO_H
|
|
#define IGL_ORTHO_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Implementation of the deprecated glOrtho function.
|
|
//
|
|
// Inputs:
|
|
// left coordinate of left vertical clipping plane
|
|
// right coordinate of right vertical clipping plane
|
|
// bottom coordinate of bottom vertical clipping plane
|
|
// top coordinate of top vertical clipping plane
|
|
// nearVal distance to near plane
|
|
// farVal distance to far plane
|
|
// Outputs:
|
|
// P 4x4 perspective matrix
|
|
template < typename DerivedP>
|
|
IGL_INLINE void ortho(
|
|
const typename DerivedP::Scalar left,
|
|
const typename DerivedP::Scalar right,
|
|
const typename DerivedP::Scalar bottom,
|
|
const typename DerivedP::Scalar top,
|
|
const typename DerivedP::Scalar nearVal,
|
|
const typename DerivedP::Scalar farVal,
|
|
Eigen::PlainObjectBase<DerivedP> & P);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "ortho.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_outer_facet = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OUTER_FACET_H
|
|
#define IGL_OUTER_FACET_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute a single facet which is guaranteed to be part of the "outer hull of
|
|
// a mesh (V,F). This implementation follows Section 3.6 of "Direct repair of
|
|
// self-intersecting meshes" [Attene 2014].
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// N #F by 3 list of face normals
|
|
// I #I list of facets to actually consider
|
|
// Outputs:
|
|
// f index of facet into V
|
|
// flip whether facet's orientation should be flipped so that
|
|
// counter-clockwise normal points outward.
|
|
//
|
|
// See also: cgal/outer_hull.h
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedI,
|
|
typename f_type>
|
|
IGL_INLINE void outer_facet(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedN> & N,
|
|
const Eigen::PlainObjectBase<DerivedI> & I,
|
|
f_type & f,
|
|
bool & flip);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "outer_facet.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_parallel_transport_angles = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_PARALLEL_TRANSPORT_ANGLE
|
|
#define IGL_PARALLEL_TRANSPORT_ANGLE
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
// Given the per-face local bases computed via igl::local_basis, this function
|
|
// computes the angle between the two reference frames across each edge.
|
|
// Any two vectors across the edge whose 2D representation only differs by
|
|
// this angle are considered to be parallel.
|
|
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex coordinates
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// FN #F by 3 list of face normals
|
|
// E2F #E by 2 list of the edge-to-face relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// F2E #F by 3 list of the face-to-edge relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// Output:
|
|
// K #E by 1 list of the parallel transport angles (zero
|
|
// for all boundary edges)
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedK>
|
|
IGL_INLINE void parallel_transport_angles(
|
|
const Eigen::PlainObjectBase<DerivedV>&V,
|
|
const Eigen::PlainObjectBase<DerivedF>&F,
|
|
const Eigen::PlainObjectBase<DerivedV>&FN,
|
|
const Eigen::MatrixXi &E2F,
|
|
const Eigen::MatrixXi &F2E,
|
|
Eigen::PlainObjectBase<DerivedK>&K);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "parallel_transport_angles.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_PARALLEL_TRANSPORT_ANGLE) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_partition = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PARTITION_H
|
|
#define IGL_PARTITION_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// PARTITION partition vertices into groups based on each
|
|
// vertex's vector: vertices with similar coordinates (close in
|
|
// space) will be put in the same group.
|
|
//
|
|
// Inputs:
|
|
// W #W by dim coordinate matrix
|
|
// k desired number of groups default is dim
|
|
// Output:
|
|
// G #W list of group indices (1 to k) for each vertex, such that vertex i
|
|
// is assigned to group G(i)
|
|
// S k list of seed vertices
|
|
// D #W list of squared distances for each vertex to it's corresponding
|
|
// closest seed
|
|
IGL_INLINE void partition(
|
|
const Eigen::MatrixXd & W,
|
|
const int k,
|
|
Eigen::Matrix<int,Eigen::Dynamic,1> & G,
|
|
Eigen::Matrix<int,Eigen::Dynamic,1> & S,
|
|
Eigen::Matrix<double,Eigen::Dynamic,1> & D);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "partition.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_parula = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PARULA_H
|
|
#define IGL_PARULA_H
|
|
#include "igl_inline.h"
|
|
//#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Dense>
|
|
//#endif
|
|
namespace igl
|
|
{
|
|
// PARULA like MATLAB's parula
|
|
//
|
|
// Inputs:
|
|
// m number of colors
|
|
// Outputs:
|
|
// J m by list of RGB colors between 0 and 1
|
|
//
|
|
// Wrapper for directly computing [r,g,b] values for a given factor f between
|
|
// 0 and 1
|
|
//
|
|
// Inputs:
|
|
// f factor determining color value as if 0 was min and 1 was max
|
|
// Outputs:
|
|
// r red value
|
|
// g green value
|
|
// b blue value
|
|
template <typename T>
|
|
IGL_INLINE void parula(const T f, T * rgb);
|
|
template <typename T>
|
|
IGL_INLINE void parula(const T f, T & r, T & g, T & b);
|
|
// Inputs:
|
|
// Z #Z list of factors
|
|
// normalize whether to normalize Z to be tightly between [0,1]
|
|
// Outputs:
|
|
// C #C by 3 list of rgb colors
|
|
template <typename DerivedZ, typename DerivedC>
|
|
IGL_INLINE void parula(
|
|
const Eigen::PlainObjectBase<DerivedZ> & Z,
|
|
const bool normalize,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
// Inputs:
|
|
// min_z value at blue
|
|
// max_z value at red
|
|
template <typename DerivedZ, typename DerivedC>
|
|
IGL_INLINE void parula(
|
|
const Eigen::PlainObjectBase<DerivedZ> & Z,
|
|
const double min_Z,
|
|
const double max_Z,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
// adapted from parula.m
|
|
const Eigen::Matrix<float,256,4> PARULA_COLOR_MAP =
|
|
(Eigen::Matrix<float,256,4>()<<
|
|
0.2081,0.1663,0.5292,1,
|
|
0.2091,0.1721,0.5411,1,
|
|
0.2101,0.1779,0.553,1,
|
|
0.2109,0.1837,0.565,1,
|
|
0.2116,0.1895,0.5771,1,
|
|
0.2121,0.1954,0.5892,1,
|
|
0.2124,0.2013,0.6013,1,
|
|
0.2125,0.2072,0.6135,1,
|
|
0.2123,0.2132,0.6258,1,
|
|
0.2118,0.2192,0.6381,1,
|
|
0.2111,0.2253,0.6505,1,
|
|
0.2099,0.2315,0.6629,1,
|
|
0.2084,0.2377,0.6753,1,
|
|
0.2063,0.244,0.6878,1,
|
|
0.2038,0.2503,0.7003,1,
|
|
0.2006,0.2568,0.7129,1,
|
|
0.1968,0.2632,0.7255,1,
|
|
0.1921,0.2698,0.7381,1,
|
|
0.1867,0.2764,0.7507,1,
|
|
0.1802,0.2832,0.7634,1,
|
|
0.1728,0.2902,0.7762,1,
|
|
0.1641,0.2975,0.789,1,
|
|
0.1541,0.3052,0.8017,1,
|
|
0.1427,0.3132,0.8145,1,
|
|
0.1295,0.3217,0.8269,1,
|
|
0.1147,0.3306,0.8387,1,
|
|
0.0986,0.3397,0.8495,1,
|
|
0.0816,0.3486,0.8588,1,
|
|
0.0646,0.3572,0.8664,1,
|
|
0.0482,0.3651,0.8722,1,
|
|
0.0329,0.3724,0.8765,1,
|
|
0.0213,0.3792,0.8796,1,
|
|
0.0136,0.3853,0.8815,1,
|
|
0.0086,0.3911,0.8827,1,
|
|
0.006,0.3965,0.8833,1,
|
|
0.0051,0.4017,0.8834,1,
|
|
0.0054,0.4066,0.8831,1,
|
|
0.0067,0.4113,0.8825,1,
|
|
0.0089,0.4159,0.8816,1,
|
|
0.0116,0.4203,0.8805,1,
|
|
0.0148,0.4246,0.8793,1,
|
|
0.0184,0.4288,0.8779,1,
|
|
0.0223,0.4329,0.8763,1,
|
|
0.0264,0.437,0.8747,1,
|
|
0.0306,0.441,0.8729,1,
|
|
0.0349,0.4449,0.8711,1,
|
|
0.0394,0.4488,0.8692,1,
|
|
0.0437,0.4526,0.8672,1,
|
|
0.0477,0.4564,0.8652,1,
|
|
0.0514,0.4602,0.8632,1,
|
|
0.0549,0.464,0.8611,1,
|
|
0.0582,0.4677,0.8589,1,
|
|
0.0612,0.4714,0.8568,1,
|
|
0.064,0.4751,0.8546,1,
|
|
0.0666,0.4788,0.8525,1,
|
|
0.0689,0.4825,0.8503,1,
|
|
0.071,0.4862,0.8481,1,
|
|
0.0729,0.4899,0.846,1,
|
|
0.0746,0.4937,0.8439,1,
|
|
0.0761,0.4974,0.8418,1,
|
|
0.0773,0.5012,0.8398,1,
|
|
0.0782,0.5051,0.8378,1,
|
|
0.0789,0.5089,0.8359,1,
|
|
0.0794,0.5129,0.8341,1,
|
|
0.0795,0.5169,0.8324,1,
|
|
0.0793,0.521,0.8308,1,
|
|
0.0788,0.5251,0.8293,1,
|
|
0.0778,0.5295,0.828,1,
|
|
0.0764,0.5339,0.827,1,
|
|
0.0746,0.5384,0.8261,1,
|
|
0.0724,0.5431,0.8253,1,
|
|
0.0698,0.5479,0.8247,1,
|
|
0.0668,0.5527,0.8243,1,
|
|
0.0636,0.5577,0.8239,1,
|
|
0.06,0.5627,0.8237,1,
|
|
0.0562,0.5677,0.8234,1,
|
|
0.0523,0.5727,0.8231,1,
|
|
0.0484,0.5777,0.8228,1,
|
|
0.0445,0.5826,0.8223,1,
|
|
0.0408,0.5874,0.8217,1,
|
|
0.0372,0.5922,0.8209,1,
|
|
0.0342,0.5968,0.8198,1,
|
|
0.0317,0.6012,0.8186,1,
|
|
0.0296,0.6055,0.8171,1,
|
|
0.0279,0.6097,0.8154,1,
|
|
0.0265,0.6137,0.8135,1,
|
|
0.0255,0.6176,0.8114,1,
|
|
0.0248,0.6214,0.8091,1,
|
|
0.0243,0.625,0.8066,1,
|
|
0.0239,0.6285,0.8039,1,
|
|
0.0237,0.6319,0.801,1,
|
|
0.0235,0.6352,0.798,1,
|
|
0.0233,0.6384,0.7948,1,
|
|
0.0231,0.6415,0.7916,1,
|
|
0.023,0.6445,0.7881,1,
|
|
0.0229,0.6474,0.7846,1,
|
|
0.0227,0.6503,0.781,1,
|
|
0.0227,0.6531,0.7773,1,
|
|
0.0232,0.6558,0.7735,1,
|
|
0.0238,0.6585,0.7696,1,
|
|
0.0246,0.6611,0.7656,1,
|
|
0.0263,0.6637,0.7615,1,
|
|
0.0282,0.6663,0.7574,1,
|
|
0.0306,0.6688,0.7532,1,
|
|
0.0338,0.6712,0.749,1,
|
|
0.0373,0.6737,0.7446,1,
|
|
0.0418,0.6761,0.7402,1,
|
|
0.0467,0.6784,0.7358,1,
|
|
0.0516,0.6808,0.7313,1,
|
|
0.0574,0.6831,0.7267,1,
|
|
0.0629,0.6854,0.7221,1,
|
|
0.0692,0.6877,0.7173,1,
|
|
0.0755,0.6899,0.7126,1,
|
|
0.082,0.6921,0.7078,1,
|
|
0.0889,0.6943,0.7029,1,
|
|
0.0956,0.6965,0.6979,1,
|
|
0.1031,0.6986,0.6929,1,
|
|
0.1104,0.7007,0.6878,1,
|
|
0.118,0.7028,0.6827,1,
|
|
0.1258,0.7049,0.6775,1,
|
|
0.1335,0.7069,0.6723,1,
|
|
0.1418,0.7089,0.6669,1,
|
|
0.1499,0.7109,0.6616,1,
|
|
0.1585,0.7129,0.6561,1,
|
|
0.1671,0.7148,0.6507,1,
|
|
0.1758,0.7168,0.6451,1,
|
|
0.1849,0.7186,0.6395,1,
|
|
0.1938,0.7205,0.6338,1,
|
|
0.2033,0.7223,0.6281,1,
|
|
0.2128,0.7241,0.6223,1,
|
|
0.2224,0.7259,0.6165,1,
|
|
0.2324,0.7275,0.6107,1,
|
|
0.2423,0.7292,0.6048,1,
|
|
0.2527,0.7308,0.5988,1,
|
|
0.2631,0.7324,0.5929,1,
|
|
0.2735,0.7339,0.5869,1,
|
|
0.2845,0.7354,0.5809,1,
|
|
0.2953,0.7368,0.5749,1,
|
|
0.3064,0.7381,0.5689,1,
|
|
0.3177,0.7394,0.563,1,
|
|
0.3289,0.7406,0.557,1,
|
|
0.3405,0.7417,0.5512,1,
|
|
0.352,0.7428,0.5453,1,
|
|
0.3635,0.7438,0.5396,1,
|
|
0.3753,0.7446,0.5339,1,
|
|
0.3869,0.7454,0.5283,1,
|
|
0.3986,0.7461,0.5229,1,
|
|
0.4103,0.7467,0.5175,1,
|
|
0.4218,0.7473,0.5123,1,
|
|
0.4334,0.7477,0.5072,1,
|
|
0.4447,0.7482,0.5021,1,
|
|
0.4561,0.7485,0.4972,1,
|
|
0.4672,0.7487,0.4924,1,
|
|
0.4783,0.7489,0.4877,1,
|
|
0.4892,0.7491,0.4831,1,
|
|
0.5,0.7491,0.4786,1,
|
|
0.5106,0.7492,0.4741,1,
|
|
0.5212,0.7492,0.4698,1,
|
|
0.5315,0.7491,0.4655,1,
|
|
0.5418,0.749,0.4613,1,
|
|
0.5519,0.7489,0.4571,1,
|
|
0.5619,0.7487,0.4531,1,
|
|
0.5718,0.7485,0.449,1,
|
|
0.5816,0.7482,0.4451,1,
|
|
0.5913,0.7479,0.4412,1,
|
|
0.6009,0.7476,0.4374,1,
|
|
0.6103,0.7473,0.4335,1,
|
|
0.6197,0.7469,0.4298,1,
|
|
0.629,0.7465,0.4261,1,
|
|
0.6382,0.746,0.4224,1,
|
|
0.6473,0.7456,0.4188,1,
|
|
0.6564,0.7451,0.4152,1,
|
|
0.6653,0.7446,0.4116,1,
|
|
0.6742,0.7441,0.4081,1,
|
|
0.683,0.7435,0.4046,1,
|
|
0.6918,0.743,0.4011,1,
|
|
0.7004,0.7424,0.3976,1,
|
|
0.7091,0.7418,0.3942,1,
|
|
0.7176,0.7412,0.3908,1,
|
|
0.7261,0.7405,0.3874,1,
|
|
0.7346,0.7399,0.384,1,
|
|
0.743,0.7392,0.3806,1,
|
|
0.7513,0.7385,0.3773,1,
|
|
0.7596,0.7378,0.3739,1,
|
|
0.7679,0.7372,0.3706,1,
|
|
0.7761,0.7364,0.3673,1,
|
|
0.7843,0.7357,0.3639,1,
|
|
0.7924,0.735,0.3606,1,
|
|
0.8005,0.7343,0.3573,1,
|
|
0.8085,0.7336,0.3539,1,
|
|
0.8166,0.7329,0.3506,1,
|
|
0.8246,0.7322,0.3472,1,
|
|
0.8325,0.7315,0.3438,1,
|
|
0.8405,0.7308,0.3404,1,
|
|
0.8484,0.7301,0.337,1,
|
|
0.8563,0.7294,0.3336,1,
|
|
0.8642,0.7288,0.33,1,
|
|
0.872,0.7282,0.3265,1,
|
|
0.8798,0.7276,0.3229,1,
|
|
0.8877,0.7271,0.3193,1,
|
|
0.8954,0.7266,0.3156,1,
|
|
0.9032,0.7262,0.3117,1,
|
|
0.911,0.7259,0.3078,1,
|
|
0.9187,0.7256,0.3038,1,
|
|
0.9264,0.7256,0.2996,1,
|
|
0.9341,0.7256,0.2953,1,
|
|
0.9417,0.7259,0.2907,1,
|
|
0.9493,0.7264,0.2859,1,
|
|
0.9567,0.7273,0.2808,1,
|
|
0.9639,0.7285,0.2754,1,
|
|
0.9708,0.7303,0.2696,1,
|
|
0.9773,0.7326,0.2634,1,
|
|
0.9831,0.7355,0.257,1,
|
|
0.9882,0.739,0.2504,1,
|
|
0.9922,0.7431,0.2437,1,
|
|
0.9952,0.7476,0.2373,1,
|
|
0.9973,0.7524,0.231,1,
|
|
0.9986,0.7573,0.2251,1,
|
|
0.9991,0.7624,0.2195,1,
|
|
0.999,0.7675,0.2141,1,
|
|
0.9985,0.7726,0.209,1,
|
|
0.9976,0.7778,0.2042,1,
|
|
0.9964,0.7829,0.1995,1,
|
|
0.995,0.788,0.1949,1,
|
|
0.9933,0.7931,0.1905,1,
|
|
0.9914,0.7981,0.1863,1,
|
|
0.9894,0.8032,0.1821,1,
|
|
0.9873,0.8083,0.178,1,
|
|
0.9851,0.8133,0.174,1,
|
|
0.9828,0.8184,0.17,1,
|
|
0.9805,0.8235,0.1661,1,
|
|
0.9782,0.8286,0.1622,1,
|
|
0.9759,0.8337,0.1583,1,
|
|
0.9736,0.8389,0.1544,1,
|
|
0.9713,0.8441,0.1505,1,
|
|
0.9692,0.8494,0.1465,1,
|
|
0.9672,0.8548,0.1425,1,
|
|
0.9654,0.8603,0.1385,1,
|
|
0.9638,0.8659,0.1343,1,
|
|
0.9623,0.8716,0.1301,1,
|
|
0.9611,0.8774,0.1258,1,
|
|
0.96,0.8834,0.1215,1,
|
|
0.9593,0.8895,0.1171,1,
|
|
0.9588,0.8958,0.1126,1,
|
|
0.9586,0.9022,0.1082,1,
|
|
0.9587,0.9088,0.1036,1,
|
|
0.9591,0.9155,0.099,1,
|
|
0.9599,0.9225,0.0944,1,
|
|
0.961,0.9296,0.0897,1,
|
|
0.9624,0.9368,0.085,1,
|
|
0.9641,0.9443,0.0802,1,
|
|
0.9662,0.9518,0.0753,1,
|
|
0.9685,0.9595,0.0703,1,
|
|
0.971,0.9673,0.0651,1,
|
|
0.9736,0.9752,0.0597,1,
|
|
0.9763,0.9831,0.0538,1).finished();
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "parula.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_path_to_executable = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PATH_TO_EXECUTABLE_H
|
|
#define IGL_PATH_TO_EXECUTABLE_H
|
|
#include "igl_inline.h"
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
// Return the path of the current executable.
|
|
// Note: Tested for Mac OS X
|
|
IGL_INLINE std::string path_to_executable();
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "path_to_executable.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_pathinfo = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PATHINFO_H
|
|
#define IGL_PATHINFO_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
//// Decided not to use these
|
|
//const int PATHINFO_DIRNAME 01
|
|
//const int PATHINFO_BASENAME 02
|
|
//const int PATHINFO_EXTENSION 04
|
|
//const int PATHINFO_FILENAME 08
|
|
|
|
// Function like PHP's pathinfo
|
|
// returns information about path
|
|
// Input:
|
|
// path string containing input path
|
|
// Outputs:
|
|
// dirname string containing dirname (see dirname.h)
|
|
// basename string containing basename (see basename.h)
|
|
// extension string containing extension (characters after last '.')
|
|
// filename string containing filename (characters of basename before last
|
|
// '.')
|
|
//
|
|
//
|
|
// Examples:
|
|
//
|
|
// input | dirname basename ext filename
|
|
// "/" | "/" "" "" ""
|
|
// "//" | "/" "" "" ""
|
|
// "/foo" | "/" "foo" "" "foo"
|
|
// "/foo/" | "/" "foo" "" "foo"
|
|
// "/foo//" | "/" "foo" "" "foo"
|
|
// "/foo/./" | "/foo" "." "" ""
|
|
// "/foo/bar" | "/foo" "bar" "" "bar"
|
|
// "/foo/bar." | "/foo" "bar." "" "bar"
|
|
// "/foo/bar.txt" | "/foo" "bar.txt" "txt" "bar"
|
|
// "/foo/bar.txt.zip" | "/foo" "bar.txt.zip" "zip" "bar.txt"
|
|
// "/foo/bar.dir/" | "/foo" "bar.dir" "dir" "bar"
|
|
// "/foo/bar.dir/file" | "/foo/bar.dir" "file" "" "file"
|
|
// "/foo/bar.dir/file.txt" | "/foo/bar.dir" "file.txt" "txt" "file"
|
|
// See also: basename, dirname
|
|
IGL_INLINE void pathinfo(
|
|
const std::string & path,
|
|
std::string & dirname,
|
|
std::string & basename,
|
|
std::string & extension,
|
|
std::string & filename);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "pathinfo.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_per_corner_normals = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PER_CORNER_NORMALS_H
|
|
#define IGL_PER_CORNER_NORMALS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Compute vertex normals via vertex position list, face list
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigne Matrix of face (triangle) indices
|
|
// corner_threshold threshold in degrees on sharp angles
|
|
// Output:
|
|
// CN #F*3 by 3 eigen Matrix of mesh vertex 3D normals, where the normal
|
|
// for corner F(i,j) is at CN(i*3+j,:)
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void per_corner_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const double corner_threshold,
|
|
Eigen::PlainObjectBase<DerivedV> & CN);
|
|
// Other Inputs:
|
|
// FN #F by 3 eigen Matrix of face normals
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedFN,
|
|
typename DerivedCN>
|
|
IGL_INLINE void per_corner_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedFN>& FN,
|
|
const double corner_threshold,
|
|
Eigen::PlainObjectBase<DerivedCN> & CN);
|
|
// Other Inputs:
|
|
// VF map from vertices to list of incident faces
|
|
template <typename DerivedV, typename DerivedF, typename IndexType>
|
|
IGL_INLINE void per_corner_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedV>& FN,
|
|
const std::vector<std::vector<IndexType> >& VF,
|
|
const double corner_threshold,
|
|
Eigen::PlainObjectBase<DerivedV> & CN);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "per_corner_normals.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_per_edge_normals = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PER_EDGE_NORMALS_H
|
|
#define IGL_PER_EDGE_NORMALS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
enum PerEdgeNormalsWeightingType
|
|
{
|
|
// Incident face normals have uniform influence on edge normal
|
|
PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM = 0,
|
|
// Incident face normals are averaged weighted by area
|
|
PER_EDGE_NORMALS_WEIGHTING_TYPE_AREA = 1,
|
|
// Area weights
|
|
PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT = 2,
|
|
NUM_PER_EDGE_NORMALS_WEIGHTING_TYPE = 3
|
|
};
|
|
// Compute face normals via vertex position list, face list
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (triangle) indices
|
|
// weighting weighting type
|
|
// Output:
|
|
// N #2 by 3 matrix of mesh edge 3D normals per row
|
|
// E #E by 2 matrix of edge indices per row
|
|
// EMAP #E by 1 matrix of indices from all edges to E
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedFN,
|
|
typename DerivedN,
|
|
typename DerivedE,
|
|
typename DerivedEMAP>
|
|
IGL_INLINE void per_edge_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const PerEdgeNormalsWeightingType weight,
|
|
const Eigen::PlainObjectBase<DerivedFN>& FN,
|
|
Eigen::PlainObjectBase<DerivedN> & N,
|
|
Eigen::PlainObjectBase<DerivedE> & E,
|
|
Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedE,
|
|
typename DerivedEMAP>
|
|
IGL_INLINE void per_edge_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const PerEdgeNormalsWeightingType weight,
|
|
Eigen::PlainObjectBase<DerivedN> & N,
|
|
Eigen::PlainObjectBase<DerivedE> & E,
|
|
Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedE,
|
|
typename DerivedEMAP>
|
|
IGL_INLINE void per_edge_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedN> & N,
|
|
Eigen::PlainObjectBase<DerivedE> & E,
|
|
Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "per_edge_normals.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_per_face_normals = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PER_FACE_NORMALS_H
|
|
#define IGL_PER_FACE_NORMALS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute face normals via vertex position list, face list
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigen Matrix of face (triangle) indices
|
|
// Z 3 vector normal given to faces with degenerate normal.
|
|
// Output:
|
|
// N #F by 3 eigen Matrix of mesh face (triangle) 3D normals
|
|
//
|
|
// Example:
|
|
// // Give degenerate faces (1/3,1/3,1/3)^0.5
|
|
// per_face_normals(V,F,Vector3d(1,1,1).normalized(),N);
|
|
template <typename DerivedV, typename DerivedF, typename DerivedZ, typename DerivedN>
|
|
IGL_INLINE void per_face_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedZ> & Z,
|
|
Eigen::PlainObjectBase<DerivedN> & N);
|
|
// Wrapper with Z = (0,0,0). Note that this means that row norms will be zero
|
|
// (i.e. not 1) for degenerate normals.
|
|
template <typename DerivedV, typename DerivedF, typename DerivedN>
|
|
IGL_INLINE void per_face_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedN> & N);
|
|
// Special version where order of face indices is guaranteed not to effect
|
|
// output.
|
|
template <typename DerivedV, typename DerivedF, typename DerivedN>
|
|
IGL_INLINE void per_face_normals_stable(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedN> & N);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "per_face_normals.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_per_vertex_attribute_smoothing = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PER_VERTEX_ATTRIBUTE_SMOOTHING_H
|
|
#define IGL_PER_VERTEX_ATTRIBUTE_SMOOTHING_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Smooth vertex attributes using uniform Laplacian
|
|
// Inputs:
|
|
// Ain #V by #A eigen Matrix of mesh vertex attributes (each vertex has #A attributes)
|
|
// F #F by 3 eigne Matrix of face (triangle) indices
|
|
// Output:
|
|
// Aout #V by #A eigen Matrix of mesh vertex attributes
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void per_vertex_attribute_smoothing(
|
|
const Eigen::PlainObjectBase<DerivedV>& Ain,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedV> & Aout);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "per_vertex_attribute_smoothing.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_per_vertex_normals = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PER_VERTEX_NORMALS_H
|
|
#define IGL_PER_VERTEX_NORMALS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
// Note: It would be nice to support more or all of the methods here:
|
|
// "A comparison of algorithms for vertex normal computation"
|
|
namespace igl
|
|
{
|
|
enum PerVertexNormalsWeightingType
|
|
{
|
|
// Incident face normals have uniform influence on vertex normal
|
|
PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM = 0,
|
|
// Incident face normals are averaged weighted by area
|
|
PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA = 1,
|
|
// Incident face normals are averaged weighted by incident angle of vertex
|
|
PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE = 2,
|
|
// Area weights
|
|
PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT = 3,
|
|
NUM_PER_VERTEX_NORMALS_WEIGHTING_TYPE = 4
|
|
};
|
|
// Compute vertex normals via vertex position list, face list
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigne Matrix of face (triangle) indices
|
|
// weighting Weighting type
|
|
// Output:
|
|
// N #V by 3 eigen Matrix of mesh vertex 3D normals
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void per_vertex_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const igl::PerVertexNormalsWeightingType weighting,
|
|
Eigen::PlainObjectBase<DerivedV> & N);
|
|
// Without weighting
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void per_vertex_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedV> & N);
|
|
// Inputs:
|
|
// FN #F by 3 matrix of face (triangle) normals
|
|
template <typename DerivedV, typename DerivedF, typename DerivedFN, typename DerivedN>
|
|
IGL_INLINE void per_vertex_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const PerVertexNormalsWeightingType weighting,
|
|
const Eigen::PlainObjectBase<DerivedFN>& FN,
|
|
Eigen::PlainObjectBase<DerivedN> & N);
|
|
// Without weighting
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void per_vertex_normals(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedV>& FN,
|
|
Eigen::PlainObjectBase<DerivedV> & N);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "per_vertex_normals.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_PI = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PI_H
|
|
#define IGL_PI_H
|
|
namespace igl
|
|
{
|
|
// Use standard mathematical constants' M_PI if available
|
|
#ifdef M_PI
|
|
const double PI = M_PI;
|
|
#else
|
|
const double PI = 3.1415926535897932384626433832795;
|
|
#endif
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_planarize_quad_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PLANARIZE_QUAD_MESH_H
|
|
#define IGL_PLANARIZE_QUAD_MESH_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Planarizes a given quad mesh using the algorithm described in the paper
|
|
// "Shape-Up: Shaping Discrete Geometry with Projections" by S. Bouaziz,
|
|
// M. Deuss, Y. Schwartzburg, T. Weise, M. Pauly, Computer Graphics Forum,
|
|
// Volume 31, Issue 5, August 2012, p. 1657-1667
|
|
// (http://dl.acm.org/citation.cfm?id=2346802).
|
|
// The algorithm iterates between projecting each quad to its closest planar
|
|
// counterpart and stitching those quads together via a least squares
|
|
// optimization. It stops whenever all quads' non-planarity is less than a
|
|
// given threshold (suggested value: 0.01), or a maximum number of iterations
|
|
// is reached.
|
|
|
|
|
|
// Inputs:
|
|
// Vin #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 4 eigen Matrix of face (quad) indices
|
|
// maxIter maximum numbers of iterations
|
|
// threshold minimum allowed threshold for non-planarity
|
|
// Output:
|
|
// Vout #V by 3 eigen Matrix of planar mesh vertex 3D positions
|
|
//
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void planarize_quad_mesh(const Eigen::PlainObjectBase<DerivedV> &Vin,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const int maxIter,
|
|
const double &threshold,
|
|
Eigen::PlainObjectBase<DerivedV> &Vout);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "planarize_quad_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ply = R"igl_Qu8mg5v7(#ifndef IGL_PLY_H
|
|
#define IGL_PLY_H
|
|
// Use unnamed namespace to avoid duplicate symbols
|
|
namespace
|
|
{
|
|
/*
|
|
|
|
Header for PLY polygon files.
|
|
|
|
- Greg Turk, March 1994
|
|
|
|
A PLY file contains a single polygonal _object_.
|
|
|
|
An object is composed of lists of _elements_. Typical elements are
|
|
vertices, faces, edges and materials.
|
|
|
|
Each type of element for a given object has one or more _properties_
|
|
associated with the element type. For instance, a vertex element may
|
|
have as properties three floating-point values x,y,z and three unsigned
|
|
chars for red, green and blue.
|
|
|
|
---------------------------------------------------------------
|
|
|
|
Copyright (c) 1994 The Board of Trustees of The Leland Stanford
|
|
Junior University. All rights reserved.
|
|
|
|
Permission to use, copy, modify and distribute this software and its
|
|
documentation for any purpose is hereby granted without fee, provided
|
|
that the above copyright notice and this permission notice appear in
|
|
all copies of this software and that you do not sell the software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*/
|
|
|
|
/*
|
|
--------------------------------------------------------------------------------
|
|
Joao Fradinho Oliveira, July 2005
|
|
Copyright (c) 2005 University College London
|
|
copyright conditions as above
|
|
|
|
update for ply reading of multi OS ply files, in any OS (Unix, Macintosh, PC)
|
|
--------------------------------------------------------------------------------
|
|
|
|
ply_open_for_reading
|
|
|
|
* was changed to always open files in binary mode, files written in ascii can also be
|
|
read with this binary mode.
|
|
|
|
* allows opening of filenames that are alias files in macintosh
|
|
|
|
* code tested on pc and mac
|
|
|
|
|
|
get_words
|
|
|
|
* was changed to handle line breaks in UNIX, MACINTOSH, PC, it resets the file pointer
|
|
accordingly for the next read.
|
|
|
|
|
|
NOTES:
|
|
The ply file, has always an ascii part for the header, and a binary or ascii
|
|
part for the data.
|
|
The header part in ascii, dictates that linebreaks are used, this make models
|
|
operating system dependent, as a line break in unix is indicated with the escape character \n,
|
|
on a macintosh, with \r, and on a pc with \r\n <--2 unsigned chars, 2 bytes, instead of 1 byte.
|
|
|
|
get_words allows reading of any OS, text editors such as BBEdit do not save the linebreaks
|
|
properly to target OSs with binary files.
|
|
|
|
*/
|
|
|
|
#ifndef __PLY_H__
|
|
#define __PLY_H__
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#define PLY_ASCII 1 /* ascii PLY file */
|
|
#define PLY_BINARY_BE 2 /* binary PLY file, big endian */
|
|
#define PLY_BINARY_LE 3 /* binary PLY file, little endian */
|
|
#define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as
|
|
current architecture */
|
|
|
|
#define PLY_OKAY 0 /* ply routine worked okay */
|
|
#define PLY_ERROR -1 /* error in ply routine */
|
|
|
|
/* scalar data types supported by PLY format */
|
|
|
|
#define PLY_START_TYPE 0
|
|
#define PLY_CHAR 1
|
|
#define PLY_SHORT 2
|
|
#define PLY_INT 3
|
|
#define PLY_UCHAR 4
|
|
#define PLY_USHORT 5
|
|
#define PLY_UINT 6
|
|
#define PLY_FLOAT 7
|
|
#define PLY_DOUBLE 8
|
|
#define PLY_END_TYPE 9
|
|
|
|
#define PLY_SCALAR 0
|
|
#define PLY_LIST 1
|
|
|
|
|
|
typedef struct PlyProperty { /* description of a property */
|
|
|
|
const char *name; /* property name */
|
|
int external_type; /* file's data type */
|
|
int internal_type; /* program's data type */
|
|
int offset; /* offset bytes of prop in a struct */
|
|
|
|
int is_list; /* 1 = list, 0 = scalar */
|
|
int count_external; /* file's count type */
|
|
int count_internal; /* program's count type */
|
|
int count_offset; /* offset byte for list count */
|
|
|
|
} PlyProperty;
|
|
|
|
typedef struct PlyElement { /* description of an element */
|
|
const char *name; /* element name */
|
|
int num; /* number of elements in this object */
|
|
int size; /* size of element (bytes) or -1 if variable */
|
|
int nprops; /* number of properties for this element */
|
|
PlyProperty **props; /* list of properties in the file */
|
|
char *store_prop; /* flags: property wanted by user? */
|
|
int other_offset; /* offset to un-asked-for props, or -1 if none*/
|
|
int other_size; /* size of other_props structure */
|
|
} PlyElement;
|
|
|
|
typedef struct PlyOtherProp { /* describes other properties in an element */
|
|
const char *name; /* element name */
|
|
int size; /* size of other_props */
|
|
int nprops; /* number of properties in other_props */
|
|
PlyProperty **props; /* list of properties in other_props */
|
|
} PlyOtherProp;
|
|
|
|
typedef struct OtherData { /* for storing other_props for an other element */
|
|
void *other_props;
|
|
} OtherData;
|
|
|
|
typedef struct OtherElem { /* data for one "other" element */
|
|
char *elem_name; /* names of other elements */
|
|
int elem_count; /* count of instances of each element */
|
|
OtherData **other_data; /* actual property data for the elements */
|
|
PlyOtherProp *other_props; /* description of the property data */
|
|
} OtherElem;
|
|
|
|
typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */
|
|
int num_elems; /* number of other elements */
|
|
OtherElem *other_list; /* list of data for other elements */
|
|
} PlyOtherElems;
|
|
|
|
typedef struct PlyFile { /* description of PLY file */
|
|
FILE *fp; /* file pointer */
|
|
int file_type; /* ascii or binary */
|
|
float version; /* version number of file */
|
|
int nelems; /* number of elements of object */
|
|
PlyElement **elems; /* list of elements */
|
|
int num_comments; /* number of comments */
|
|
char **comments; /* list of comments */
|
|
int num_obj_info; /* number of items of object information */
|
|
char **obj_info; /* list of object info items */
|
|
PlyElement *which_elem; /* which element we're currently writing */
|
|
PlyOtherElems *other_elems; /* "other" elements from a PLY file */
|
|
} PlyFile;
|
|
|
|
/* memory allocation */
|
|
extern char *my_alloc();
|
|
#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__)
|
|
|
|
#ifndef ALLOCN
|
|
#define REALLOCN(PTR,TYPE,OLD_N,NEW_N) \
|
|
{ \
|
|
if ((OLD_N) == 0) \
|
|
{ ALLOCN((PTR),TYPE,(NEW_N));} \
|
|
else \
|
|
{ \
|
|
(PTR) = (TYPE *)realloc((PTR),(NEW_N)*sizeof(TYPE)); \
|
|
if (((PTR) == NULL) && ((NEW_N) != 0)) \
|
|
{ \
|
|
fprintf(stderr, "Memory reallocation failed on line %d in %s\n", \
|
|
__LINE__, __FILE__); \
|
|
fprintf(stderr, " tried to reallocate %d->%d\n", \
|
|
(OLD_N), (NEW_N)); \
|
|
exit(-1); \
|
|
} \
|
|
if ((NEW_N)>(OLD_N)) \
|
|
memset((char *)(PTR)+(OLD_N)*sizeof(TYPE), 0, \
|
|
((NEW_N)-(OLD_N))*sizeof(TYPE)); \
|
|
} \
|
|
}
|
|
|
|
#define ALLOCN(PTR,TYPE,N) \
|
|
{ (PTR) = (TYPE *) calloc(((unsigned)(N)),sizeof(TYPE));\
|
|
if ((PTR) == NULL) { \
|
|
fprintf(stderr, "Memory allocation failed on line %d in %s\n", \
|
|
__LINE__, __FILE__); \
|
|
exit(-1); \
|
|
} \
|
|
}
|
|
|
|
|
|
#define FREE(PTR) { free((PTR)); (PTR) = NULL; }
|
|
#endif
|
|
|
|
|
|
/*** delcaration of routines ***/
|
|
|
|
inline int get_native_binary_type2();
|
|
|
|
inline PlyFile *ply_write(FILE *, int,const char **, int);
|
|
inline PlyFile *ply_open_for_writing(char *, int,const char **, int, float *);
|
|
inline void ply_describe_element(PlyFile *, const char *, int, int, PlyProperty *);
|
|
inline void ply_describe_property(PlyFile *, const char *, PlyProperty *);
|
|
inline void ply_element_count(PlyFile *, const char *, int);
|
|
inline void ply_header_complete(PlyFile *);
|
|
inline void ply_put_element_setup(PlyFile *, const char *);
|
|
inline void ply_put_element(PlyFile *, void *);
|
|
inline void ply_put_comment(PlyFile *, char *);
|
|
inline void ply_put_obj_info(PlyFile *, char *);
|
|
inline PlyFile *ply_read(FILE *, int *, char ***);
|
|
inline PlyFile *ply_open_for_reading( const char *, int *, char ***, int *, float *);
|
|
inline PlyProperty **ply_get_element_description(PlyFile *, const char *, int*, int*);
|
|
inline void ply_get_element_setup( PlyFile *, const char *, int, PlyProperty *);
|
|
inline void ply_get_property(PlyFile *, const char *, PlyProperty *);
|
|
inline PlyOtherProp *ply_get_other_properties(PlyFile *, const char *, int);
|
|
inline void ply_get_element(PlyFile *, void *);
|
|
inline char **ply_get_comments(PlyFile *, int *);
|
|
inline char **ply_get_obj_info(PlyFile *, int *);
|
|
inline void ply_close(PlyFile *);
|
|
inline void ply_get_info(PlyFile *, float *, int *);
|
|
inline PlyOtherElems *ply_get_other_element (PlyFile *, const char *, int);
|
|
inline void ply_describe_other_elements ( PlyFile *, PlyOtherElems *);
|
|
inline void ply_put_other_elements (PlyFile *);
|
|
inline void ply_free_other_elements (PlyOtherElems *);
|
|
inline void ply_describe_other_properties(PlyFile *, PlyOtherProp *, int);
|
|
|
|
inline int equal_strings(const char *, const char *);
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* !__PLY_H__ */
|
|
/*
|
|
|
|
The interface routines for reading and writing PLY polygon files.
|
|
|
|
Greg Turk, February 1994
|
|
|
|
---------------------------------------------------------------
|
|
|
|
A PLY file contains a single polygonal _object_.
|
|
|
|
An object is composed of lists of _elements_. Typical elements are
|
|
vertices, faces, edges and materials.
|
|
|
|
Each type of element for a given object has one or more _properties_
|
|
associated with the element type. For instance, a vertex element may
|
|
have as properties the floating-point values x,y,z and the three unsigned
|
|
chars representing red, green and blue.
|
|
|
|
---------------------------------------------------------------
|
|
|
|
Copyright (c) 1994 The Board of Trustees of The Leland Stanford
|
|
Junior University. All rights reserved.
|
|
|
|
Permission to use, copy, modify and distribute this software and its
|
|
documentation for any purpose is hereby granted without fee, provided
|
|
that the above copyright notice and this permission notice appear in
|
|
all copies of this software and that you do not sell the software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*/
|
|
|
|
/*
|
|
--------------------------------------------------------------------------------
|
|
Joao Fradinho Oliveira, July 2005
|
|
University College London
|
|
|
|
update for ply reading of multi OS ply files, in any OS (Unix, Macintosh, PC)
|
|
--------------------------------------------------------------------------------
|
|
|
|
ply_open_for_reading
|
|
|
|
* was changed to always open files in binary mode, files written in ascii can also be
|
|
read with this binary mode.
|
|
|
|
* allows opening of filenames that are alias files in macintosh
|
|
|
|
* code tested on pc and mac
|
|
|
|
|
|
get_words
|
|
|
|
* was changed to handle line breaks in UNIX, MACINTOSH, PC, it resets the file pointer
|
|
accordingly for the next read.
|
|
|
|
|
|
NOTES:
|
|
The ply file, has always an ascii part for the header, and a binary or ascii
|
|
part for the data.
|
|
The header part in ascii, dictates that linebreaks are used, this make models
|
|
operating system dependent, as a line break in unix is indicated with the escape character \n,
|
|
on a macintosh, with \r, and on a pc with \r\n <--2 unsigned chars, 2 bytes, instead of 1 byte.
|
|
|
|
get_words allows reading of any OS, text editors such as BBEdit do not save the linebreaks
|
|
properly to target OSs with binary files.
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
//#include "ply.h"
|
|
|
|
const char *type_names[] = {
|
|
"invalid",
|
|
"char", "short", "int",
|
|
"uchar", "ushort", "uint",
|
|
"float", "double",
|
|
};
|
|
|
|
const char *alt_type_names[] = { /* names of scalar types */
|
|
"invalid",
|
|
"int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64",
|
|
};
|
|
|
|
int ply_type_size[] = {
|
|
0, 1, 2, 4, 1, 2, 4, 4, 8
|
|
};
|
|
|
|
typedef union
|
|
{
|
|
int int_value;
|
|
char byte_values[sizeof(int)];
|
|
} endian_test_type;
|
|
|
|
|
|
static int native_binary_type = -1;
|
|
static int types_checked = 0;
|
|
|
|
#define NO_OTHER_PROPS -1
|
|
|
|
#define DONT_STORE_PROP 0
|
|
#define STORE_PROP 1
|
|
|
|
#define OTHER_PROP 0
|
|
#define NAMED_PROP 1
|
|
|
|
/* returns 1 if strings are equal, 0 if not */
|
|
inline int equal_strings(const char *, const char *);
|
|
|
|
/* find an element in a plyfile's list */
|
|
inline PlyElement *find_element(PlyFile *, const char *);
|
|
|
|
/* find a property in an element's list */
|
|
inline PlyProperty *find_property(PlyElement *, const char *, int *);
|
|
|
|
/* write to a file the word describing a PLY file data type */
|
|
inline void write_scalar_type (FILE *, int);
|
|
|
|
/* read a line from a file and break it up into separate words */
|
|
inline char **get_words(FILE *, int *, char **);
|
|
inline char **old_get_words(FILE *, int *);
|
|
|
|
/* write an item to a file */
|
|
inline void write_binary_item(FILE *, int, int, unsigned int, double, int);
|
|
inline void write_ascii_item(FILE *, int, unsigned int, double, int);
|
|
inline double old_write_ascii_item(FILE *, char *, int);
|
|
|
|
/* add information to a PLY file descriptor */
|
|
inline void add_element(PlyFile *, char **);
|
|
inline void add_property(PlyFile *, char **);
|
|
inline void add_comment(PlyFile *, char *);
|
|
inline void add_obj_info(PlyFile *, char *);
|
|
|
|
/* copy a property */
|
|
inline void copy_property(PlyProperty *, PlyProperty *);
|
|
|
|
/* store a value into where a pointer and a type specify */
|
|
inline void store_item(char *, int, int, unsigned int, double);
|
|
|
|
/* return the value of a stored item */
|
|
inline void get_stored_item( void *, int, int *, unsigned int *, double *);
|
|
|
|
/* return the value stored in an item, given ptr to it and its type */
|
|
inline double get_item_value(char *, int);
|
|
|
|
/* get binary or ascii item and store it according to ptr and type */
|
|
inline void get_ascii_item(char *, int, int *, unsigned int *, double *);
|
|
inline void get_binary_item(FILE *, int, int, int *, unsigned int *, double *);
|
|
|
|
/* get a bunch of elements from a file */
|
|
inline void ascii_get_element(PlyFile *, char *);
|
|
inline void binary_get_element(PlyFile *, char *);
|
|
|
|
/* memory allocation */
|
|
inline char *my_alloc(int, int, const char *);
|
|
|
|
/* byte ordering */
|
|
inline void get_native_binary_type();
|
|
inline void swap_bytes(char *, int);
|
|
|
|
inline void check_types();
|
|
|
|
|
|
/*************/
|
|
/* Writing */
|
|
/*************/
|
|
|
|
|
|
/******************************************************************************
|
|
Given a file pointer, get ready to write PLY data to the file.
|
|
|
|
Entry:
|
|
fp - the given file pointer
|
|
nelems - number of elements in object
|
|
elem_names - list of element names
|
|
file_type - file type, either ascii or binary
|
|
|
|
Exit:
|
|
returns a pointer to a PlyFile, used to refer to this file, or NULL if error
|
|
******************************************************************************/
|
|
|
|
inline PlyFile *ply_write(
|
|
FILE *fp,
|
|
int nelems,
|
|
const char **elem_names,
|
|
int file_type
|
|
)
|
|
{
|
|
int i;
|
|
PlyFile *plyfile;
|
|
PlyElement *elem;
|
|
|
|
/* check for NULL file pointer */
|
|
if (fp == NULL)
|
|
return (NULL);
|
|
|
|
if (native_binary_type == -1)
|
|
get_native_binary_type();
|
|
if (!types_checked)
|
|
check_types();
|
|
|
|
/* create a record for this object */
|
|
|
|
plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
|
|
if (file_type == PLY_BINARY_NATIVE)
|
|
plyfile->file_type = native_binary_type;
|
|
else
|
|
plyfile->file_type = file_type;
|
|
plyfile->num_comments = 0;
|
|
plyfile->num_obj_info = 0;
|
|
plyfile->nelems = nelems;
|
|
plyfile->version = 1.0;
|
|
plyfile->fp = fp;
|
|
plyfile->other_elems = NULL;
|
|
|
|
/* tuck aside the names of the elements */
|
|
|
|
plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
|
|
for (i = 0; i < nelems; i++) {
|
|
elem = (PlyElement *) myalloc (sizeof (PlyElement));
|
|
plyfile->elems[i] = elem;
|
|
elem->name = strdup (elem_names[i]);
|
|
elem->num = 0;
|
|
elem->nprops = 0;
|
|
}
|
|
|
|
/* return pointer to the file descriptor */
|
|
return (plyfile);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Open a polygon file for writing.
|
|
|
|
Entry:
|
|
filename - name of file to read from
|
|
nelems - number of elements in object
|
|
elem_names - list of element names
|
|
file_type - file type, either ascii or binary
|
|
|
|
Exit:
|
|
version - version number of PLY file
|
|
returns a file identifier, used to refer to this file, or NULL if error
|
|
******************************************************************************/
|
|
|
|
inline PlyFile *ply_open_for_writing(
|
|
const char *filename,
|
|
int nelems,
|
|
const char **elem_names,
|
|
int file_type,
|
|
float *version
|
|
)
|
|
{
|
|
PlyFile *plyfile;
|
|
char *name;
|
|
FILE *fp;
|
|
|
|
/* tack on the extension .ply, if necessary */
|
|
|
|
name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
|
|
strcpy (name, filename);
|
|
if (strlen (name) < 4 ||
|
|
strcmp (name + strlen (name) - 4, ".ply") != 0)
|
|
strcat (name, ".ply");
|
|
|
|
/* open the file for writing */
|
|
|
|
fp = fopen (name, "w");
|
|
if (fp == NULL) {
|
|
return (NULL);
|
|
}
|
|
|
|
/* create the actual PlyFile structure */
|
|
|
|
plyfile = ply_write (fp, nelems, elem_names, file_type);
|
|
if (plyfile == NULL)
|
|
return (NULL);
|
|
|
|
/* say what PLY file version number we're writing */
|
|
*version = plyfile->version;
|
|
|
|
/* return pointer to the file descriptor */
|
|
return (plyfile);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Describe an element, including its properties and how many will be written
|
|
to the file.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - name of element that information is being specified about
|
|
nelems - number of elements of this type to be written
|
|
nprops - number of properties contained in the element
|
|
prop_list - list of properties
|
|
******************************************************************************/
|
|
|
|
inline void ply_describe_element(
|
|
PlyFile *plyfile,
|
|
const char *elem_name,
|
|
int nelems,
|
|
int nprops,
|
|
PlyProperty *prop_list
|
|
)
|
|
{
|
|
int i;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
|
|
/* look for appropriate element */
|
|
elem = find_element (plyfile, elem_name);
|
|
if (elem == NULL) {
|
|
fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name);
|
|
exit (-1);
|
|
}
|
|
|
|
elem->num = nelems;
|
|
|
|
/* copy the list of properties */
|
|
|
|
elem->nprops = nprops;
|
|
elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
|
|
elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
|
|
|
|
for (i = 0; i < nprops; i++) {
|
|
prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
|
|
elem->props[i] = prop;
|
|
elem->store_prop[i] = NAMED_PROP;
|
|
copy_property (prop, &prop_list[i]);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Describe a property of an element.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - name of element that information is being specified about
|
|
prop - the new property
|
|
******************************************************************************/
|
|
|
|
inline void ply_describe_property(
|
|
PlyFile *plyfile,
|
|
const char *elem_name,
|
|
PlyProperty *prop
|
|
)
|
|
{
|
|
PlyElement *elem;
|
|
PlyProperty *elem_prop;
|
|
|
|
/* look for appropriate element */
|
|
elem = find_element (plyfile, elem_name);
|
|
if (elem == NULL) {
|
|
fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
|
|
elem_name);
|
|
return;
|
|
}
|
|
|
|
/* create room for new property */
|
|
|
|
if (elem->nprops == 0) {
|
|
elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
|
|
elem->store_prop = (char *) myalloc (sizeof (char));
|
|
elem->nprops = 1;
|
|
}
|
|
else {
|
|
elem->nprops++;
|
|
elem->props = (PlyProperty **)
|
|
realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
|
|
elem->store_prop = (char *)
|
|
realloc (elem->store_prop, sizeof (char) * elem->nprops);
|
|
}
|
|
|
|
/* copy the new property */
|
|
|
|
elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
|
|
elem->props[elem->nprops - 1] = elem_prop;
|
|
elem->store_prop[elem->nprops - 1] = NAMED_PROP;
|
|
copy_property (elem_prop, prop);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Describe what the "other" properties are that are to be stored, and where
|
|
they are in an element.
|
|
******************************************************************************/
|
|
|
|
inline void ply_describe_other_properties(
|
|
PlyFile *plyfile,
|
|
PlyOtherProp *other,
|
|
int offset
|
|
)
|
|
{
|
|
int i;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
|
|
/* look for appropriate element */
|
|
elem = find_element (plyfile, other->name);
|
|
if (elem == NULL) {
|
|
fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n",
|
|
other->name);
|
|
return;
|
|
}
|
|
|
|
/* create room for other properties */
|
|
|
|
if (elem->nprops == 0) {
|
|
elem->props = (PlyProperty **)
|
|
myalloc (sizeof (PlyProperty *) * other->nprops);
|
|
elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
|
|
elem->nprops = 0;
|
|
}
|
|
else {
|
|
int newsize;
|
|
newsize = elem->nprops + other->nprops;
|
|
elem->props = (PlyProperty **)
|
|
realloc (elem->props, sizeof (PlyProperty *) * newsize);
|
|
elem->store_prop = (char *)
|
|
realloc (elem->store_prop, sizeof (char) * newsize);
|
|
}
|
|
|
|
/* copy the other properties */
|
|
|
|
for (i = 0; i < other->nprops; i++) {
|
|
prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
|
|
copy_property (prop, other->props[i]);
|
|
elem->props[elem->nprops] = prop;
|
|
elem->store_prop[elem->nprops] = OTHER_PROP;
|
|
elem->nprops++;
|
|
}
|
|
|
|
/* save other info about other properties */
|
|
elem->other_size = other->size;
|
|
elem->other_offset = offset;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
State how many of a given element will be written.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - name of element that information is being specified about
|
|
nelems - number of elements of this type to be written
|
|
******************************************************************************/
|
|
|
|
inline void ply_element_count(
|
|
PlyFile *plyfile,
|
|
const char *elem_name,
|
|
int nelems
|
|
)
|
|
{
|
|
PlyElement *elem;
|
|
|
|
/* look for appropriate element */
|
|
elem = find_element (plyfile, elem_name);
|
|
if (elem == NULL) {
|
|
fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name);
|
|
exit (-1);
|
|
}
|
|
|
|
elem->num = nelems;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Signal that we've described everything a PLY file's header and that the
|
|
header should be written to the file.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
******************************************************************************/
|
|
|
|
inline void ply_header_complete(PlyFile *plyfile)
|
|
{
|
|
int i,j;
|
|
FILE *fp = plyfile->fp;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
|
|
fprintf (fp, "ply\n");
|
|
|
|
switch (plyfile->file_type) {
|
|
case PLY_ASCII:
|
|
fprintf (fp, "format ascii 1.0\n");
|
|
break;
|
|
case PLY_BINARY_BE:
|
|
fprintf (fp, "format binary_big_endian 1.0\n");
|
|
break;
|
|
case PLY_BINARY_LE:
|
|
fprintf (fp, "format binary_little_endian 1.0\n");
|
|
break;
|
|
default:
|
|
fprintf (stderr, "ply_header_complete: bad file type = %d\n",
|
|
plyfile->file_type);
|
|
exit (-1);
|
|
}
|
|
|
|
/* write out the comments */
|
|
|
|
for (i = 0; i < plyfile->num_comments; i++)
|
|
fprintf (fp, "comment %s\n", plyfile->comments[i]);
|
|
|
|
/* write out object information */
|
|
|
|
for (i = 0; i < plyfile->num_obj_info; i++)
|
|
fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
|
|
|
|
/* write out information about each element */
|
|
|
|
for (i = 0; i < plyfile->nelems; i++) {
|
|
|
|
elem = plyfile->elems[i];
|
|
fprintf (fp, "element %s %d\n", elem->name, elem->num);
|
|
|
|
/* write out each property */
|
|
for (j = 0; j < elem->nprops; j++) {
|
|
prop = elem->props[j];
|
|
if (prop->is_list) {
|
|
fprintf (fp, "property list ");
|
|
write_scalar_type (fp, prop->count_external);
|
|
fprintf (fp, " ");
|
|
write_scalar_type (fp, prop->external_type);
|
|
fprintf (fp, " %s\n", prop->name);
|
|
}
|
|
else {
|
|
fprintf (fp, "property ");
|
|
write_scalar_type (fp, prop->external_type);
|
|
fprintf (fp, " %s\n", prop->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf (fp, "end_header\n");
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Specify which elements are going to be written. This should be called
|
|
before a call to the routine ply_put_element().
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - name of element we're talking about
|
|
******************************************************************************/
|
|
|
|
inline void ply_put_element_setup(PlyFile *plyfile, const char *elem_name)
|
|
{
|
|
PlyElement *elem;
|
|
|
|
elem = find_element (plyfile, elem_name);
|
|
if (elem == NULL) {
|
|
fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name);
|
|
exit (-1);
|
|
}
|
|
|
|
plyfile->which_elem = elem;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Write an element to the file. This routine assumes that we're
|
|
writing the type of element specified in the last call to the routine
|
|
ply_put_element_setup().
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_ptr - pointer to the element
|
|
******************************************************************************/
|
|
|
|
inline void ply_put_element(PlyFile *plyfile, void *elem_ptr)
|
|
{
|
|
int j,k;
|
|
FILE *fp = plyfile->fp;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
char *elem_data,*item;
|
|
char **item_ptr;
|
|
int list_count;
|
|
int item_size;
|
|
int int_val;
|
|
unsigned int uint_val;
|
|
double double_val;
|
|
char **other_ptr;
|
|
|
|
elem = plyfile->which_elem;
|
|
elem_data = (char *)elem_ptr;
|
|
other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
|
|
|
|
/* write out either to an ascii or binary file */
|
|
|
|
if (plyfile->file_type == PLY_ASCII) {
|
|
|
|
/* write an ascii file */
|
|
|
|
/* write out each property of the element */
|
|
for (j = 0; j < elem->nprops; j++) {
|
|
prop = elem->props[j];
|
|
if (elem->store_prop[j] == OTHER_PROP)
|
|
elem_data = *other_ptr;
|
|
else
|
|
elem_data = (char *)elem_ptr;
|
|
if (prop->is_list) {
|
|
item = elem_data + prop->count_offset;
|
|
get_stored_item ((void *) item, prop->count_internal,
|
|
&int_val, &uint_val, &double_val);
|
|
write_ascii_item (fp, int_val, uint_val, double_val,
|
|
prop->count_external);
|
|
list_count = uint_val;
|
|
item_ptr = (char **) (elem_data + prop->offset);
|
|
item = item_ptr[0];
|
|
item_size = ply_type_size[prop->internal_type];
|
|
for (k = 0; k < list_count; k++) {
|
|
get_stored_item ((void *) item, prop->internal_type,
|
|
&int_val, &uint_val, &double_val);
|
|
write_ascii_item (fp, int_val, uint_val, double_val,
|
|
prop->external_type);
|
|
item += item_size;
|
|
}
|
|
}
|
|
else {
|
|
item = elem_data + prop->offset;
|
|
get_stored_item ((void *) item, prop->internal_type,
|
|
&int_val, &uint_val, &double_val);
|
|
write_ascii_item (fp, int_val, uint_val, double_val,
|
|
prop->external_type);
|
|
}
|
|
}
|
|
|
|
fprintf (fp, "\n");
|
|
}
|
|
else {
|
|
|
|
/* write a binary file */
|
|
|
|
/* write out each property of the element */
|
|
for (j = 0; j < elem->nprops; j++) {
|
|
prop = elem->props[j];
|
|
if (elem->store_prop[j] == OTHER_PROP)
|
|
elem_data = *other_ptr;
|
|
else
|
|
elem_data = (char *)elem_ptr;
|
|
if (prop->is_list) {
|
|
item = elem_data + prop->count_offset;
|
|
item_size = ply_type_size[prop->count_internal];
|
|
get_stored_item ((void *) item, prop->count_internal,
|
|
&int_val, &uint_val, &double_val);
|
|
write_binary_item (fp, plyfile->file_type, int_val, uint_val,
|
|
double_val, prop->count_external);
|
|
list_count = uint_val;
|
|
item_ptr = (char **) (elem_data + prop->offset);
|
|
item = item_ptr[0];
|
|
item_size = ply_type_size[prop->internal_type];
|
|
for (k = 0; k < list_count; k++) {
|
|
get_stored_item ((void *) item, prop->internal_type,
|
|
&int_val, &uint_val, &double_val);
|
|
write_binary_item (fp, plyfile->file_type, int_val, uint_val,
|
|
double_val, prop->external_type);
|
|
item += item_size;
|
|
}
|
|
}
|
|
else {
|
|
item = elem_data + prop->offset;
|
|
item_size = ply_type_size[prop->internal_type];
|
|
get_stored_item ((void *) item, prop->internal_type,
|
|
&int_val, &uint_val, &double_val);
|
|
write_binary_item (fp, plyfile->file_type, int_val, uint_val,
|
|
double_val, prop->external_type);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Specify a comment that will be written in the header.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
comment - the comment to be written
|
|
******************************************************************************/
|
|
|
|
inline void ply_put_comment(PlyFile *plyfile, char *comment)
|
|
{
|
|
/* (re)allocate space for new comment */
|
|
if (plyfile->num_comments == 0)
|
|
plyfile->comments = (char **) myalloc (sizeof (char *));
|
|
else
|
|
plyfile->comments = (char **) realloc (plyfile->comments,
|
|
sizeof (char *) * (plyfile->num_comments + 1));
|
|
|
|
/* add comment to list */
|
|
plyfile->comments[plyfile->num_comments] = strdup (comment);
|
|
plyfile->num_comments++;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Specify a piece of object information (arbitrary text) that will be written
|
|
in the header.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
obj_info - the text information to be written
|
|
******************************************************************************/
|
|
|
|
inline void ply_put_obj_info(PlyFile *plyfile, char *obj_info)
|
|
{
|
|
/* (re)allocate space for new info */
|
|
if (plyfile->num_obj_info == 0)
|
|
plyfile->obj_info = (char **) myalloc (sizeof (char *));
|
|
else
|
|
plyfile->obj_info = (char **) realloc (plyfile->obj_info,
|
|
sizeof (char *) * (plyfile->num_obj_info + 1));
|
|
|
|
/* add info to list */
|
|
plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info);
|
|
plyfile->num_obj_info++;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************/
|
|
/* Reading */
|
|
/*************/
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
Given a file pointer, get ready to read PLY data from the file.
|
|
|
|
Entry:
|
|
fp - the given file pointer
|
|
|
|
Exit:
|
|
nelems - number of elements in object
|
|
elem_names - list of element names
|
|
returns a pointer to a PlyFile, used to refer to this file, or NULL if error
|
|
******************************************************************************/
|
|
|
|
inline PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
|
|
{
|
|
int i,j;
|
|
PlyFile *plyfile;
|
|
int nwords;
|
|
char **words;
|
|
char **elist;
|
|
PlyElement *elem;
|
|
char *orig_line;
|
|
|
|
/* check for NULL file pointer */
|
|
if (fp == NULL)
|
|
return (NULL);
|
|
|
|
if (native_binary_type == -1)
|
|
get_native_binary_type();
|
|
if (!types_checked)
|
|
check_types();
|
|
|
|
/* create record for this object */
|
|
|
|
plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
|
|
plyfile->nelems = 0;
|
|
plyfile->comments = NULL;
|
|
plyfile->num_comments = 0;
|
|
plyfile->obj_info = NULL;
|
|
plyfile->num_obj_info = 0;
|
|
plyfile->fp = fp;
|
|
plyfile->other_elems = NULL;
|
|
|
|
/* read and parse the file's header */
|
|
|
|
words = get_words (plyfile->fp, &nwords, &orig_line);
|
|
if (!words || !equal_strings (words[0], "ply"))
|
|
{
|
|
if (words)
|
|
free(words);
|
|
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
while (words) {
|
|
|
|
/* parse words */
|
|
|
|
if (equal_strings (words[0], "format")) {
|
|
if (nwords != 3) {
|
|
free(words);
|
|
return (NULL);
|
|
}
|
|
if (equal_strings (words[1], "ascii"))
|
|
plyfile->file_type = PLY_ASCII;
|
|
else if (equal_strings (words[1], "binary_big_endian"))
|
|
plyfile->file_type = PLY_BINARY_BE;
|
|
else if (equal_strings (words[1], "binary_little_endian"))
|
|
plyfile->file_type = PLY_BINARY_LE;
|
|
else {
|
|
free(words);
|
|
return (NULL);
|
|
}
|
|
plyfile->version = atof (words[2]);
|
|
}
|
|
else if (equal_strings (words[0], "element"))
|
|
add_element (plyfile, words);
|
|
else if (equal_strings (words[0], "property"))
|
|
add_property (plyfile, words);
|
|
else if (equal_strings (words[0], "comment"))
|
|
add_comment (plyfile, orig_line);
|
|
else if (equal_strings (words[0], "obj_info"))
|
|
add_obj_info (plyfile, orig_line);
|
|
else if (equal_strings (words[0], "end_header")) {
|
|
free(words);
|
|
break;
|
|
}
|
|
|
|
/* free up words space */
|
|
free (words);
|
|
|
|
words = get_words (plyfile->fp, &nwords, &orig_line);
|
|
}
|
|
|
|
/* create tags for each property of each element, to be used */
|
|
/* later to say whether or not to store each property for the user */
|
|
|
|
for (i = 0; i < plyfile->nelems; i++) {
|
|
elem = plyfile->elems[i];
|
|
elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
|
|
for (j = 0; j < elem->nprops; j++)
|
|
elem->store_prop[j] = DONT_STORE_PROP;
|
|
elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
|
|
}
|
|
|
|
/* set return values about the elements */
|
|
|
|
elist = (char **) myalloc (sizeof (char *) * plyfile->nelems);
|
|
for (i = 0; i < plyfile->nelems; i++)
|
|
elist[i] = strdup (plyfile->elems[i]->name);
|
|
|
|
*elem_names = elist;
|
|
*nelems = plyfile->nelems;
|
|
|
|
/* return a pointer to the file's information */
|
|
|
|
return (plyfile);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Open a polygon file for reading.
|
|
|
|
Entry:
|
|
filename - name of file to read from
|
|
|
|
Exit:
|
|
nelems - number of elements in object
|
|
elem_names - list of element names
|
|
file_type - file type, either ascii or binary
|
|
version - version number of PLY file
|
|
returns a file identifier, used to refer to this file, or NULL if error
|
|
******************************************************************************/
|
|
|
|
inline PlyFile *ply_open_for_reading(
|
|
char *filename,
|
|
int *nelems,
|
|
char ***elem_names,
|
|
int *file_type,
|
|
float *version
|
|
)
|
|
{
|
|
FILE *fp;
|
|
PlyFile *plyfile;
|
|
//char *name;
|
|
|
|
|
|
|
|
/* tack on the extension .ply, if necessary */
|
|
|
|
// removing below, to handle also macintosh alias filenames
|
|
//name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
|
|
//strcpy (name, filename);
|
|
//if (strlen (name) < 4 ||
|
|
// strcmp (name + strlen (name) - 4, ".ply") != 0)
|
|
// strcat (name, ".ply");
|
|
|
|
/* open the file for reading */
|
|
|
|
//fp = fopen (name, "r");
|
|
|
|
//opening file in binary, ascii data can be read in binary with get_words
|
|
fp = fopen (filename, "rb");
|
|
|
|
if (fp == NULL)
|
|
return (NULL);
|
|
|
|
/* create the PlyFile data structure */
|
|
|
|
plyfile = ply_read (fp, nelems, elem_names);
|
|
|
|
/* determine the file type and version */
|
|
|
|
*file_type = plyfile->file_type;
|
|
*version = plyfile->version;
|
|
|
|
/* return a pointer to the file's information */
|
|
|
|
return (plyfile);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Get information about a particular element.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - name of element to get information about
|
|
|
|
Exit:
|
|
nelems - number of elements of this type in the file
|
|
nprops - number of properties
|
|
returns a list of properties, or NULL if the file doesn't contain that elem
|
|
******************************************************************************/
|
|
|
|
inline PlyProperty **ply_get_element_description(
|
|
PlyFile *plyfile,
|
|
const char *elem_name,
|
|
int *nelems,
|
|
int *nprops
|
|
)
|
|
{
|
|
int i;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
PlyProperty **prop_list;
|
|
|
|
/* find information about the element */
|
|
elem = find_element (plyfile, elem_name);
|
|
if (elem == NULL)
|
|
return (NULL);
|
|
|
|
*nelems = elem->num;
|
|
*nprops = elem->nprops;
|
|
|
|
/* make a copy of the element's property list */
|
|
prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
|
|
for (i = 0; i < elem->nprops; i++) {
|
|
prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
|
|
copy_property (prop, elem->props[i]);
|
|
prop_list[i] = prop;
|
|
}
|
|
|
|
/* return this duplicate property list */
|
|
return (prop_list);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Specify which properties of an element are to be returned. This should be
|
|
called before a call to the routine ply_get_element().
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - which element we're talking about
|
|
nprops - number of properties
|
|
prop_list - list of properties
|
|
******************************************************************************/
|
|
|
|
inline void ply_get_element_setup(
|
|
PlyFile *plyfile,
|
|
const char *elem_name,
|
|
int nprops,
|
|
PlyProperty *prop_list
|
|
)
|
|
{
|
|
int i;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
int index;
|
|
|
|
/* find information about the element */
|
|
elem = find_element (plyfile, elem_name);
|
|
plyfile->which_elem = elem;
|
|
|
|
/* deposit the property information into the element's description */
|
|
for (i = 0; i < nprops; i++) {
|
|
|
|
/* look for actual property */
|
|
prop = find_property (elem, prop_list[i].name, &index);
|
|
if (prop == NULL) {
|
|
fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
|
|
prop_list[i].name, elem_name);
|
|
continue;
|
|
}
|
|
|
|
/* store its description */
|
|
prop->internal_type = prop_list[i].internal_type;
|
|
prop->offset = prop_list[i].offset;
|
|
prop->count_internal = prop_list[i].count_internal;
|
|
prop->count_offset = prop_list[i].count_offset;
|
|
|
|
/* specify that the user wants this property */
|
|
elem->store_prop[index] = STORE_PROP;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Specify a property of an element that is to be returned. This should be
|
|
called (usually multiple times) before a call to the routine ply_get_element().
|
|
This routine should be used in preference to the less flexible old routine
|
|
called ply_get_element_setup().
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - which element we're talking about
|
|
prop - property to add to those that will be returned
|
|
******************************************************************************/
|
|
|
|
inline void ply_get_property(
|
|
PlyFile *plyfile,
|
|
const char *elem_name,
|
|
PlyProperty *prop
|
|
)
|
|
{
|
|
PlyElement *elem;
|
|
PlyProperty *prop_ptr;
|
|
int index;
|
|
|
|
/* find information about the element */
|
|
elem = find_element (plyfile, elem_name);
|
|
plyfile->which_elem = elem;
|
|
|
|
/* deposit the property information into the element's description */
|
|
|
|
prop_ptr = find_property (elem, prop->name, &index);
|
|
if (prop_ptr == NULL) {
|
|
fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
|
|
prop->name, elem_name);
|
|
return;
|
|
}
|
|
prop_ptr->internal_type = prop->internal_type;
|
|
prop_ptr->offset = prop->offset;
|
|
prop_ptr->count_internal = prop->count_internal;
|
|
prop_ptr->count_offset = prop->count_offset;
|
|
|
|
/* specify that the user wants this property */
|
|
elem->store_prop[index] = STORE_PROP;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Read one element from the file. This routine assumes that we're reading
|
|
the type of element specified in the last call to the routine
|
|
ply_get_element_setup().
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_ptr - pointer to location where the element information should be put
|
|
******************************************************************************/
|
|
|
|
inline void ply_get_element(PlyFile *plyfile, void *elem_ptr)
|
|
{
|
|
if (plyfile->file_type == PLY_ASCII)
|
|
ascii_get_element (plyfile, (char *) elem_ptr);
|
|
else
|
|
binary_get_element (plyfile, (char *) elem_ptr);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Extract the comments from the header information of a PLY file.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
|
|
Exit:
|
|
num_comments - number of comments returned
|
|
returns a pointer to a list of comments
|
|
******************************************************************************/
|
|
|
|
inline char **ply_get_comments(PlyFile *plyfile, int *num_comments)
|
|
{
|
|
*num_comments = plyfile->num_comments;
|
|
return (plyfile->comments);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Extract the object information (arbitrary text) from the header information
|
|
of a PLY file.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
|
|
Exit:
|
|
num_obj_info - number of lines of text information returned
|
|
returns a pointer to a list of object info lines
|
|
******************************************************************************/
|
|
|
|
inline char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
|
|
{
|
|
*num_obj_info = plyfile->num_obj_info;
|
|
return (plyfile->obj_info);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Make ready for "other" properties of an element-- those properties that
|
|
the user has not explicitly asked for, but that are to be stashed away
|
|
in a special structure to be carried along with the element's other
|
|
information.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem - element for which we want to save away other properties
|
|
******************************************************************************/
|
|
|
|
inline void setup_other_props(PlyElement *elem)
|
|
{
|
|
int i;
|
|
PlyProperty *prop;
|
|
int size = 0;
|
|
int type_size;
|
|
|
|
/* Examine each property in decreasing order of size. */
|
|
/* We do this so that all data types will be aligned by */
|
|
/* word, half-word, or whatever within the structure. */
|
|
|
|
for (type_size = 8; type_size > 0; type_size /= 2) {
|
|
|
|
/* add up the space taken by each property, and save this information */
|
|
/* away in the property descriptor */
|
|
|
|
for (i = 0; i < elem->nprops; i++) {
|
|
|
|
/* don't bother with properties we've been asked to store explicitly */
|
|
if (elem->store_prop[i])
|
|
continue;
|
|
|
|
prop = elem->props[i];
|
|
|
|
/* internal types will be same as external */
|
|
prop->internal_type = prop->external_type;
|
|
prop->count_internal = prop->count_external;
|
|
|
|
/* check list case */
|
|
if (prop->is_list) {
|
|
|
|
/* pointer to list */
|
|
if (type_size == sizeof (void *)) {
|
|
prop->offset = size;
|
|
size += sizeof (void *); /* always use size of a pointer here */
|
|
}
|
|
|
|
/* count of number of list elements */
|
|
if (type_size == ply_type_size[prop->count_external]) {
|
|
prop->count_offset = size;
|
|
size += ply_type_size[prop->count_external];
|
|
}
|
|
}
|
|
/* not list */
|
|
else if (type_size == ply_type_size[prop->external_type]) {
|
|
prop->offset = size;
|
|
size += ply_type_size[prop->external_type];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* save the size for the other_props structure */
|
|
elem->other_size = size;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Specify that we want the "other" properties of an element to be tucked
|
|
away within the user's structure. The user needn't be concerned for how
|
|
these properties are stored.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_name - name of element that we want to store other_props in
|
|
offset - offset to where other_props will be stored inside user's structure
|
|
|
|
Exit:
|
|
returns pointer to structure containing description of other_props
|
|
******************************************************************************/
|
|
|
|
inline PlyOtherProp *ply_get_other_properties(
|
|
PlyFile *plyfile,
|
|
const char *elem_name,
|
|
int offset
|
|
)
|
|
{
|
|
int i;
|
|
PlyElement *elem;
|
|
PlyOtherProp *other;
|
|
PlyProperty *prop;
|
|
int nprops;
|
|
|
|
/* find information about the element */
|
|
elem = find_element (plyfile, elem_name);
|
|
if (elem == NULL) {
|
|
fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
|
|
elem_name);
|
|
return (NULL);
|
|
}
|
|
|
|
/* remember that this is the "current" element */
|
|
plyfile->which_elem = elem;
|
|
|
|
/* save the offset to where to store the other_props */
|
|
elem->other_offset = offset;
|
|
|
|
/* place the appropriate pointers, etc. in the element's property list */
|
|
setup_other_props (elem);
|
|
|
|
/* create structure for describing other_props */
|
|
other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
|
|
other->name = strdup (elem_name);
|
|
#if 0
|
|
if (elem->other_offset == NO_OTHER_PROPS) {
|
|
other->size = 0;
|
|
other->props = NULL;
|
|
other->nprops = 0;
|
|
return (other);
|
|
}
|
|
#endif
|
|
other->size = elem->other_size;
|
|
other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops);
|
|
|
|
/* save descriptions of each "other" property */
|
|
nprops = 0;
|
|
for (i = 0; i < elem->nprops; i++) {
|
|
if (elem->store_prop[i])
|
|
continue;
|
|
prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
|
|
copy_property (prop, elem->props[i]);
|
|
other->props[nprops] = prop;
|
|
nprops++;
|
|
}
|
|
other->nprops = nprops;
|
|
|
|
#if 1
|
|
/* set other_offset pointer appropriately if there are NO other properties */
|
|
if (other->nprops == 0) {
|
|
elem->other_offset = NO_OTHER_PROPS;
|
|
}
|
|
#endif
|
|
|
|
/* return structure */
|
|
return (other);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************/
|
|
/* Other Element Stuff */
|
|
/*************************/
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
Grab all the data for an element that a user does not want to explicitly
|
|
read in.
|
|
|
|
Entry:
|
|
plyfile - pointer to file
|
|
elem_name - name of element whose data is to be read in
|
|
elem_count - number of instances of this element stored in the file
|
|
|
|
Exit:
|
|
returns pointer to ALL the "other" element data for this PLY file
|
|
******************************************************************************/
|
|
|
|
inline PlyOtherElems *ply_get_other_element (
|
|
PlyFile *plyfile,
|
|
char *elem_name,
|
|
int elem_count
|
|
)
|
|
{
|
|
int i;
|
|
PlyElement *elem;
|
|
PlyOtherElems *other_elems;
|
|
OtherElem *other;
|
|
|
|
/* look for appropriate element */
|
|
elem = find_element (plyfile, elem_name);
|
|
if (elem == NULL) {
|
|
fprintf (stderr,
|
|
"ply_get_other_element: can't find element '%s'\n", elem_name);
|
|
exit (-1);
|
|
}
|
|
|
|
/* create room for the new "other" element, initializing the */
|
|
/* other data structure if necessary */
|
|
|
|
if (plyfile->other_elems == NULL) {
|
|
plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
|
|
other_elems = plyfile->other_elems;
|
|
other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
|
|
other = &(other_elems->other_list[0]);
|
|
other_elems->num_elems = 1;
|
|
}
|
|
else {
|
|
other_elems = plyfile->other_elems;
|
|
other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
|
|
sizeof (OtherElem) * (other_elems->num_elems + 1));
|
|
other = &(other_elems->other_list[other_elems->num_elems]);
|
|
other_elems->num_elems++;
|
|
}
|
|
|
|
/* count of element instances in file */
|
|
other->elem_count = elem_count;
|
|
|
|
/* save name of element */
|
|
other->elem_name = strdup (elem_name);
|
|
|
|
/* create a list to hold all the current elements */
|
|
other->other_data = (OtherData **)
|
|
malloc (sizeof (OtherData *) * other->elem_count);
|
|
|
|
/* set up for getting elements */
|
|
other->other_props = ply_get_other_properties (plyfile, elem_name,
|
|
offsetof(OtherData,other_props));
|
|
|
|
/* grab all these elements */
|
|
for (i = 0; i < other->elem_count; i++) {
|
|
/* grab and element from the file */
|
|
other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
|
|
ply_get_element (plyfile, (void *) other->other_data[i]);
|
|
}
|
|
|
|
/* return pointer to the other elements data */
|
|
return (other_elems);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Pass along a pointer to "other" elements that we want to save in a given
|
|
PLY file. These other elements were presumably read from another PLY file.
|
|
|
|
Entry:
|
|
plyfile - file pointer in which to store this other element info
|
|
other_elems - info about other elements that we want to store
|
|
******************************************************************************/
|
|
|
|
inline void ply_describe_other_elements (
|
|
PlyFile *plyfile,
|
|
PlyOtherElems *other_elems
|
|
)
|
|
{
|
|
int i;
|
|
OtherElem *other;
|
|
PlyElement *elem;
|
|
|
|
/* ignore this call if there is no other element */
|
|
if (other_elems == NULL)
|
|
return;
|
|
|
|
/* save pointer to this information */
|
|
plyfile->other_elems = other_elems;
|
|
|
|
/* describe the other properties of this element */
|
|
/* store them in the main element list as elements with
|
|
only other properties */
|
|
|
|
REALLOCN(plyfile->elems, PlyElement *,
|
|
plyfile->nelems, plyfile->nelems + other_elems->num_elems);
|
|
for (i = 0; i < other_elems->num_elems; i++) {
|
|
other = &(other_elems->other_list[i]);
|
|
elem = (PlyElement *) myalloc (sizeof (PlyElement));
|
|
plyfile->elems[plyfile->nelems++] = elem;
|
|
elem->name = strdup (other->elem_name);
|
|
elem->num = other->elem_count;
|
|
elem->nprops = 0;
|
|
ply_describe_other_properties (plyfile, other->other_props,
|
|
offsetof(OtherData,other_props));
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Write out the "other" elements specified for this PLY file.
|
|
|
|
Entry:
|
|
plyfile - pointer to PLY file to write out other elements for
|
|
******************************************************************************/
|
|
|
|
inline void ply_put_other_elements (PlyFile *plyfile)
|
|
{
|
|
int i,j;
|
|
OtherElem *other;
|
|
|
|
/* make sure we have other elements to write */
|
|
if (plyfile->other_elems == NULL)
|
|
return;
|
|
|
|
/* write out the data for each "other" element */
|
|
|
|
for (i = 0; i < plyfile->other_elems->num_elems; i++) {
|
|
|
|
other = &(plyfile->other_elems->other_list[i]);
|
|
ply_put_element_setup (plyfile, other->elem_name);
|
|
|
|
/* write out each instance of the current element */
|
|
for (j = 0; j < other->elem_count; j++)
|
|
ply_put_element (plyfile, (void *) other->other_data[j]);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Free up storage used by an "other" elements data structure.
|
|
|
|
Entry:
|
|
other_elems - data structure to free up
|
|
******************************************************************************/
|
|
|
|
inline void ply_free_other_elements (PlyOtherElems *other_elems)
|
|
{
|
|
// Alec:
|
|
//other_elems = other_elems;
|
|
delete(other_elems);
|
|
}
|
|
|
|
|
|
|
|
/*******************/
|
|
/* Miscellaneous */
|
|
/*******************/
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
Close a PLY file.
|
|
|
|
Entry:
|
|
plyfile - identifier of file to close
|
|
******************************************************************************/
|
|
|
|
inline void ply_close(PlyFile *plyfile)
|
|
{
|
|
fclose (plyfile->fp);
|
|
|
|
/* free up memory associated with the PLY file */
|
|
free (plyfile);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Get version number and file type of a PlyFile.
|
|
|
|
Entry:
|
|
ply - pointer to PLY file
|
|
|
|
Exit:
|
|
version - version of the file
|
|
file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
|
|
******************************************************************************/
|
|
|
|
inline void ply_get_info(PlyFile *ply, float *version, int *file_type)
|
|
{
|
|
if (ply == NULL)
|
|
return;
|
|
|
|
*version = ply->version;
|
|
*file_type = ply->file_type;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Compare two strings. Returns 1 if they are the same, 0 if not.
|
|
******************************************************************************/
|
|
|
|
inline int equal_strings(const char *s1, const char *s2)
|
|
{
|
|
|
|
while (*s1 && *s2)
|
|
if (*s1++ != *s2++)
|
|
return (0);
|
|
|
|
if (*s1 != *s2)
|
|
return (0);
|
|
else
|
|
return (1);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Find an element from the element list of a given PLY object.
|
|
|
|
Entry:
|
|
plyfile - file id for PLY file
|
|
element - name of element we're looking for
|
|
|
|
Exit:
|
|
returns the element, or NULL if not found
|
|
******************************************************************************/
|
|
|
|
inline PlyElement *find_element(PlyFile *plyfile, const char *element)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < plyfile->nelems; i++)
|
|
if (equal_strings (element, plyfile->elems[i]->name))
|
|
return (plyfile->elems[i]);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Find a property in the list of properties of a given element.
|
|
|
|
Entry:
|
|
elem - pointer to element in which we want to find the property
|
|
prop_name - name of property to find
|
|
|
|
Exit:
|
|
index - index to position in list
|
|
returns a pointer to the property, or NULL if not found
|
|
******************************************************************************/
|
|
|
|
inline PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < elem->nprops; i++)
|
|
if (equal_strings (prop_name, elem->props[i]->name)) {
|
|
*index = i;
|
|
return (elem->props[i]);
|
|
}
|
|
|
|
*index = -1;
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Read an element from an ascii file.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_ptr - pointer to element
|
|
******************************************************************************/
|
|
|
|
inline void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
|
|
{
|
|
int j,k;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
char **words;
|
|
int nwords;
|
|
int which_word;
|
|
char *elem_data,*item=NULL;
|
|
char *item_ptr;
|
|
int item_size;
|
|
int int_val;
|
|
unsigned int uint_val;
|
|
double double_val;
|
|
int list_count;
|
|
int store_it;
|
|
char **store_array;
|
|
char *orig_line;
|
|
char *other_data=NULL;
|
|
int other_flag;
|
|
|
|
/* the kind of element we're reading currently */
|
|
elem = plyfile->which_elem;
|
|
|
|
/* do we need to setup for other_props? */
|
|
|
|
if (elem->other_offset != NO_OTHER_PROPS) {
|
|
char **ptr;
|
|
other_flag = 1;
|
|
/* make room for other_props */
|
|
other_data = (char *) myalloc (elem->other_size);
|
|
/* store pointer in user's structure to the other_props */
|
|
ptr = (char **) (elem_ptr + elem->other_offset);
|
|
*ptr = other_data;
|
|
}
|
|
else
|
|
other_flag = 0;
|
|
|
|
/* read in the element */
|
|
|
|
words = get_words (plyfile->fp, &nwords, &orig_line);
|
|
if (words == NULL) {
|
|
fprintf (stderr, "ply_get_element: unexpected end of file\n");
|
|
exit (-1);
|
|
}
|
|
|
|
which_word = 0;
|
|
|
|
for (j = 0; j < elem->nprops; j++) {
|
|
|
|
prop = elem->props[j];
|
|
store_it = (elem->store_prop[j] | other_flag);
|
|
|
|
/* store either in the user's structure or in other_props */
|
|
// if (elem->store_prop[j])
|
|
elem_data = elem_ptr;
|
|
//else
|
|
//elem_data = other_data;
|
|
|
|
if (prop->is_list) { /* a list */
|
|
|
|
/* get and store the number of items in the list */
|
|
get_ascii_item (words[which_word++], prop->count_external,
|
|
&int_val, &uint_val, &double_val);
|
|
if (store_it) {
|
|
item = elem_data + prop->count_offset;
|
|
store_item(item, prop->count_internal, int_val, uint_val, double_val);
|
|
}
|
|
|
|
/* allocate space for an array of items and store a ptr to the array */
|
|
list_count = int_val;
|
|
item_size = ply_type_size[prop->internal_type];
|
|
store_array = (char **) (elem_data + prop->offset);
|
|
|
|
if (list_count == 0) {
|
|
if (store_it)
|
|
*store_array = NULL;
|
|
}
|
|
else {
|
|
if (store_it) {
|
|
item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
|
|
|
|
item = item_ptr;
|
|
*store_array = item_ptr;
|
|
}
|
|
|
|
/* read items and store them into the array */
|
|
for (k = 0; k < list_count; k++) {
|
|
get_ascii_item (words[which_word++], prop->external_type,
|
|
&int_val, &uint_val, &double_val);
|
|
if (store_it) {
|
|
store_item (item, prop->internal_type,
|
|
int_val, uint_val, double_val);
|
|
item += item_size;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else { /* not a list */
|
|
get_ascii_item (words[which_word++], prop->external_type,
|
|
&int_val, &uint_val, &double_val);
|
|
if (store_it) {
|
|
item = elem_data + prop->offset;
|
|
store_item (item, prop->internal_type, int_val, uint_val, double_val);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
free (words);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Read an element from a binary file.
|
|
|
|
Entry:
|
|
plyfile - file identifier
|
|
elem_ptr - pointer to an element
|
|
******************************************************************************/
|
|
|
|
inline void binary_get_element(PlyFile *plyfile, char *elem_ptr)
|
|
{
|
|
int j,k;
|
|
PlyElement *elem;
|
|
PlyProperty *prop;
|
|
FILE *fp = plyfile->fp;
|
|
char *elem_data,*item=NULL;
|
|
char *item_ptr;
|
|
int item_size;
|
|
int int_val;
|
|
unsigned int uint_val;
|
|
double double_val;
|
|
int list_count;
|
|
int store_it;
|
|
char **store_array;
|
|
char *other_data=NULL;
|
|
int other_flag;
|
|
|
|
/* the kind of element we're reading currently */
|
|
elem = plyfile->which_elem;
|
|
|
|
/* do we need to setup for other_props? */
|
|
|
|
if (elem->other_offset != NO_OTHER_PROPS) {
|
|
char **ptr;
|
|
other_flag = 1;
|
|
/* make room for other_props */
|
|
other_data = (char *) myalloc (elem->other_size);
|
|
/* store pointer in user's structure to the other_props */
|
|
ptr = (char **) (elem_ptr + elem->other_offset);
|
|
*ptr = other_data;
|
|
}
|
|
else
|
|
other_flag = 0;
|
|
|
|
/* read in a number of elements */
|
|
|
|
for (j = 0; j < elem->nprops; j++) {
|
|
|
|
prop = elem->props[j];
|
|
store_it = (elem->store_prop[j] | other_flag);
|
|
|
|
/* store either in the user's structure or in other_props */
|
|
// if (elem->store_prop[j])
|
|
elem_data = elem_ptr;
|
|
// else
|
|
// elem_data = other_data;
|
|
|
|
if (prop->is_list) { /* a list */
|
|
|
|
/* get and store the number of items in the list */
|
|
get_binary_item (fp, plyfile->file_type, prop->count_external,
|
|
&int_val, &uint_val, &double_val);
|
|
if (store_it) {
|
|
item = elem_data + prop->count_offset;
|
|
store_item(item, prop->count_internal, int_val, uint_val, double_val);
|
|
}
|
|
|
|
/* allocate space for an array of items and store a ptr to the array */
|
|
list_count = int_val;
|
|
|
|
item_size = ply_type_size[prop->internal_type];
|
|
store_array = (char **) (elem_data + prop->offset);
|
|
if (list_count == 0) {
|
|
if (store_it)
|
|
*store_array = NULL;
|
|
}
|
|
else {
|
|
if (store_it) {
|
|
item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
|
|
|
|
item = item_ptr;
|
|
*store_array = item_ptr;
|
|
}
|
|
|
|
// read items and store them into the array
|
|
for (k = 0; k < list_count; k++) {
|
|
get_binary_item (fp, plyfile->file_type, prop->external_type,
|
|
&int_val, &uint_val, &double_val);
|
|
if (store_it) {
|
|
store_item (item, prop->internal_type,
|
|
int_val, uint_val, double_val);
|
|
item += item_size;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
else { /* not a list */
|
|
get_binary_item (fp, plyfile->file_type, prop->external_type,
|
|
&int_val, &uint_val, &double_val);
|
|
if (store_it) {
|
|
item = elem_data + prop->offset;
|
|
store_item (item, prop->internal_type, int_val, uint_val, double_val);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Write to a file the word that represents a PLY data type.
|
|
|
|
Entry:
|
|
fp - file pointer
|
|
code - code for type
|
|
******************************************************************************/
|
|
|
|
inline void write_scalar_type (FILE *fp, int code)
|
|
{
|
|
/* make sure this is a valid code */
|
|
|
|
if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
|
|
fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
|
|
exit (-1);
|
|
}
|
|
|
|
/* write the code to a file */
|
|
|
|
fprintf (fp, "%s", type_names[code]);
|
|
}
|
|
|
|
/******************************************************************************
|
|
Reverse the order in an array of bytes. This is the conversion from big
|
|
endian to little endian and vice versa
|
|
|
|
Entry:
|
|
bytes - array of bytes to reverse (in place)
|
|
num_bytes - number of bytes in array
|
|
******************************************************************************/
|
|
|
|
inline void swap_bytes(char *bytes, int num_bytes)
|
|
{
|
|
int i;
|
|
char temp;
|
|
|
|
for (i=0; i < num_bytes/2; i++)
|
|
{
|
|
temp = bytes[i];
|
|
bytes[i] = bytes[(num_bytes-1)-i];
|
|
bytes[(num_bytes-1)-i] = temp;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
Find out if this machine is big endian or little endian
|
|
|
|
Exit:
|
|
set global variable, native_binary_type =
|
|
either PLY_BINARY_BE or PLY_BINARY_LE
|
|
|
|
******************************************************************************/
|
|
|
|
inline void get_native_binary_type()
|
|
{
|
|
endian_test_type test;
|
|
|
|
test.int_value = 0;
|
|
test.int_value = 1;
|
|
if (test.byte_values[0] == 1)
|
|
native_binary_type = PLY_BINARY_LE;
|
|
else if (test.byte_values[sizeof(int)-1] == 1)
|
|
native_binary_type = PLY_BINARY_BE;
|
|
else
|
|
{
|
|
fprintf(stderr, "ply: Couldn't determine machine endianness.\n");
|
|
fprintf(stderr, "ply: Exiting...\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
inline int get_native_binary_type2()
|
|
{
|
|
endian_test_type test;
|
|
|
|
test.int_value = 0;
|
|
test.int_value = 1;
|
|
if (test.byte_values[0] == 1)
|
|
return PLY_BINARY_LE;
|
|
else if (test.byte_values[sizeof(int)-1] == 1)
|
|
return PLY_BINARY_BE;
|
|
else
|
|
{
|
|
fprintf(stderr, "ply: Couldn't determine machine endianness.\n");
|
|
fprintf(stderr, "ply: Exiting...\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
Verify that all the native types are the sizes we need
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
inline void check_types()
|
|
{
|
|
if ((ply_type_size[PLY_CHAR] != sizeof(char)) ||
|
|
(ply_type_size[PLY_SHORT] != sizeof(short)) ||
|
|
(ply_type_size[PLY_INT] != sizeof(int)) ||
|
|
(ply_type_size[PLY_UCHAR] != sizeof(unsigned char)) ||
|
|
(ply_type_size[PLY_USHORT] != sizeof(unsigned short)) ||
|
|
(ply_type_size[PLY_UINT] != sizeof(unsigned int)) ||
|
|
(ply_type_size[PLY_FLOAT] != sizeof(float)) ||
|
|
(ply_type_size[PLY_DOUBLE] != sizeof(double)))
|
|
{
|
|
fprintf(stderr, "ply: Type sizes do not match built-in types\n");
|
|
fprintf(stderr, "ply: Exiting...\n");
|
|
exit(1);
|
|
}
|
|
|
|
types_checked = 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
Get a text line from a file and break it up into words.
|
|
|
|
IMPORTANT: The calling routine call "free" on the returned pointer once
|
|
finished with it.
|
|
|
|
Entry:
|
|
fp - file to read from
|
|
|
|
Exit:
|
|
nwords - number of words returned
|
|
orig_line - the original line of characters
|
|
returns a list of words from the line, or NULL if end-of-file
|
|
******************************************************************************/
|
|
|
|
inline char **get_words(FILE *fp, int *nwords, char **orig_line)
|
|
{
|
|
#define BIG_STRING 4096
|
|
static char str[BIG_STRING];
|
|
static char str_copy[BIG_STRING];
|
|
char **words;
|
|
int max_words = 10;
|
|
int num_words = 0;
|
|
char *ptr,*ptr2;
|
|
char *result;
|
|
|
|
fpos_t pos; //keep track of file pointer
|
|
int nbytes;
|
|
int nonUNIX;
|
|
nonUNIX=0;
|
|
nbytes=0;
|
|
fgetpos(fp, &pos);
|
|
|
|
words = (char **) myalloc (sizeof (char *) * max_words);
|
|
|
|
/* read in a line */
|
|
result = fgets (str, BIG_STRING, fp);
|
|
if (result == NULL) {
|
|
*nwords = 0;
|
|
*orig_line = NULL;
|
|
return (NULL);
|
|
}
|
|
|
|
/* convert line-feed and tabs into spaces */
|
|
/* (this guarentees that there will be a space before the */
|
|
/* null character at the end of the string) */
|
|
|
|
str[BIG_STRING-2] = ' ';
|
|
str[BIG_STRING-1] = '\0';
|
|
|
|
for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
|
|
*ptr2 = *ptr;
|
|
nbytes++;
|
|
if (*ptr == '\t') {
|
|
*ptr = ' ';
|
|
*ptr2 = ' ';
|
|
}
|
|
else if (*ptr == '\n') {
|
|
*ptr = ' '; //has to have a space, to be caught later when grouping words
|
|
*ptr2 = '\0';
|
|
break;
|
|
}
|
|
else if (*ptr == '\r')
|
|
{ //MAC line break
|
|
nonUNIX=1;
|
|
if(*(ptr+1)=='\n') //actuall PC line break
|
|
{
|
|
nbytes++;
|
|
}
|
|
|
|
*ptr = ' ';
|
|
|
|
*(ptr+1) = '\0'; //when reading mac, best end string here
|
|
*ptr2 = '\0'; //note a pc \r is followed by \n
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*check to see if a PC or MAC header was detected instead of UNIX*/
|
|
if(nonUNIX==1)
|
|
{
|
|
fsetpos(fp, &pos);
|
|
fseek(fp, nbytes, SEEK_CUR);
|
|
}
|
|
|
|
/* find the words in the line */
|
|
|
|
ptr = str;
|
|
while (*ptr != '\0') {
|
|
|
|
/* jump over leading spaces */
|
|
while (*ptr == ' ')
|
|
ptr++;
|
|
|
|
/* break if we reach the end */
|
|
if (*ptr == '\0')
|
|
break;
|
|
|
|
/* save pointer to beginning of word */
|
|
if (num_words >= max_words) {
|
|
max_words += 10;
|
|
words = (char **) realloc (words, sizeof (char *) * max_words);
|
|
}
|
|
words[num_words++] = ptr;
|
|
|
|
/* jump over non-spaces */
|
|
while (*ptr != ' ')
|
|
ptr++;
|
|
|
|
/* place a null character here to mark the end of the word */
|
|
*ptr++ = '\0';
|
|
}
|
|
|
|
/* return the list of words */
|
|
*nwords = num_words;
|
|
*orig_line = str_copy;
|
|
return (words);
|
|
}
|
|
|
|
/*
|
|
char **get_words(FILE *fp, int *nwords, char **orig_line)
|
|
{
|
|
#define BIG_STRING 4096
|
|
static char str[BIG_STRING];
|
|
static char str_copy[BIG_STRING];
|
|
char **words;
|
|
int max_words = 10;
|
|
int num_words = 0;
|
|
char *ptr,*ptr2;
|
|
char *result;
|
|
|
|
words = (char **) myalloc (sizeof (char *) * max_words);
|
|
|
|
// read in a line
|
|
result = fgets (str, BIG_STRING, fp);
|
|
if (result == NULL) {
|
|
*nwords = 0;
|
|
*orig_line = NULL;
|
|
return (NULL);
|
|
}
|
|
|
|
// convert line-feed and tabs into spaces
|
|
// (this guarentees that there will be a space before the
|
|
// null character at the end of the string)
|
|
|
|
str[BIG_STRING-2] = ' ';
|
|
str[BIG_STRING-1] = '\0';
|
|
|
|
for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
|
|
*ptr2 = *ptr;
|
|
if (*ptr == '\t') {
|
|
*ptr = ' ';
|
|
*ptr2 = ' ';
|
|
}
|
|
else if (*ptr == '\n') {
|
|
*ptr = ' ';
|
|
*ptr2 = '\0';
|
|
break;
|
|
}
|
|
else if (*ptr == '\r') {
|
|
*ptr = '\0';
|
|
*ptr2 = '\0'; //note dont break yet, on a pc \r is followed by \n
|
|
}
|
|
}
|
|
|
|
// find the words in the line
|
|
|
|
ptr = str;
|
|
while (*ptr != '\0') {
|
|
|
|
// jump over leading spaces
|
|
while (*ptr == ' ')
|
|
ptr++;
|
|
|
|
// break if we reach the end
|
|
if (*ptr == '\0')
|
|
break;
|
|
|
|
// save pointer to beginning of word
|
|
if (num_words >= max_words) {
|
|
max_words += 10;
|
|
words = (char **) realloc (words, sizeof (char *) * max_words);
|
|
}
|
|
words[num_words++] = ptr;
|
|
|
|
// jump over non-spaces
|
|
while (*ptr != ' ')
|
|
ptr++;
|
|
|
|
// place a null character here to mark the end of the word
|
|
*ptr++ = '\0';
|
|
}
|
|
|
|
// return the list of words
|
|
*nwords = num_words;
|
|
*orig_line = str_copy;
|
|
return (words);
|
|
}*/
|
|
|
|
/******************************************************************************
|
|
Return the value of an item, given a pointer to it and its type.
|
|
|
|
Entry:
|
|
item - pointer to item
|
|
type - data type that "item" points to
|
|
|
|
Exit:
|
|
returns a double-precision float that contains the value of the item
|
|
******************************************************************************/
|
|
|
|
inline double get_item_value(char *item, int type)
|
|
{
|
|
unsigned char *puchar;
|
|
char *pchar;
|
|
short int *pshort;
|
|
unsigned short int *pushort;
|
|
int *pint;
|
|
unsigned int *puint;
|
|
float *pfloat;
|
|
double *pdouble;
|
|
int int_value;
|
|
unsigned int uint_value;
|
|
double double_value;
|
|
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
pchar = (char *) item;
|
|
int_value = *pchar;
|
|
return ((double) int_value);
|
|
case PLY_UCHAR:
|
|
puchar = (unsigned char *) item;
|
|
int_value = *puchar;
|
|
return ((double) int_value);
|
|
case PLY_SHORT:
|
|
pshort = (short int *) item;
|
|
int_value = *pshort;
|
|
return ((double) int_value);
|
|
case PLY_USHORT:
|
|
pushort = (unsigned short int *) item;
|
|
int_value = *pushort;
|
|
return ((double) int_value);
|
|
case PLY_INT:
|
|
pint = (int *) item;
|
|
int_value = *pint;
|
|
return ((double) int_value);
|
|
case PLY_UINT:
|
|
puint = (unsigned int *) item;
|
|
uint_value = *puint;
|
|
return ((double) uint_value);
|
|
case PLY_FLOAT:
|
|
pfloat = (float *) item;
|
|
double_value = *pfloat;
|
|
return (double_value);
|
|
case PLY_DOUBLE:
|
|
pdouble = (double *) item;
|
|
double_value = *pdouble;
|
|
return (double_value);
|
|
default:
|
|
fprintf (stderr, "get_item_value: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Write out an item to a file as raw binary bytes.
|
|
|
|
Entry:
|
|
fp - file to write to
|
|
int_val - integer version of item
|
|
uint_val - unsigned integer version of item
|
|
double_val - double-precision float version of item
|
|
type - data type to write out
|
|
******************************************************************************/
|
|
|
|
inline void write_binary_item(
|
|
FILE *fp,
|
|
int file_type,
|
|
int int_val,
|
|
unsigned int uint_val,
|
|
double double_val,
|
|
int type
|
|
)
|
|
{
|
|
unsigned char uchar_val;
|
|
char char_val;
|
|
unsigned short ushort_val;
|
|
short short_val;
|
|
float float_val;
|
|
void *value;
|
|
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
char_val = int_val;
|
|
value = &char_val;
|
|
break;
|
|
case PLY_SHORT:
|
|
short_val = int_val;
|
|
value = &short_val;
|
|
break;
|
|
case PLY_INT:
|
|
value = &int_val;
|
|
break;
|
|
case PLY_UCHAR:
|
|
uchar_val = uint_val;
|
|
value = &uchar_val;
|
|
break;
|
|
case PLY_USHORT:
|
|
ushort_val = uint_val;
|
|
value = &ushort_val;
|
|
break;
|
|
case PLY_UINT:
|
|
value = &uint_val;
|
|
break;
|
|
case PLY_FLOAT:
|
|
float_val = double_val;
|
|
value = &float_val;
|
|
break;
|
|
case PLY_DOUBLE:
|
|
value = &double_val;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "write_binary_item: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
|
|
if ((file_type != native_binary_type) && (ply_type_size[type] > 1))
|
|
swap_bytes((char *)value, ply_type_size[type]);
|
|
|
|
if (fwrite (value, ply_type_size[type], 1, fp) != 1)
|
|
{
|
|
fprintf(stderr, "PLY ERROR: fwrite() failed -- aborting.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Write out an item to a file as ascii characters.
|
|
|
|
Entry:
|
|
fp - file to write to
|
|
int_val - integer version of item
|
|
uint_val - unsigned integer version of item
|
|
double_val - double-precision float version of item
|
|
type - data type to write out
|
|
******************************************************************************/
|
|
|
|
inline void write_ascii_item(
|
|
FILE *fp,
|
|
int int_val,
|
|
unsigned int uint_val,
|
|
double double_val,
|
|
int type
|
|
)
|
|
{
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
case PLY_SHORT:
|
|
case PLY_INT:
|
|
if (fprintf (fp, "%d ", int_val) <= 0)
|
|
{
|
|
fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
case PLY_UCHAR:
|
|
case PLY_USHORT:
|
|
case PLY_UINT:
|
|
if (fprintf (fp, "%u ", uint_val) <= 0)
|
|
{
|
|
fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
case PLY_FLOAT:
|
|
case PLY_DOUBLE:
|
|
if (fprintf (fp, "%g ", double_val) <= 0)
|
|
{
|
|
fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
default:
|
|
fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Write out an item to a file as ascii characters.
|
|
|
|
Entry:
|
|
fp - file to write to
|
|
item - pointer to item to write
|
|
type - data type that "item" points to
|
|
|
|
Exit:
|
|
returns a double-precision float that contains the value of the written item
|
|
******************************************************************************/
|
|
|
|
inline double old_write_ascii_item(FILE *fp, char *item, int type)
|
|
{
|
|
unsigned char *puchar;
|
|
char *pchar;
|
|
short int *pshort;
|
|
unsigned short int *pushort;
|
|
int *pint;
|
|
unsigned int *puint;
|
|
float *pfloat;
|
|
double *pdouble;
|
|
int int_value;
|
|
unsigned int uint_value;
|
|
double double_value;
|
|
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
pchar = (char *) item;
|
|
int_value = *pchar;
|
|
fprintf (fp, "%d ", int_value);
|
|
return ((double) int_value);
|
|
case PLY_UCHAR:
|
|
puchar = (unsigned char *) item;
|
|
int_value = *puchar;
|
|
fprintf (fp, "%d ", int_value);
|
|
return ((double) int_value);
|
|
case PLY_SHORT:
|
|
pshort = (short int *) item;
|
|
int_value = *pshort;
|
|
fprintf (fp, "%d ", int_value);
|
|
return ((double) int_value);
|
|
case PLY_USHORT:
|
|
pushort = (unsigned short int *) item;
|
|
int_value = *pushort;
|
|
fprintf (fp, "%d ", int_value);
|
|
return ((double) int_value);
|
|
case PLY_INT:
|
|
pint = (int *) item;
|
|
int_value = *pint;
|
|
fprintf (fp, "%d ", int_value);
|
|
return ((double) int_value);
|
|
case PLY_UINT:
|
|
puint = (unsigned int *) item;
|
|
uint_value = *puint;
|
|
fprintf (fp, "%u ", uint_value);
|
|
return ((double) uint_value);
|
|
case PLY_FLOAT:
|
|
pfloat = (float *) item;
|
|
double_value = *pfloat;
|
|
fprintf (fp, "%g ", double_value);
|
|
return (double_value);
|
|
case PLY_DOUBLE:
|
|
pdouble = (double *) item;
|
|
double_value = *pdouble;
|
|
fprintf (fp, "%g ", double_value);
|
|
return (double_value);
|
|
default:
|
|
fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Get the value of an item that is in memory, and place the result
|
|
into an integer, an unsigned integer and a double.
|
|
|
|
Entry:
|
|
ptr - pointer to the item
|
|
type - data type supposedly in the item
|
|
|
|
Exit:
|
|
int_val - integer value
|
|
uint_val - unsigned integer value
|
|
double_val - double-precision floating point value
|
|
******************************************************************************/
|
|
|
|
inline void get_stored_item(
|
|
void *ptr,
|
|
int type,
|
|
int *int_val,
|
|
unsigned int *uint_val,
|
|
double *double_val
|
|
)
|
|
{
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
*int_val = *((char *) ptr);
|
|
*uint_val = *int_val;
|
|
*double_val = *int_val;
|
|
break;
|
|
case PLY_UCHAR:
|
|
*uint_val = *((unsigned char *) ptr);
|
|
*int_val = *uint_val;
|
|
*double_val = *uint_val;
|
|
break;
|
|
case PLY_SHORT:
|
|
*int_val = *((short int *) ptr);
|
|
*uint_val = *int_val;
|
|
*double_val = *int_val;
|
|
break;
|
|
case PLY_USHORT:
|
|
*uint_val = *((unsigned short int *) ptr);
|
|
*int_val = *uint_val;
|
|
*double_val = *uint_val;
|
|
break;
|
|
case PLY_INT:
|
|
*int_val = *((int *) ptr);
|
|
*uint_val = *int_val;
|
|
*double_val = *int_val;
|
|
break;
|
|
case PLY_UINT:
|
|
*uint_val = *((unsigned int *) ptr);
|
|
*int_val = *uint_val;
|
|
*double_val = *uint_val;
|
|
break;
|
|
case PLY_FLOAT:
|
|
*double_val = *((float *) ptr);
|
|
*int_val = (int) *double_val;
|
|
*uint_val = (unsigned int) *double_val;
|
|
break;
|
|
case PLY_DOUBLE:
|
|
*double_val = *((double *) ptr);
|
|
*int_val = (int) *double_val;
|
|
*uint_val = (unsigned int) *double_val;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "get_stored_item: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Get the value of an item from a binary file, and place the result
|
|
into an integer, an unsigned integer and a double.
|
|
|
|
Entry:
|
|
fp - file to get item from
|
|
type - data type supposedly in the word
|
|
|
|
Exit:
|
|
int_val - integer value
|
|
uint_val - unsigned integer value
|
|
double_val - double-precision floating point value
|
|
******************************************************************************/
|
|
|
|
inline void get_binary_item(
|
|
FILE *fp,
|
|
int file_type,
|
|
int type,
|
|
int *int_val,
|
|
unsigned int *uint_val,
|
|
double *double_val
|
|
)
|
|
{
|
|
char c[8];
|
|
void *ptr;
|
|
|
|
ptr = (void *) c;
|
|
|
|
if (fread (ptr, ply_type_size[type], 1, fp) != 1)
|
|
{
|
|
fprintf(stderr, "PLY ERROR: fread() failed -- aborting.\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
if ((file_type != native_binary_type) && (ply_type_size[type] > 1))
|
|
swap_bytes((char *)ptr, ply_type_size[type]);
|
|
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
*int_val = *((char *) ptr);
|
|
*uint_val = *int_val;
|
|
*double_val = *int_val;
|
|
break;
|
|
case PLY_UCHAR:
|
|
*uint_val = *((unsigned char *) ptr);
|
|
*int_val = *uint_val;
|
|
*double_val = *uint_val;
|
|
break;
|
|
case PLY_SHORT:
|
|
*int_val = *((short int *) ptr);
|
|
*uint_val = *int_val;
|
|
*double_val = *int_val;
|
|
break;
|
|
case PLY_USHORT:
|
|
*uint_val = *((unsigned short int *) ptr);
|
|
*int_val = *uint_val;
|
|
*double_val = *uint_val;
|
|
break;
|
|
case PLY_INT:
|
|
*int_val = *((int *) ptr);
|
|
*uint_val = *int_val;
|
|
*double_val = *int_val;
|
|
break;
|
|
case PLY_UINT:
|
|
*uint_val = *((unsigned int *) ptr);
|
|
*int_val = *uint_val;
|
|
*double_val = *uint_val;
|
|
break;
|
|
case PLY_FLOAT:
|
|
*double_val = *((float *) ptr);
|
|
*int_val = (int) *double_val;
|
|
*uint_val = (unsigned int) *double_val;
|
|
break;
|
|
case PLY_DOUBLE:
|
|
*double_val = *((double *) ptr);
|
|
*int_val = (int) *double_val;
|
|
*uint_val = (unsigned int) *double_val;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "get_binary_item: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Extract the value of an item from an ascii word, and place the result
|
|
into an integer, an unsigned integer and a double.
|
|
|
|
Entry:
|
|
word - word to extract value from
|
|
type - data type supposedly in the word
|
|
|
|
Exit:
|
|
int_val - integer value
|
|
uint_val - unsigned integer value
|
|
double_val - double-precision floating point value
|
|
******************************************************************************/
|
|
|
|
inline void get_ascii_item(
|
|
char *word,
|
|
int type,
|
|
int *int_val,
|
|
unsigned int *uint_val,
|
|
double *double_val
|
|
)
|
|
{
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
case PLY_UCHAR:
|
|
case PLY_SHORT:
|
|
case PLY_USHORT:
|
|
case PLY_INT:
|
|
*int_val = atoi (word);
|
|
*uint_val = (unsigned int) *int_val;
|
|
*double_val = (double) *int_val;
|
|
break;
|
|
|
|
case PLY_UINT:
|
|
*uint_val = strtol (word, (char **) NULL, 10);
|
|
*int_val = (int) *uint_val;
|
|
*double_val = (double) *uint_val;
|
|
break;
|
|
|
|
case PLY_FLOAT:
|
|
case PLY_DOUBLE:
|
|
*double_val = atof (word);
|
|
*int_val = (int) *double_val;
|
|
*uint_val = (unsigned int) *double_val;
|
|
break;
|
|
|
|
default:
|
|
fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Store a value into a place being pointed to, guided by a data type.
|
|
|
|
Entry:
|
|
item - place to store value
|
|
type - data type
|
|
int_val - integer version of value
|
|
uint_val - unsigned integer version of value
|
|
double_val - double version of value
|
|
|
|
Exit:
|
|
item - pointer to stored value
|
|
******************************************************************************/
|
|
|
|
inline void store_item (
|
|
char *item,
|
|
int type,
|
|
int int_val,
|
|
unsigned int uint_val,
|
|
double double_val
|
|
)
|
|
{
|
|
unsigned char *puchar;
|
|
short int *pshort;
|
|
unsigned short int *pushort;
|
|
int *pint;
|
|
unsigned int *puint;
|
|
float *pfloat;
|
|
double *pdouble;
|
|
|
|
switch (type) {
|
|
case PLY_CHAR:
|
|
*item = int_val;
|
|
break;
|
|
case PLY_UCHAR:
|
|
puchar = (unsigned char *) item;
|
|
*puchar = uint_val;
|
|
break;
|
|
case PLY_SHORT:
|
|
pshort = (short *) item;
|
|
*pshort = int_val;
|
|
break;
|
|
case PLY_USHORT:
|
|
pushort = (unsigned short *) item;
|
|
*pushort = uint_val;
|
|
break;
|
|
case PLY_INT:
|
|
pint = (int *) item;
|
|
*pint = int_val;
|
|
break;
|
|
case PLY_UINT:
|
|
puint = (unsigned int *) item;
|
|
*puint = uint_val;
|
|
break;
|
|
case PLY_FLOAT:
|
|
pfloat = (float *) item;
|
|
*pfloat = double_val;
|
|
break;
|
|
case PLY_DOUBLE:
|
|
pdouble = (double *) item;
|
|
*pdouble = double_val;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "store_item: bad type = %d\n", type);
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Add an element to a PLY file descriptor.
|
|
|
|
Entry:
|
|
plyfile - PLY file descriptor
|
|
words - list of words describing the element
|
|
nwords - number of words in the list
|
|
******************************************************************************/
|
|
|
|
inline void add_element (PlyFile *plyfile, char **words)
|
|
{
|
|
PlyElement *elem;
|
|
|
|
/* create the new element */
|
|
elem = (PlyElement *) myalloc (sizeof (PlyElement));
|
|
elem->name = strdup (words[1]);
|
|
elem->num = atoi (words[2]);
|
|
elem->nprops = 0;
|
|
|
|
/* make room for new element in the object's list of elements */
|
|
if (plyfile->nelems == 0)
|
|
plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
|
|
else
|
|
plyfile->elems = (PlyElement **) realloc (plyfile->elems,
|
|
sizeof (PlyElement *) * (plyfile->nelems + 1));
|
|
|
|
/* add the new element to the object's list */
|
|
plyfile->elems[plyfile->nelems] = elem;
|
|
plyfile->nelems++;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Return the type of a property, given the name of the property.
|
|
|
|
Entry:
|
|
name - name of property type
|
|
|
|
Exit:
|
|
returns integer code for property, or 0 if not found
|
|
******************************************************************************/
|
|
|
|
inline int get_prop_type(char *type_name)
|
|
{
|
|
int i;
|
|
|
|
for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
|
|
if (equal_strings (type_name, type_names[i]))
|
|
return (i);
|
|
|
|
for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
|
|
if (equal_strings (type_name, alt_type_names[i]))
|
|
return (i);
|
|
|
|
/* if we get here, we didn't find the type */
|
|
return (0);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Add a property to a PLY file descriptor.
|
|
|
|
Entry:
|
|
plyfile - PLY file descriptor
|
|
words - list of words describing the property
|
|
nwords - number of words in the list
|
|
******************************************************************************/
|
|
|
|
inline void add_property (PlyFile *plyfile, char **words)
|
|
{
|
|
PlyProperty *prop;
|
|
PlyElement *elem;
|
|
|
|
/* create the new property */
|
|
|
|
prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
|
|
|
|
if (equal_strings (words[1], "list")) { /* is a list */
|
|
prop->count_external = get_prop_type (words[2]);
|
|
prop->external_type = get_prop_type (words[3]);
|
|
prop->name = strdup (words[4]);
|
|
prop->is_list = 1;
|
|
}
|
|
else { /* not a list */
|
|
prop->external_type = get_prop_type (words[1]);
|
|
prop->name = strdup (words[2]);
|
|
prop->is_list = 0;
|
|
}
|
|
|
|
/* add this property to the list of properties of the current element */
|
|
|
|
elem = plyfile->elems[plyfile->nelems - 1];
|
|
|
|
if (elem->nprops == 0)
|
|
elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
|
|
else
|
|
elem->props = (PlyProperty **) realloc (elem->props,
|
|
sizeof (PlyProperty *) * (elem->nprops + 1));
|
|
|
|
elem->props[elem->nprops] = prop;
|
|
elem->nprops++;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Add a comment to a PLY file descriptor.
|
|
|
|
Entry:
|
|
plyfile - PLY file descriptor
|
|
line - line containing comment
|
|
******************************************************************************/
|
|
|
|
inline void add_comment (PlyFile *plyfile, char *line)
|
|
{
|
|
int i;
|
|
|
|
/* skip over "comment" and leading spaces and tabs */
|
|
i = 7;
|
|
while (line[i] == ' ' || line[i] == '\t')
|
|
i++;
|
|
|
|
ply_put_comment (plyfile, &line[i]);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Add a some object information to a PLY file descriptor.
|
|
|
|
Entry:
|
|
plyfile - PLY file descriptor
|
|
line - line containing text info
|
|
******************************************************************************/
|
|
|
|
inline void add_obj_info (PlyFile *plyfile, char *line)
|
|
{
|
|
int i;
|
|
|
|
/* skip over "obj_info" and leading spaces and tabs */
|
|
i = 8;
|
|
while (line[i] == ' ' || line[i] == '\t')
|
|
i++;
|
|
|
|
ply_put_obj_info (plyfile, &line[i]);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Copy a property.
|
|
******************************************************************************/
|
|
|
|
inline void copy_property(PlyProperty *dest, PlyProperty *src)
|
|
{
|
|
dest->name = strdup (src->name);
|
|
dest->external_type = src->external_type;
|
|
dest->internal_type = src->internal_type;
|
|
dest->offset = src->offset;
|
|
|
|
dest->is_list = src->is_list;
|
|
dest->count_external = src->count_external;
|
|
dest->count_internal = src->count_internal;
|
|
dest->count_offset = src->count_offset;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
Allocate some memory.
|
|
|
|
Entry:
|
|
size - amount of memory requested (in bytes)
|
|
lnum - line number from which memory was requested
|
|
fname - file name from which memory was requested
|
|
******************************************************************************/
|
|
|
|
inline char *my_alloc(int size, int lnum, const char *fe)
|
|
{
|
|
char *ptr;
|
|
|
|
ptr = (char *) malloc (size);
|
|
|
|
if (ptr == 0) {
|
|
fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fe);
|
|
}
|
|
|
|
return (ptr);
|
|
}
|
|
|
|
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_point_in_circle = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_POINT_IN_CIRCLE_H
|
|
#define IGL_POINT_IN_CIRCLE_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Determine if 2d point is in a circle
|
|
// Inputs:
|
|
// qx x-coordinate of query point
|
|
// qy y-coordinate of query point
|
|
// cx x-coordinate of circle center
|
|
// cy y-coordinate of circle center
|
|
// r radius of circle
|
|
// Returns true if query point is in circle, false otherwise
|
|
IGL_INLINE bool point_in_circle(
|
|
const double qx,
|
|
const double qy,
|
|
const double cx,
|
|
const double cy,
|
|
const double r);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "point_in_circle.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_point_in_poly = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_POINT_IN_POLY_H
|
|
#define IGL_POINT_IN_POLY_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Determine if 2d point is inside a 2D polygon
|
|
// Inputs:
|
|
// poly vector of polygon points, [0]=x, [1]=y.
|
|
// Polyline need not be closed (i.e. first point != last point),
|
|
// the line segment between last and first selected points is constructed
|
|
// within this function.
|
|
// x x-coordinate of query point
|
|
// y y-coordinate of query point
|
|
// Returns true if query point is in polygon, false otherwise
|
|
// from http://www.visibone.com/inpoly/
|
|
bool IGL_INLINE point_in_poly( const std::vector<std::vector<unsigned int > >&poly,
|
|
const unsigned int xt,
|
|
const unsigned int yt);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "point_in_poly.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_point_mesh_squared_distance = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_POINT_MESH_SQUARED_DISTANCE_H
|
|
#define IGL_POINT_MESH_SQUARED_DISTANCE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Compute distances from a set of points P to a triangle mesh (V,F)
|
|
//
|
|
// Inputs:
|
|
// P #P by 3 list of query point positions
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by (3|2|1) list of (triangle|edge|point) indices
|
|
// Outputs:
|
|
// sqrD #P list of smallest squared distances
|
|
// I #P list of primitive indices corresponding to smallest distances
|
|
// C #P by 3 list of closest points
|
|
//
|
|
// Known bugs: This only computes distances to given primitivess. So
|
|
// unreferenced vertices are ignored. However, degenerate primitives are
|
|
// handled correctly: triangle [1 2 2] is treated as a segment [1 2], and
|
|
// triangle [1 1 1] is treated as a point. So one _could_ add extra
|
|
// combinatorially degenerate rows to Ele for all unreferenced vertices to
|
|
// also get distances to points.
|
|
template <
|
|
typename DerivedP,
|
|
typename DerivedV,
|
|
typename DerivedsqrD,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
IGL_INLINE void point_mesh_squared_distance(
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::MatrixXi & Ele,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "point_mesh_squared_distance.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polar_dec = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_POLAR_DEC
|
|
#define IGL_POLAR_DEC
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Computes the polar decomposition (R,T) of a matrix A
|
|
// Inputs:
|
|
// A 3 by 3 matrix to be decomposed
|
|
// Outputs:
|
|
// R 3 by 3 orthonormal matrix part of decomposition
|
|
// T 3 by 3 stretch matrix part of decomposition
|
|
// U 3 by 3 left-singular vectors
|
|
// S 3 by 1 singular values
|
|
// V 3 by 3 right-singular vectors
|
|
//
|
|
//
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedR,
|
|
typename DerivedT,
|
|
typename DerivedU,
|
|
typename DerivedS,
|
|
typename DerivedV>
|
|
IGL_INLINE void polar_dec(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
Eigen::PlainObjectBase<DerivedR> & R,
|
|
Eigen::PlainObjectBase<DerivedT> & T,
|
|
Eigen::PlainObjectBase<DerivedU> & U,
|
|
Eigen::PlainObjectBase<DerivedS> & S,
|
|
Eigen::PlainObjectBase<DerivedV> & V);
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedR,
|
|
typename DerivedT>
|
|
IGL_INLINE void polar_dec(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
Eigen::PlainObjectBase<DerivedR> & R,
|
|
Eigen::PlainObjectBase<DerivedT> & T);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "polar_dec.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polar_svd = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_POLAR_SVD
|
|
#define IGL_POLAR_SVD
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Computes the polar decomposition (R,T) of a matrix A using SVD singular
|
|
// value decomposition
|
|
//
|
|
// Inputs:
|
|
// A 3 by 3 matrix to be decomposed
|
|
// Outputs:
|
|
// R 3 by 3 rotation matrix part of decomposition (**always rotataion**)
|
|
// T 3 by 3 stretch matrix part of decomposition
|
|
// U 3 by 3 left-singular vectors
|
|
// S 3 by 1 singular values
|
|
// V 3 by 3 right-singular vectors
|
|
//
|
|
//
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedR,
|
|
typename DerivedT,
|
|
typename DerivedU,
|
|
typename DerivedS,
|
|
typename DerivedV>
|
|
IGL_INLINE void polar_svd(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
Eigen::PlainObjectBase<DerivedR> & R,
|
|
Eigen::PlainObjectBase<DerivedT> & T,
|
|
Eigen::PlainObjectBase<DerivedU> & U,
|
|
Eigen::PlainObjectBase<DerivedS> & S,
|
|
Eigen::PlainObjectBase<DerivedV> & V);
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedR,
|
|
typename DerivedT>
|
|
IGL_INLINE void polar_svd(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
Eigen::PlainObjectBase<DerivedR> & R,
|
|
Eigen::PlainObjectBase<DerivedT> & T);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "polar_svd.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polar_svd3x3 = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_POLAR_SVD3X3_H
|
|
#define IGL_POLAR_SVD3X3_H
|
|
#include <Eigen/Core>
|
|
#include "igl_inline.h"
|
|
namespace igl
|
|
{
|
|
// Computes the closest rotation to input matrix A using specialized 3x3 SVD
|
|
// singular value decomposition (WunderSVD3x3)
|
|
//
|
|
// Inputs:
|
|
// A 3 by 3 matrix to be decomposed
|
|
// Outputs:
|
|
// R 3 by 3 closest element in SO(3) (closeness in terms of Frobenius
|
|
// metric)
|
|
//
|
|
// This means that det(R) = 1. Technically it's not polar decomposition
|
|
// which guarantees positive semidefinite stretch factor (at the cost of
|
|
// having det(R) = -1). "• The orthogonal factors U and V will be true
|
|
// rotation matrices..." [McAdams, Selle, Tamstorf, Teran, Sefakis 2011]
|
|
//
|
|
template<typename Mat>
|
|
IGL_INLINE void polar_svd3x3(const Mat& A, Mat& R);
|
|
#ifdef __SSE__
|
|
template<typename T>
|
|
IGL_INLINE void polar_svd3x3_sse(const Eigen::Matrix<T, 3*4, 3>& A, Eigen::Matrix<T, 3*4, 3> &R);
|
|
#endif
|
|
#ifdef __AVX__
|
|
template<typename T>
|
|
IGL_INLINE void polar_svd3x3_avx(const Eigen::Matrix<T, 3*8, 3>& A, Eigen::Matrix<T, 3*8, 3> &R);
|
|
#endif
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "polar_svd3x3.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polygon_mesh_to_triangle_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_POLYGON_MESH_TO_TRIANGLE_MESH_H
|
|
#define IGL_POLYGON_MESH_TO_TRIANGLE_MESH_H
|
|
#include "igl_inline.h"
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Core>
|
|
#endif
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Triangulate a general polygonal mesh into a triangle mesh.
|
|
//
|
|
// Inputs:
|
|
// vF list of polygon index lists
|
|
// Outputs:
|
|
// F eigen int matrix #F by 3
|
|
//
|
|
// Example:
|
|
// vector<vector<double > > vV;
|
|
// vector<vector<int > > vF;
|
|
// read_triangle_mesh("poly.obj",vV,vF);
|
|
// MatrixXd V;
|
|
// MatrixXi F;
|
|
// list_to_matrix(vV,V);
|
|
// triangulate(vF,F);
|
|
template <typename Index, typename DerivedF>
|
|
IGL_INLINE void polygon_mesh_to_triangle_mesh(
|
|
const std::vector<std::vector<Index> > & vF,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
template <typename DerivedP, typename DerivedF>
|
|
IGL_INLINE void polygon_mesh_to_triangle_mesh(
|
|
const Eigen::PlainObjectBase<DerivedP>& P,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "polygon_mesh_to_triangle_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polyroots = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_POLYROOTS
|
|
#define IGL_POLYROOTS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl {
|
|
//todo
|
|
/// Given 2 vectors centered on origin calculate the rotation matrix from first to the second
|
|
|
|
// Inputs:
|
|
// v0, v1 the two #3 by 1 vectors
|
|
// normalized boolean, if false, then the vectors are normalized prior to the calculation
|
|
// Output:
|
|
// 3 by 3 rotation matrix that takes v0 to v1
|
|
//
|
|
template <typename S, typename T>
|
|
IGL_INLINE void polyRoots(Eigen::Matrix<S, Eigen::Dynamic,1> &polyCoeff, //real or comples coefficients
|
|
Eigen::Matrix<std::complex<T>, Eigen::Dynamic,1> &roots // complex roots (double or float)
|
|
);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "polyroots.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_NCHOOSEK) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polyvector_field_comb_from_matchings_and_cuts = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_POLYVECTOR_FIELD_COMB_FROM_MATCHINGS_AND_CUTS
|
|
#define IGL_POLYVECTOR_FIELD_COMB_FROM_MATCHINGS_AND_CUTS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
// Given an mesh, an N- polyvector field with given matchings between
|
|
// the vector sets across interior edges, and corresponding mesh cuts,
|
|
// compute a "combed" polyvector field, i.e.
|
|
// separate the vector set field into N vector fields, where the separation is defined
|
|
// by the matchings. The cuts have previously been generated based on the field
|
|
// singularities, see igl::polyvector_field_cut_mesh_with_singularities.
|
|
// Inputs:
|
|
// V #V by 3 list of the vertex positions
|
|
// F #F by 3 list of the faces (must be triangles)
|
|
// TT #F by 3 triangle to triangle adjacent matrix (e.g. computed
|
|
// via igl:triangle_triangle_adjacency).
|
|
// E2F #E by 2 list of the edge-to-face relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// F2E #F by 3 list of the face-to-edge relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// sol3D #F by 3n list of the 3D coordinates of the per-face vectors of the input vector set field
|
|
// (stacked horizontally for each triangle). Vector #1 in one face does not necessarily match
|
|
// vector #1 in the adjacent face.
|
|
// match_ab #E by N matrix, describing for each edge the matching a->b, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #i of
|
|
// the vector set in a is matched to vector #mab[i] in b)
|
|
// match_ba #E by N matrix, describing for each edge the matching b->a, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #mba[i] of
|
|
// the vector set in a is matched to vector #i in b)
|
|
// cuts #F by 3 list of boolean flags, indicating the edges that need to be cut
|
|
// Outputs:
|
|
// sol3D_combed #F by 3n list of the 3D coordinates of the per-face vectors of the combed vector set field
|
|
// (stacked horizontally for each triangle). Vector #1 in one face will match vector #1 in
|
|
// the adjacent face.
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedTT, typename DerivedS, typename DerivedM, typename DerivedC>
|
|
IGL_INLINE void polyvector_field_comb_from_matchings_and_cuts(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedTT> &TT,
|
|
const Eigen::MatrixXi &E2F,
|
|
const Eigen::MatrixXi &F2E,
|
|
const Eigen::PlainObjectBase<DerivedS> &sol3D,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ab,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ba,
|
|
const Eigen::PlainObjectBase<DerivedC> &cuts,
|
|
Eigen::PlainObjectBase<DerivedS> &sol3D_combed);
|
|
|
|
//Wrapper with only the mesh as input
|
|
template <typename DerivedV, typename DerivedF, typename DerivedS, typename DerivedM, typename DerivedC>
|
|
IGL_INLINE void polyvector_field_comb_from_matchings_and_cuts(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedS> &sol3D,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ab,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ba,
|
|
const Eigen::PlainObjectBase<DerivedC> &cuts,
|
|
Eigen::PlainObjectBase<DerivedS> &sol3D_combed);
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "polyvector_field_comb_from_matchings_and_cuts.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_POLYVECTOR_FIELD_COMB_FROM_MATCHINGS_AND_CUTS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polyvector_field_cut_mesh_with_singularities = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_POLYVECTOR_FIELD_CUT_MESH_WITH_SINGULARITIES
|
|
#define IGL_POLYVECTOR_FIELD_CUT_MESH_WITH_SINGULARITIES
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
// Given a mesh and the singularities of a polyvector field, cut the mesh
|
|
// to disk topology in such a way that the singularities lie at the boundary of
|
|
// the disk, as described in the paper "Mixed Integer Quadrangulation" by
|
|
// Bommes et al. 2009.
|
|
// Inputs:
|
|
// V #V by 3 list of the vertex positions
|
|
// F #F by 3 list of the faces (must be triangles)
|
|
// VF #V list of lists of incident faces (adjacency list), e.g.
|
|
// as returned by igl::vertex_triangle_adjacency
|
|
// VV #V list of lists of incident vertices (adjacency list), e.g.
|
|
// as returned by igl::adjacency_list
|
|
// TT #F by 3 triangle to triangle adjacent matrix (e.g. computed
|
|
// via igl:triangle_triangle_adjacency)
|
|
// TTi #F by 3 adjacent matrix, the element i,j is the id of edge of the
|
|
// triangle TT(i,j) that is adjacent with triangle i (e.g. computed
|
|
// via igl:triangle_triangle_adjacency)
|
|
// singularities #S by 1 list of the indices of the singular vertices
|
|
// Outputs:
|
|
// cuts #F by 3 list of boolean flags, indicating the edges that need to be cut
|
|
// (has 1 at the face edges that are to be cut, 0 otherwise)
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename VFType, typename VVType, typename DerivedTT, typename DerivedC, typename DerivedS>
|
|
IGL_INLINE void polyvector_field_cut_mesh_with_singularities(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const std::vector<std::vector<VFType> >& VF,
|
|
const std::vector<std::vector<VVType> >& VV,
|
|
const Eigen::PlainObjectBase<DerivedTT>& TT,
|
|
const Eigen::PlainObjectBase<DerivedTT>& TTi,
|
|
const Eigen::PlainObjectBase<DerivedS> &singularities,
|
|
Eigen::PlainObjectBase<DerivedC> &cuts);
|
|
|
|
|
|
//Wrapper of the above with only vertices and faces as mesh input
|
|
template <typename DerivedV, typename DerivedF, typename DerivedC, typename DerivedS>
|
|
IGL_INLINE void polyvector_field_cut_mesh_with_singularities(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedS> &singularities,
|
|
Eigen::PlainObjectBase<DerivedC> &cuts);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "polyvector_field_cut_mesh_with_singularities.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_POLYVECTOR_FIELD_CUT_MESH_WITH_SINGULARITIES) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polyvector_field_matchings = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_POLYVECTOR_FIELD_MATCHINGS
|
|
#define IGL_POLYVECTOR_FIELD_MATCHINGS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
// Given a pair of adjacent faces a and b, and a set of N unordered vectors
|
|
// of a vector set defined on each face, the function computes the best order-preserving
|
|
// matching between them, where "best" means "minimum curl", or "smoothest".
|
|
// Inputs:
|
|
// _ua 1 by 3N row vector of the vectors on face a, stacked horizontally
|
|
// _ub 1 by 3N row vector of the vectors on face b, stacked horizontally
|
|
// na 1 by 3, normal of face a
|
|
// nb 1 by 3, normal of face b
|
|
// e 1 by 3, the vector corresponding to the shared edge between a and b
|
|
// match_with_curl boolean flag, determines whether a curl or a smoothness matching will
|
|
// be computed
|
|
// Outputs:
|
|
// mab 1 by N row vector, describing the matching a->b (i.e. vector #i of the
|
|
// vector set in a is matched to vector #mab[i] in b)
|
|
// mba 1 by N row vector, describing the matching b->a (i.e. vector #mba[i]
|
|
// of the vector set in a is matched to vector #i in b)
|
|
//
|
|
template <typename DerivedS, typename DerivedV, typename DerivedM>
|
|
IGL_INLINE void polyvector_field_matching(
|
|
const Eigen::PlainObjectBase<DerivedS>& _ua,
|
|
const Eigen::PlainObjectBase<DerivedS>& _ub,
|
|
const Eigen::PlainObjectBase<DerivedV>& na,
|
|
const Eigen::PlainObjectBase<DerivedV>& nb,
|
|
const Eigen::PlainObjectBase<DerivedV>& e,
|
|
bool match_with_curl,
|
|
Eigen::PlainObjectBase<DerivedM>& mab,
|
|
Eigen::PlainObjectBase<DerivedM>& mba);
|
|
|
|
|
|
// Given a mesh and a vector set field consisting of unordered N-vector sets defined
|
|
// on the faces of the mesh, the function computes, for each (non-boundary) edge
|
|
// the best order-preserving matching between the vector sets of the faces across
|
|
// the edge, where "best" means to "with minimum curl", or "smoothest"
|
|
// Inputs:
|
|
// sol3D #F by 3n list of the 3D coordinates of the per-face vectors
|
|
// (stacked horizontally for each triangle)
|
|
// V #V by 3 list of mesh vertex coordinates
|
|
// F #F by 3 list of mesh faces
|
|
// E #E by 2 list of mesh edges (pairs of vertex indices)
|
|
// FN #F by 3 list of face normals
|
|
// E2F #E by 2 list of the edge-to-face relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// match_with_curl boolean flag, determines whether curl or smoothness matchings will
|
|
// be computed
|
|
// Outputs:
|
|
// match_ab #E by N matrix, describing for each edge the matching a->b, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #i of
|
|
// the vector set in a is matched to vector #mab[i] in b)
|
|
// match_ba #E by N matrix, describing for each edge the matching b->a, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #mba[i] of
|
|
// the vector set in a is matched to vector #i in b)
|
|
// curl the per-edge curl of the matchings (zero for boundary edges)
|
|
// Returns:
|
|
// meanCurl the average of the per-edge curl values (only non-boundary edges are counted)
|
|
//
|
|
template <typename DerivedS, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedM, typename DerivedC>
|
|
IGL_INLINE typename DerivedC::Scalar polyvector_field_matchings(
|
|
const Eigen::PlainObjectBase<DerivedS>& sol3D,
|
|
const Eigen::PlainObjectBase<DerivedV>&V,
|
|
const Eigen::PlainObjectBase<DerivedF>&F,
|
|
const Eigen::PlainObjectBase<DerivedE>&E,
|
|
const Eigen::PlainObjectBase<DerivedV>& FN,
|
|
const Eigen::MatrixXi &E2F,
|
|
bool match_with_curl,
|
|
Eigen::PlainObjectBase<DerivedM>& match_ab,
|
|
Eigen::PlainObjectBase<DerivedM>& match_ba,
|
|
Eigen::PlainObjectBase<DerivedC>& curl);
|
|
|
|
|
|
//Wrapper of the above with only vertices and faces as mesh input
|
|
template <typename DerivedS, typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedC>
|
|
IGL_INLINE typename DerivedC::Scalar polyvector_field_matchings(
|
|
const Eigen::PlainObjectBase<DerivedS>& sol3D,
|
|
const Eigen::PlainObjectBase<DerivedV>&V,
|
|
const Eigen::PlainObjectBase<DerivedF>&F,
|
|
bool match_with_curl,
|
|
Eigen::PlainObjectBase<DerivedM>& match_ab,
|
|
Eigen::PlainObjectBase<DerivedM>& match_ba,
|
|
Eigen::PlainObjectBase<DerivedC>& curl);
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "polyvector_field_matchings.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_POLYVECTOR_FIELD_MATCHINGS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polyvector_field_poisson_reconstruction = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_POLYVECTOR_FIELD_POISSON_RECONSTRUCTION
|
|
#define IGL_POLYVECTOR_FIELD_POISSON_RECONSTRUCTION
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
// Poisson integration on a combed n-polyvector field, defined on a cut mesh.
|
|
// The function finds n new integrable vector fields that are as close as possible to the
|
|
// N-vector fields of the original combed polyvector field. Integrable means
|
|
// that the vector fields are gradients of scalar functions. The deviation from the input
|
|
// field measures how much the input field deviates from integrability.
|
|
// Inputs:
|
|
// Vcut #V by 3 list of the vertex positions
|
|
// Fcut #F by 3 list of the faces (must be triangles)
|
|
// sol3D_combed #F by 3n list of the 3D coordinates of the per-face vectors of the combed vector set field
|
|
// (stacked horizontally for each triangle). Vector #1 in one face will match vector #1 in
|
|
// the adjacent face.
|
|
// Outputs:
|
|
// scalars #V by n list of the per-vertex scalar functions of which the input field
|
|
// is approximately the gradients
|
|
// sol3D_recon #F by 3n list of the 3D coordinates of the per-face vectors of the reconstructed
|
|
// vector set fields (stacked horizontally for each triangle). The fields are the
|
|
// gradients of the scalar functions sF.
|
|
// max_error #V by 1 list of the maximal (across the n vector fields) reconstruction error.
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedSF, typename DerivedS, typename DerivedE>
|
|
IGL_INLINE double polyvector_field_poisson_reconstruction(
|
|
const Eigen::PlainObjectBase<DerivedV> &Vcut,
|
|
const Eigen::PlainObjectBase<DerivedF> &Fcut,
|
|
const Eigen::PlainObjectBase<DerivedS> &sol3D_combed,
|
|
Eigen::PlainObjectBase<DerivedSF> &scalars,
|
|
Eigen::PlainObjectBase<DerivedS> &sol3D_recon,
|
|
Eigen::PlainObjectBase<DerivedE> &max_error );
|
|
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "polyvector_field_poisson_reconstruction.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_POLYVECTOR_FIELD_POISSON_RECONSTRUCTION) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_polyvector_field_singularities_from_matchings = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_POLYVECTOR_FIELD_SINGULARITIES_FROM_MATCHINGS
|
|
#define IGL_POLYVECTOR_FIELD_SINGULARITIES_FROM_MATCHINGS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl {
|
|
|
|
// We are given a polyvector field on a mesh (with N vectors per face), and matchings between the vector sets
|
|
// across all non-boundary edges. The function computes, for the one-ring
|
|
// neighborhood of a given vertex, and for the selected vector of the vector set,
|
|
// the sequence of the vectors that match to it around the one-ring. If the vector that
|
|
// we land on by following the matchings is not the original vector that we started from,
|
|
// the vertex is a singularity.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of the vertex positions
|
|
// F #F by 3 list of the faces (must be triangles)
|
|
// VF #V list of lists of incident faces (adjacency list), e.g.
|
|
// as returned by igl::vertex_triangle_adjacency
|
|
// E2F #E by 2 list of the edge-to-face relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// F2E #F by 3 list of the face-to-edge relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// TT #F by 3 triangle to triangle adjacent matrix (e.g. computed
|
|
// via igl:triangle_triangle_adjacency)
|
|
// match_ab #E by N matrix, describing for each edge the matching a->b, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #i of
|
|
// the vector set in a is matched to vector #mab[i] in b)
|
|
// match_ba #E by N matrix, describing for each edge the matching b->a, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #mba[i] of
|
|
// the vector set in a is matched to vector #i in b)
|
|
// vi the selected one ring
|
|
// vector_id the selected vector of the polyvector
|
|
//
|
|
// Output:
|
|
// mvi #numOneRingFaces by 1 list of the indices of the sequentially matching vectors
|
|
// in the faces of the one ring (first enty is always vector_id, then the vector matching
|
|
// vector_id in the next face, then the vector matching that in the third face etc.)
|
|
// fi #numOneRingFaces by 1 list of the sequentially visited faces in the one ring neighborhood
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedM, typename VFType, typename DerivedTT>
|
|
void polyvector_field_one_ring_matchings(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const std::vector<std::vector<VFType> >& VF,
|
|
const Eigen::MatrixXi& E2F,
|
|
const Eigen::MatrixXi& F2E,
|
|
const Eigen::PlainObjectBase<DerivedTT>& TT,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ab,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ba,
|
|
const int vi,
|
|
const int vector_id,
|
|
Eigen::VectorXi &mvi,
|
|
Eigen::VectorXi &fi);
|
|
|
|
|
|
// Given a polyvector field on a mesh, and matchings between the vector sets
|
|
// across all non-boundary edges, the function computes the singularities of the
|
|
// polyvector field, by computing the one ring matchings.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of the vertex positions
|
|
// F #F by 3 list of the faces (must be triangles)
|
|
// V_border #V by 1 list of booleans, indicating if the corresponging vertex is
|
|
// at the mesh boundary, e.g. as returned by igl::is_border_vertex
|
|
// VF #V list of lists of incident faces (adjacency list), e.g.
|
|
// as returned by igl::vertex_triangle_adjacency
|
|
// TT #F by 3 triangle to triangle adjacent matrix (e.g. computed
|
|
// via igl:triangle_triangle_adjacency)
|
|
// E2F #E by 2 list of the edge-to-face relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// F2E #F by 3 list of the face-to-edge relation (e.g. computed
|
|
// via igl::edge_topology)
|
|
// match_ab #E by N matrix, describing for each edge the matching a->b, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #i of
|
|
// the vector set in a is matched to vector #mab[i] in b)
|
|
// match_ba #E by N matrix, describing for each edge the matching b->a, where a
|
|
// and b are the faces adjacent to the edge (i.e. vector #mba[i] of
|
|
// the vector set in a is matched to vector #i in b)
|
|
//
|
|
// Output:
|
|
// singularities #S by 1 list of the indices of the singular vertices
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedM, typename VFType, typename DerivedS>
|
|
IGL_INLINE void polyvector_field_singularities_from_matchings(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const std::vector<bool> &V_border,
|
|
const std::vector<std::vector<VFType> > &VF,
|
|
const Eigen::MatrixXi &TT,
|
|
const Eigen::MatrixXi &E2F,
|
|
const Eigen::MatrixXi &F2E,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ab,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ba,
|
|
Eigen::PlainObjectBase<DerivedS> &singularities);
|
|
|
|
|
|
// Wrapper with only V,F and the matchings as input
|
|
template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedS>
|
|
IGL_INLINE void polyvector_field_singularities_from_matchings(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ab,
|
|
const Eigen::PlainObjectBase<DerivedM> &match_ba,
|
|
Eigen::PlainObjectBase<DerivedS> &singularities);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "polyvector_field_singularities_from_matchings.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_POLYVECTOR_FIELD_SINGULARITIES_FROM_MATCHINGS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_principal_curvature = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PRINCIPAL_CURVATURE_H
|
|
#define IGL_PRINCIPAL_CURVATURE_H
|
|
|
|
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/Dense>
|
|
|
|
#include <igl/igl_inline.h>
|
|
#include <igl/cotmatrix.h>
|
|
#include <igl/writeOFF.h>
|
|
|
|
|
|
|
|
namespace igl
|
|
{
|
|
|
|
// Compute the principal curvature directions and magnitude of the given triangle mesh
|
|
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
|
|
// DerivedF derived from face indices matrix type: i.e. MatrixXi
|
|
// Inputs:
|
|
// V eigen matrix #V by 3
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// radius controls the size of the neighbourhood used, 1 = average edge lenght
|
|
//
|
|
// Outputs:
|
|
// PD1 #V by 3 maximal curvature direction for each vertex.
|
|
// PD2 #V by 3 minimal curvature direction for each vertex.
|
|
// PV1 #V by 1 maximal curvature value for each vertex.
|
|
// PV2 #V by 1 minimal curvature value for each vertex.
|
|
//
|
|
// See also: average_onto_faces, average_onto_vertices
|
|
//
|
|
// This function has been developed by: Nikolas De Giorgis, Luigi Rocca and Enrico Puppo.
|
|
// The algorithm is based on:
|
|
// Efficient Multi-scale Curvature and Crease Estimation
|
|
// Daniele Panozzo, Enrico Puppo, Luigi Rocca
|
|
// GraVisMa, 2010
|
|
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedPD1,
|
|
typename DerivedPD2,
|
|
typename DerivedPV1,
|
|
typename DerivedPV2>
|
|
IGL_INLINE void principal_curvature(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedPD1>& PD1,
|
|
Eigen::PlainObjectBase<DerivedPD2>& PD2,
|
|
Eigen::PlainObjectBase<DerivedPV1>& PV1,
|
|
Eigen::PlainObjectBase<DerivedPV2>& PV2,
|
|
unsigned radius = 5,
|
|
bool useKring = true);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "principal_curvature.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_print_ijv = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PRINT_IJV_H
|
|
#define IGL_PRINT_IJV_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Prints a 3 column matrix representing [I,J,V] = find(X). That is, each
|
|
// row is the row index, column index and value for each non zero entry. Each
|
|
// row is printed on a new line
|
|
//
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Input:
|
|
// X m by n matrix whose entries are to be sorted
|
|
// offset optional offset for I and J indices {0}
|
|
template <typename T>
|
|
IGL_INLINE void print_ijv(
|
|
const Eigen::SparseMatrix<T>& X,
|
|
const int offset=0);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "print_ijv.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_print_vector = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PRINT_VECTOR_H
|
|
#define IGL_PRINT_VECTOR_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Not clear what these are supposed to be doing. Currently they print
|
|
// vectors to standard error...
|
|
template <typename T>
|
|
IGL_INLINE void print_vector( std::vector<T>& v);
|
|
template <typename T>
|
|
IGL_INLINE void print_vector( std::vector< std::vector<T> >& v);
|
|
template <typename T>
|
|
IGL_INLINE void print_vector(std::vector< std::vector< std::vector<T> > >& v);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "print_vector.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_procrustes = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PROCRUSTES_H
|
|
#define IGL_PROCRUSTES_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Geometry>
|
|
|
|
namespace igl
|
|
{
|
|
// Solve Procrustes problem in d dimensions. Given two point sets X,Y in R^d
|
|
// find best scale s, orthogonal R and translation t s.t. |s*X*R + t - Y|^2
|
|
// is minimized.
|
|
//
|
|
// Templates:
|
|
// DerivedV point type
|
|
// Scalar scalar type
|
|
// DerivedR type of R
|
|
// DerivedT type of t
|
|
// Inputs:
|
|
// X #V by DIM first list of points
|
|
// Y #V by DIM second list of points
|
|
// includeScaling if scaling should be allowed
|
|
// includeReflections if R is allowed to be a reflection
|
|
// Outputs:
|
|
// scale scaling
|
|
// R orthogonal matrix
|
|
// t translation
|
|
//
|
|
// Example:
|
|
// MatrixXd X, Y; (containing 3d points as rows)
|
|
// double scale;
|
|
// MatrixXd R;
|
|
// VectorXd t;
|
|
// igl::procrustes(X,Y,true,false,scale,R,t);
|
|
// R *= scale;
|
|
// MatrixXd Xprime = (X * R).rowwise() + t.transpose();
|
|
//
|
|
template <
|
|
typename DerivedX,
|
|
typename DerivedY,
|
|
typename Scalar,
|
|
typename DerivedR,
|
|
typename DerivedT>
|
|
IGL_INLINE void procrustes(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const Eigen::PlainObjectBase<DerivedY>& Y,
|
|
bool includeScaling,
|
|
bool includeReflections,
|
|
Scalar& scale,
|
|
Eigen::PlainObjectBase<DerivedR>& R,
|
|
Eigen::PlainObjectBase<DerivedT>& t);
|
|
// Same as above but returns Eigen transformation object.
|
|
//
|
|
// Templates:
|
|
// DerivedV point type
|
|
// Scalar scalar type
|
|
// DIM point dimension
|
|
// TType type of transformation
|
|
// (Isometry,Affine,AffineCompact,Projective)
|
|
// Inputs:
|
|
// X #V by DIM first list of points
|
|
// Y #V by DIM second list of points
|
|
// includeScaling if scaling should be allowed
|
|
// includeReflections if R is allowed to be a reflection
|
|
// Outputs:
|
|
// T transformation that minimizes error
|
|
//
|
|
// Example:
|
|
// MatrixXd X, Y; (containing 3d points as rows)
|
|
// AffineCompact3d T;
|
|
// igl::procrustes(X,Y,true,false,T);
|
|
// MatrixXd Xprime = (X * T.linear()).rowwise() + T.translation().transpose();
|
|
template <
|
|
typename DerivedX,
|
|
typename DerivedY,
|
|
typename Scalar,
|
|
int DIM,
|
|
int TType>
|
|
IGL_INLINE void procrustes(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const Eigen::PlainObjectBase<DerivedY>& Y,
|
|
bool includeScaling,
|
|
bool includeReflections,
|
|
Eigen::Transform<Scalar,DIM,TType>& T);
|
|
|
|
|
|
// Convenient wrapper that returns S=scale*R instead of scale and R separately
|
|
template <
|
|
typename DerivedX,
|
|
typename DerivedY,
|
|
typename DerivedR,
|
|
typename DerivedT>
|
|
IGL_INLINE void procrustes(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const Eigen::PlainObjectBase<DerivedY>& Y,
|
|
bool includeScaling,
|
|
bool includeReflections,
|
|
Eigen::PlainObjectBase<DerivedR>& S,
|
|
Eigen::PlainObjectBase<DerivedT>& t);
|
|
|
|
// Convenient wrapper for rigid case (no scaling, no reflections)
|
|
template <
|
|
typename DerivedX,
|
|
typename DerivedY,
|
|
typename DerivedR,
|
|
typename DerivedT>
|
|
IGL_INLINE void procrustes(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const Eigen::PlainObjectBase<DerivedY>& Y,
|
|
Eigen::PlainObjectBase<DerivedR>& R,
|
|
Eigen::PlainObjectBase<DerivedT>& t);
|
|
|
|
// Convenient wrapper for 2D case.
|
|
template <
|
|
typename DerivedX,
|
|
typename DerivedY,
|
|
typename Scalar,
|
|
typename DerivedT>
|
|
IGL_INLINE void procrustes(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const Eigen::PlainObjectBase<DerivedY>& Y,
|
|
Eigen::Rotation2D<Scalar>& R,
|
|
Eigen::PlainObjectBase<DerivedT>& t);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "procrustes.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_project = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PROJECT_H
|
|
#define IGL_PROJECT_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Eigen reimplementation of gluProject
|
|
// Inputs:
|
|
// obj* 3D objects' x, y, and z coordinates respectively
|
|
// model model matrix
|
|
// proj projection matrix
|
|
// viewport viewport vector
|
|
// Returns:
|
|
// screen space x, y, and z coordinates respectively
|
|
template <typename Scalar>
|
|
IGL_INLINE Eigen::Matrix<Scalar,3,1> project(
|
|
const Eigen::Matrix<Scalar,3,1>& obj,
|
|
const Eigen::Matrix<Scalar,4,4>& model,
|
|
const Eigen::Matrix<Scalar,4,4>& proj,
|
|
const Eigen::Matrix<Scalar,4,1>& viewport);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "project.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_project_isometrically_to_plane = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PROJECT_ISOMETRICALLY_TO_PLANE_H
|
|
#define IGL_PROJECT_ISOMETRICALLY_TO_PLANE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Project each triangle to the plane
|
|
//
|
|
// [U,UF,I] = project_isometrically_to_plane(V,F)
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of mesh indices
|
|
// Outputs:
|
|
// U #F*3 by 2 list of triangle positions
|
|
// UF #F by 3 list of mesh indices into U
|
|
// I #V by #F such that I(i,j) = 1 implies U(j,:) corresponds to V(i,:)
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedU,
|
|
typename DerivedUF,
|
|
typename Scalar>
|
|
IGL_INLINE void project_isometrically_to_plane(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedU> & U,
|
|
Eigen::PlainObjectBase<DerivedUF> & UF,
|
|
Eigen::SparseMatrix<Scalar>& I);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "project_isometrically_to_plane.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_project_to_line = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PROJECT_TO_LINE_H
|
|
#define IGL_PROJECT_TO_LINE_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// PROJECT_TO_LINES project points onto vectors, that is find the paramter
|
|
// t for a point p such that proj_p = (y-x).*t, additionally compute the
|
|
// squared distance from p to the line of the vector, such that
|
|
// |p - proj_p|² = sqr_d
|
|
//
|
|
// [T,sqrD] = project_to_lines(P,S,D)
|
|
//
|
|
// Templates:
|
|
// MatP matrix template for P, implementing .cols(), .rows()
|
|
// MatL matrix template for S and D, implementing .size(), .array(), .sum()
|
|
// Matt matrix template for t
|
|
// MatsqrD matrix template for sqrD
|
|
// Inputs:
|
|
// P #P by dim list of points to be projected
|
|
// S size dim start position of line vector
|
|
// D size dim destination position of line vector
|
|
// Outputs:
|
|
// T #P by 1 list of parameters
|
|
// sqrD #P by 1 list of squared distances
|
|
//
|
|
//
|
|
template <
|
|
typename MatP,
|
|
typename MatL,
|
|
typename Matt,
|
|
typename MatsqrD>
|
|
IGL_INLINE void project_to_line(
|
|
const MatP & P,
|
|
const MatL & S,
|
|
const MatL & D,
|
|
Matt & t,
|
|
MatsqrD & sqrD);
|
|
|
|
// Same as above but for a single query point
|
|
template <typename Scalar>
|
|
IGL_INLINE void project_to_line(
|
|
const Scalar px,
|
|
const Scalar py,
|
|
const Scalar pz,
|
|
const Scalar sx,
|
|
const Scalar sy,
|
|
const Scalar sz,
|
|
const Scalar dx,
|
|
const Scalar dy,
|
|
const Scalar dz,
|
|
Scalar & projpx,
|
|
Scalar & projpy,
|
|
Scalar & projpz,
|
|
Scalar & t,
|
|
Scalar & sqrd);
|
|
|
|
// Same as above but for a single query point
|
|
template <typename Scalar>
|
|
IGL_INLINE void project_to_line(
|
|
const Scalar px,
|
|
const Scalar py,
|
|
const Scalar pz,
|
|
const Scalar sx,
|
|
const Scalar sy,
|
|
const Scalar sz,
|
|
const Scalar dx,
|
|
const Scalar dy,
|
|
const Scalar dz,
|
|
Scalar & t,
|
|
Scalar & sqrd);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "project_to_line.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_project_to_line_segment = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PROJECT_TO_LINE_SEGMENT_H
|
|
#define IGL_PROJECT_TO_LINE_SEGMENT_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// PROJECT_TO_LINE_SEGMENT project points onto vectors, that is find the paramter
|
|
// t for a point p such that proj_p = (y-x).*t, additionally compute the
|
|
// squared distance from p to the line of the vector, such that
|
|
// |p - proj_p|² = sqr_d
|
|
//
|
|
// [T,sqrD] = project_to_line_segment(P,S,D)
|
|
//
|
|
// Inputs:
|
|
// P #P by dim list of points to be projected
|
|
// S size dim start position of line vector
|
|
// D size dim destination position of line vector
|
|
// Outputs:
|
|
// T #P by 1 list of parameters
|
|
// sqrD #P by 1 list of squared distances
|
|
//
|
|
//
|
|
template <
|
|
typename DerivedP,
|
|
typename DerivedS,
|
|
typename DerivedD,
|
|
typename Derivedt,
|
|
typename DerivedsqrD>
|
|
IGL_INLINE void project_to_line_segment(
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
const Eigen::PlainObjectBase<DerivedS> & S,
|
|
const Eigen::PlainObjectBase<DerivedD> & D,
|
|
Eigen::PlainObjectBase<Derivedt> & t,
|
|
Eigen::PlainObjectBase<DerivedsqrD> & sqrD);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "project_to_line_segment.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_pseudonormal_test = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PSEUDONORMAL_TEST_H
|
|
#define IGL_PSEUDONORMAL_TEST_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Given a mesh (V,F), a query point q, and a point on (V,F) c, determine
|
|
// whether q is inside (V,F) --> s=-1 or outside (V,F) s=1, based on the
|
|
// sign of the dot product between (q-c) and n, where n is the normal _at c_,
|
|
// carefully chosen according to [Bærentzen & Aanæs 2005]
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// FN #F by 3 list of triangle normals
|
|
// VN #V by 3 list of vertex normals (ANGLE WEIGHTING)
|
|
// EN #E by 3 list of edge normals (UNIFORM WEIGHTING)
|
|
// EMAP #F*3 mapping edges in F to E
|
|
// q Query point
|
|
// i index into F to face to which c belongs
|
|
// c Point on (V,F)
|
|
// Outputs:
|
|
// s sign
|
|
// n normal
|
|
IGL_INLINE void pseudonormal_test(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & FN,
|
|
const Eigen::MatrixXd & VN,
|
|
const Eigen::MatrixXd & EN,
|
|
const Eigen::VectorXi & EMAP,
|
|
const Eigen::RowVector3d & q,
|
|
const int i,
|
|
const Eigen::RowVector3d & c,
|
|
double & s,
|
|
Eigen::RowVector3d & n);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "pseudonormal_test.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_quad_planarity = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_QUAD_PLANARITY_H
|
|
#define IGL_QUAD_PLANARITY_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute planarity of the faces of a quad mesh
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 4 eigen Matrix of face (quad) indices
|
|
// Output:
|
|
// P #F by 1 eigen Matrix of mesh face (quad) planarities
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedP>
|
|
IGL_INLINE void quad_planarity(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedP> & P);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "quad_planarity.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_quat_conjugate = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_QUAT_CONJUGATE_H
|
|
#define IGL_QUAT_CONJUGATE_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Compute conjugate of given quaternion
|
|
// http://en.wikipedia.org/wiki/Quaternion#Conjugation.2C_the_norm.2C_and_reciprocal
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
// Inputs:
|
|
// q1 input quaternion
|
|
// Outputs:
|
|
// out result of conjugation, allowed to be same as input
|
|
template <typename Q_type>
|
|
IGL_INLINE void quat_conjugate(
|
|
const Q_type *q1,
|
|
Q_type *out);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "quat_conjugate.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_quat_mult = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_QUAT_MULT_H
|
|
#define IGL_QUAT_MULT_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Computes out = q1 * q2 with quaternion multiplication
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
// Inputs:
|
|
// q1 left quaternion
|
|
// q2 right quaternion
|
|
// Outputs:
|
|
// out result of multiplication
|
|
template <typename Q_type>
|
|
IGL_INLINE void quat_mult(
|
|
const Q_type *q1,
|
|
const Q_type *q2,
|
|
Q_type *out);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "quat_mult.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_quat_to_axis_angle = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_QUAT_TO_AXIS_ANGLE_H
|
|
#define IGL_QUAT_TO_AXIS_ANGLE_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Convert quat representation of a rotation to axis angle
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
// Inputs:
|
|
// q quaternion
|
|
// Outputs:
|
|
// axis 3d vector
|
|
// angle scalar in radians
|
|
template <typename Q_type>
|
|
IGL_INLINE void quat_to_axis_angle(
|
|
const Q_type *q,
|
|
Q_type *axis,
|
|
Q_type & angle);
|
|
// Wrapper with angle in degrees
|
|
template <typename Q_type>
|
|
IGL_INLINE void quat_to_axis_angle_deg(
|
|
const Q_type *q,
|
|
Q_type *axis,
|
|
Q_type & angle);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "quat_to_axis_angle.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_quat_to_mat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_QUAT_TO_MAT_H
|
|
#define IGL_QUAT_TO_MAT_H
|
|
#include "igl_inline.h"
|
|
// Name history:
|
|
// quat2mat until 16 Sept 2011
|
|
namespace igl
|
|
{
|
|
// Convert a quaternion to a 4x4 matrix
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
// Input:
|
|
// quat pointer to four elements of quaternion (x,y,z,w)
|
|
// Output:
|
|
// mat pointer to 16 elements of matrix
|
|
template <typename Q_type>
|
|
IGL_INLINE void quat_to_mat(const Q_type * quat, Q_type * mat);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "quat_to_mat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_quats_to_column = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_QUATS_TO_COLUMN_H
|
|
#define IGL_QUATS_TO_COLUMN_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/StdVector>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// "Columnize" a list of quaternions (q1x,q1y,q1z,q1w,q2x,q2y,q2z,q2w,...)
|
|
//
|
|
// Inputs:
|
|
// vQ n-long list of quaternions
|
|
// Outputs:
|
|
// Q n*4-long list of coefficients
|
|
IGL_INLINE void quats_to_column(
|
|
const std::vector<
|
|
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > vQ,
|
|
Eigen::VectorXd & Q);
|
|
IGL_INLINE Eigen::VectorXd quats_to_column(
|
|
const std::vector<
|
|
Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > vQ);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "quats_to_column.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_random_dir = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_RANDOM_DIR_H
|
|
#define IGL_RANDOM_DIR_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Generate a uniformly random unit direction in 3D, return as vector
|
|
IGL_INLINE Eigen::Vector3d random_dir();
|
|
// Generate n stratified uniformly random unit directions in 3d, return as rows
|
|
// of an n by 3 matrix
|
|
//
|
|
// Inputs:
|
|
// n number of directions
|
|
// Return n by 3 matrix of random directions
|
|
IGL_INLINE Eigen::MatrixXd random_dir_stratified(const int n);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "random_dir.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_random_points_on_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_RANDOM_POINTS_ON_MESH_H
|
|
#define IGL_RANDOM_POINTS_ON_MESH_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// RANDOM_POINTS_ON_MESH Randomly sample a mesh (V,F) n times.
|
|
//
|
|
// Inputs:
|
|
// n number of samples
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by 3 list of mesh triangle indices
|
|
// Outputs:
|
|
// B n by #V list of barycentric coordinates such that each row i has
|
|
// three nonzero entries hoding barycentric corridinates of the point.
|
|
// FI n list of indices into F
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedB, typename DerivedFI>
|
|
IGL_INLINE void random_points_on_mesh(
|
|
const int n,
|
|
const Eigen::PlainObjectBase<DerivedV > & V,
|
|
const Eigen::PlainObjectBase<DerivedF > & F,
|
|
Eigen::PlainObjectBase<DerivedB > & B,
|
|
Eigen::PlainObjectBase<DerivedFI > & FI);
|
|
template <typename DerivedV, typename DerivedF, typename ScalarB, typename DerivedFI>
|
|
IGL_INLINE void random_points_on_mesh(
|
|
const int n,
|
|
const Eigen::PlainObjectBase<DerivedV > & V,
|
|
const Eigen::PlainObjectBase<DerivedF > & F,
|
|
Eigen::SparseMatrix<ScalarB > & B,
|
|
Eigen::PlainObjectBase<DerivedFI > & FI);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "random_points_on_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_random_quaternion = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_RANDOM_QUATERNION_H
|
|
#define IGL_RANDOM_QUATERNION_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Geometry>
|
|
namespace igl
|
|
{
|
|
// Return a random quaternion via uniform sampling of the 4-sphere
|
|
template <typename Scalar>
|
|
IGL_INLINE Eigen::Quaternion<Scalar> random_quaternion();
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "random_quaternion.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_randperm = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_RANDPERM_H
|
|
#define IGL_RANDPERM_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Like matlab's randperm(n) but minus 1
|
|
//
|
|
// Inputs:
|
|
// n number of elements
|
|
// Outputs:
|
|
// I n list of rand permutation of 0:n-1
|
|
template <typename DerivedI>
|
|
IGL_INLINE void randperm(
|
|
const int n,
|
|
Eigen::PlainObjectBase<DerivedI> & I);
|
|
template <typename DerivedI>
|
|
IGL_INLINE Eigen::PlainObjectBase<DerivedI> randperm( const int n);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "randperm.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ray_sphere_intersect = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_RAY_SPHERE_INTERSECT_H
|
|
#define IGL_RAY_SPHERE_INTERSECT_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Compute the intersection between a ray from O in direction D and a sphere
|
|
// centered at C with radius r
|
|
//
|
|
// Inputs:
|
|
// o origin of ray
|
|
// d direction of ray
|
|
// c center of sphere
|
|
// r radius of sphere
|
|
// Outputs:
|
|
// t0 parameterization of first hit (set only if exists) so that hit
|
|
// position = o + t0*d
|
|
// t1 parameterization of second hit (set only if exists)
|
|
//
|
|
// Returns the number of hits
|
|
template <
|
|
typename Derivedo,
|
|
typename Derivedd,
|
|
typename Derivedc,
|
|
typename r_type,
|
|
typename t_type>
|
|
IGL_INLINE int ray_sphere_intersect(
|
|
const Eigen::PlainObjectBase<Derivedo> & o,
|
|
const Eigen::PlainObjectBase<Derivedd> & d,
|
|
const Eigen::PlainObjectBase<Derivedc> & c,
|
|
r_type r,
|
|
t_type & t0,
|
|
t_type & t1);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "ray_sphere_intersect.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_read_triangle_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READ_TRIANGLE_MESH_H
|
|
#define IGL_READ_TRIANGLE_MESH_H
|
|
#include "igl_inline.h"
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Core>
|
|
#endif
|
|
#include <string>
|
|
#include <vector>
|
|
// History:
|
|
// renamed read -> read_triangle_mesh Daniele 24 June 2014
|
|
// return type changed from void to bool Alec 18 Sept 2011
|
|
|
|
namespace igl
|
|
{
|
|
// read mesh from an ascii file with automatic detection of file format.
|
|
// supported: obj, off, stl, wrl, ply, mesh)
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Index type for indices (will be read as int and cast to Index)
|
|
// Inputs:
|
|
// str path to file
|
|
// Outputs:
|
|
// V eigen double matrix #V by 3
|
|
// F eigen int matrix #F by 3
|
|
// Returns true iff success
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool read_triangle_mesh(
|
|
const std::string str,
|
|
std::vector<std::vector<Scalar> > & V,
|
|
std::vector<std::vector<Index> > & F);
|
|
#ifndef IGL_NO_EIGEN
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool read_triangle_mesh(
|
|
const std::string str,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
// Outputs:
|
|
// dir directory path (see pathinfo.h)
|
|
// base base name (see pathinfo.h)
|
|
// ext extension (see pathinfo.h)
|
|
// name filename (see pathinfo.h)
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool read_triangle_mesh(
|
|
const std::string str,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::string & dir,
|
|
std::string & base,
|
|
std::string & ext,
|
|
std::string & name);
|
|
#endif
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "read_triangle_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readCSV = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READ_CSV_H
|
|
#define IGL_READ_CSV_H
|
|
|
|
#include "igl/igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// read a matrix from a csv file into a Eigen matrix
|
|
// Templates:
|
|
// Scalar type for the matrix
|
|
// Inputs:
|
|
// str path to .csv file
|
|
// Outputs:
|
|
// M eigen matrix
|
|
template <typename Scalar>
|
|
IGL_INLINE bool readCSV(
|
|
const std::string str,
|
|
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>& M);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readCSV.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readDMAT = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READDMAT_H
|
|
#define IGL_READDMAT_H
|
|
#include "igl_inline.h"
|
|
// .dmat is a simple ascii matrix file type, defined as follows. The first line
|
|
// is always:
|
|
// <#columns> <#rows>
|
|
// Then the coefficients of the matrix are given separated by whitespace with
|
|
// columns running fastest.
|
|
//
|
|
// Example:
|
|
// The matrix m = [1 2 3; 4 5 6];
|
|
// corresponds to a .dmat file containing:
|
|
// 3 2
|
|
// 1 4 2 5 3 6
|
|
#include <string>
|
|
#include <vector>
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Core>
|
|
#endif
|
|
namespace igl
|
|
{
|
|
// Read a matrix from an ascii dmat file
|
|
//
|
|
// Inputs:
|
|
// file_name path to .dmat file
|
|
// Outputs:
|
|
// W eigen matrix containing read-in coefficients
|
|
// Returns true on success, false on error
|
|
//
|
|
#ifndef IGL_NO_EIGEN
|
|
template <typename DerivedW>
|
|
IGL_INLINE bool readDMAT(const std::string file_name,
|
|
Eigen::PlainObjectBase<DerivedW> & W);
|
|
#endif
|
|
// Wrapper for vector of vectors
|
|
template <typename Scalar>
|
|
IGL_INLINE bool readDMAT(
|
|
const std::string file_name,
|
|
std::vector<std::vector<Scalar> > & W);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readDMAT.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readMESH = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READMESH_H
|
|
#define IGL_READMESH_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// load a tetrahedral volume mesh from a .mesh file
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Index type for indices (will be read as int and cast to Index)
|
|
// Input:
|
|
// mesh_file_name path of .mesh file
|
|
// Outputs:
|
|
// V double matrix of vertex positions #V by 3
|
|
// T #T list of tet indices into vertex positions
|
|
// F #F list of face indices into vertex positions
|
|
//
|
|
// Known bugs: Holes and regions are not supported
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool readMESH(
|
|
const std::string mesh_file_name,
|
|
std::vector<std::vector<Scalar > > & V,
|
|
std::vector<std::vector<Index > > & T,
|
|
std::vector<std::vector<Index > > & F);
|
|
|
|
// Input:
|
|
// mesh_file_name path of .mesh file
|
|
// Outputs:
|
|
// V eigen double matrix #V by 3
|
|
// T eigen int matrix #T by 4
|
|
// F eigen int matrix #F by 3
|
|
template <typename DerivedV, typename DerivedF, typename DerivedT>
|
|
IGL_INLINE bool readMESH(
|
|
const std::string mesh_file_name,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedT>& T,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readMESH.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readNODE = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READNODE_H
|
|
#define IGL_READNODE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// load a list of points from a .node file
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Index type for indices (will be read as int and cast to Index)
|
|
// Input:
|
|
// node_file_name path of .node file
|
|
// Outputs:
|
|
// V double matrix of vertex positions #V by dim
|
|
// I list of indices (first tells whether 0 or 1 indexed)
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool readNODE(
|
|
const std::string node_file_name,
|
|
std::vector<std::vector<Scalar > > & V,
|
|
std::vector<std::vector<Index > > & I);
|
|
|
|
// Input:
|
|
// node_file_name path of .node file
|
|
// Outputs:
|
|
// V eigen double matrix #V by dim
|
|
template <typename DerivedV, typename DerivedI>
|
|
IGL_INLINE bool readNODE(
|
|
const std::string node_file_name,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedI>& I);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readNODE.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readOBJ = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READOBJ_H
|
|
#define IGL_READOBJ_H
|
|
#include "igl_inline.h"
|
|
#include "deprecated.h"
|
|
// History:
|
|
// return type changed from void to bool Alec 18 Sept 2011
|
|
// added pure vector of vectors version that has much more support Alec 31 Oct
|
|
// 2011
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Core>
|
|
#endif
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Read a mesh from an ascii obj file, filling in vertex positions, normals
|
|
// and texture coordinates. Mesh may have faces of any number of degree
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Index type for indices (will be read as int and cast to Index)
|
|
// Inputs:
|
|
// str path to .obj file
|
|
// Outputs:
|
|
// V double matrix of vertex positions #V by 3
|
|
// TC double matrix of texture coordinats #TC by 2
|
|
// N double matrix of corner normals #N by 3
|
|
// F #F list of face indices into vertex positions
|
|
// FTC #F list of face indices into vertex texture coordinates
|
|
// FN #F list of face indices into vertex normals
|
|
// Returns true on success, false on errors
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool readOBJ(
|
|
const std::string obj_file_name,
|
|
std::vector<std::vector<Scalar > > & V,
|
|
std::vector<std::vector<Scalar > > & TC,
|
|
std::vector<std::vector<Scalar > > & N,
|
|
std::vector<std::vector<Index > > & F,
|
|
std::vector<std::vector<Index > > & FTC,
|
|
std::vector<std::vector<Index > > & FN);
|
|
// Just V and F
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool readOBJ(
|
|
const std::string obj_file_name,
|
|
std::vector<std::vector<Scalar > > & V,
|
|
std::vector<std::vector<Index > > & F);
|
|
#ifndef IGL_NO_EIGEN
|
|
// Eigen Wrappers. These will return true only if the data is perfectly
|
|
// "rectangular": All faces are the same degree, all have the same number of
|
|
// textures/normals etc.
|
|
template <typename DerivedV, typename DerivedF, typename DerivedT>
|
|
IGL_INLINE bool readOBJ(
|
|
const std::string str,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedT>& TC,
|
|
Eigen::PlainObjectBase<DerivedV>& CN,
|
|
Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedF>& FTC,
|
|
Eigen::PlainObjectBase<DerivedF>& FN);
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool readOBJ(
|
|
const std::string str,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readOBJ.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readOFF = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READOFF_H
|
|
#define IGL_READOFF_H
|
|
#include "igl_inline.h"
|
|
// History:
|
|
// return type changed from void to bool Alec 18 Sept 2011
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Core>
|
|
#endif
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
|
|
// Read a mesh from an ascii obj file, filling in vertex positions, normals
|
|
// and texture coordinates. Mesh may have faces of any number of degree
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Index type for indices (will be read as int and cast to Index)
|
|
// Inputs:
|
|
// str path to .obj file
|
|
// Outputs:
|
|
// V double matrix of vertex positions #V by 3
|
|
// F #F list of face indices into vertex positions
|
|
// TC double matrix of texture coordinats #TC by 2
|
|
// FTC #F list of face indices into vertex texture coordinates
|
|
// N double matrix of corner normals #N by 3
|
|
// FN #F list of face indices into vertex normals
|
|
// Returns true on success, false on errors
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool readOFF(
|
|
const std::string off_file_name,
|
|
std::vector<std::vector<Scalar > > & V,
|
|
std::vector<std::vector<Index > > & F,
|
|
std::vector<std::vector<Scalar > > & N);
|
|
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
// read mesh from a ascii off file
|
|
// Inputs:
|
|
// str path to .off file
|
|
// Outputs:
|
|
// V eigen double matrix #V by 3
|
|
// F eigen int matrix #F by 3
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool readOFF(
|
|
const std::string str,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool readOFF(
|
|
const std::string str,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedV>& N);
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readOFF.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readPLY = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READPLY_H
|
|
#define IGL_READPLY_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Read a mesh from a .ply file.
|
|
//
|
|
// Inputs:
|
|
// filename path to .ply file
|
|
// Outputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F list of lists of triangle indices
|
|
// N #V by 3 list of vertex normals
|
|
// UV #V by 2 list of vertex texture coordinates
|
|
// Returns true iff success
|
|
template <
|
|
typename Vtype,
|
|
typename Ftype,
|
|
typename Ntype,
|
|
typename UVtype>
|
|
IGL_INLINE bool readPLY(
|
|
const std::string & filename,
|
|
std::vector<std::vector<Vtype> > & V,
|
|
std::vector<std::vector<Ftype> > & F,
|
|
std::vector<std::vector<Ntype> > & N,
|
|
std::vector<std::vector<UVtype> > & UV);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedUV>
|
|
IGL_INLINE bool readPLY(
|
|
const std::string & filename,
|
|
Eigen::PlainObjectBase<DerivedV> & V,
|
|
Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedN> & N,
|
|
Eigen::PlainObjectBase<DerivedUV> & UV);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF>
|
|
IGL_INLINE bool readPLY(
|
|
const std::string & filename,
|
|
Eigen::PlainObjectBase<DerivedV> & V,
|
|
Eigen::PlainObjectBase<DerivedF> & F);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readPLY.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readSTL = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READSTL_H
|
|
#define IGL_READSTL_H
|
|
#include "igl_inline.h"
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Core>
|
|
#endif
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Read a mesh from an ascii/binary stl file.
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Inputs:
|
|
// filename path to .obj file
|
|
// Outputs:
|
|
// V double matrix of vertex positions #F*3 by 3
|
|
// F index matrix of triangle indices #F by 3
|
|
// N double matrix of vertex positions #F by 3
|
|
// Returns true on success, false on errors
|
|
//
|
|
// Example:
|
|
// bool success = readSTL(filename,temp_V,F,N);
|
|
// remove_duplicate_vertices(temp_V,0,V,SVI,SVJ);
|
|
// for_each(F.data(),F.data()+F.size(),[&SVJ](int & f){f=SVJ(f);});
|
|
// writeOBJ("Downloads/cat.obj",V,F);
|
|
template <typename DerivedV, typename DerivedF, typename DerivedN>
|
|
IGL_INLINE bool readSTL(
|
|
const std::string & filename,
|
|
Eigen::PlainObjectBase<DerivedV> & V,
|
|
Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedN> & N);
|
|
template <typename TypeV, typename TypeF, typename TypeN>
|
|
IGL_INLINE bool readSTL(
|
|
const std::string & filename,
|
|
std::vector<std::vector<TypeV> > & V,
|
|
std::vector<std::vector<TypeF> > & F,
|
|
std::vector<std::vector<TypeN> > & N);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readSTL.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readTGF = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READTGF_H
|
|
#define IGL_READTGF_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#ifndef IGL_NO_EIGEN
|
|
#include <Eigen/Dense>
|
|
#endif
|
|
|
|
namespace igl
|
|
{
|
|
// READTGF
|
|
//
|
|
// [V,E,P,BE,CE,PE] = readTGF(filename)
|
|
//
|
|
// Read a graph from a .tgf file
|
|
//
|
|
// Input:
|
|
// filename .tgf file name
|
|
// Ouput:
|
|
// V # vertices by 3 list of vertex positions
|
|
// E # edges by 2 list of edge indices
|
|
// P # point-handles list of point handle indices
|
|
// BE # bone-edges by 2 list of bone-edge indices
|
|
// CE # cage-edges by 2 list of cage-edge indices
|
|
// PE # pseudo-edges by 2 list of pseudo-edge indices
|
|
//
|
|
// Assumes that graph vertices are 3 dimensional
|
|
IGL_INLINE bool readTGF(
|
|
const std::string tgf_filename,
|
|
std::vector<std::vector<double> > & C,
|
|
std::vector<std::vector<int> > & E,
|
|
std::vector<int> & P,
|
|
std::vector<std::vector<int> > & BE,
|
|
std::vector<std::vector<int> > & CE,
|
|
std::vector<std::vector<int> > & PE);
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
IGL_INLINE bool readTGF(
|
|
const std::string tgf_filename,
|
|
Eigen::MatrixXd & C,
|
|
Eigen::MatrixXi & E,
|
|
Eigen::VectorXi & P,
|
|
Eigen::MatrixXi & BE,
|
|
Eigen::MatrixXi & CE,
|
|
Eigen::MatrixXi & PE);
|
|
IGL_INLINE bool readTGF(
|
|
const std::string tgf_filename,
|
|
Eigen::MatrixXd & C,
|
|
Eigen::MatrixXi & E);
|
|
#endif
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readTGF.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_readWRL = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_READWRL_H
|
|
#define IGL_READWRL_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Read a mesh from an ascii wrl file, filling in vertex positions and face
|
|
// indices of the first model. Mesh may have faces of any number of degree
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Index type for indices (will be read as int and cast to Index)
|
|
// Inputs:
|
|
// str path to .wrl file
|
|
// Outputs:
|
|
// V double matrix of vertex positions #V by 3
|
|
// F #F list of face indices into vertex positions
|
|
// Returns true on success, false on errors
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool readWRL(
|
|
const std::string wrl_file_name,
|
|
std::vector<std::vector<Scalar > > & V,
|
|
std::vector<std::vector<Index > > & F);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "readWRL.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_REDRUM = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_REDRUM_H
|
|
#define IGL_REDRUM_H
|
|
|
|
// Q: These should probably be inside the igl namespace. What's the correct
|
|
// way to do that?
|
|
// A: I guess the right way is to not use a macro but a proper function with
|
|
// streams as input and output.
|
|
|
|
// ANSI color codes for formating iostream style output
|
|
|
|
#ifdef IGL_REDRUM_NOOP
|
|
|
|
// Bold Red, etc.
|
|
#define NORUM(X) X
|
|
#define REDRUM(X) X
|
|
#define GREENRUM(X) X
|
|
#define YELLOWRUM(X) X
|
|
#define BLUERUM(X) X
|
|
#define MAGENTARUM(X) X
|
|
#define CYANRUM(X) X
|
|
// Regular Red, etc.
|
|
#define REDGIN(X) X
|
|
#define GREENGIN(X) X
|
|
#define YELLOWGIN(X) X
|
|
#define BLUEGIN(X) X
|
|
#define MAGENTAGIN(X) X
|
|
#define CYANGIN(X) X
|
|
|
|
#else
|
|
|
|
// Bold Red, etc.
|
|
#define NORUM(X) ""<<X<<""
|
|
#define REDRUM(X) "\e[1m\e[31m"<<X<<"\e[m"
|
|
#define GREENRUM(X) "\e[1m\e[32m"<<X<<"\e[m"
|
|
#define YELLOWRUM(X) "\e[1m\e[33m"<<X<<"\e[m"
|
|
#define BLUERUM(X) "\e[1m\e[34m"<<X<<"\e[m"
|
|
#define MAGENTARUM(X) "\e[1m\e[35m"<<X<<"\e[m"
|
|
#define CYANRUM(X) "\e[1m\e[36m"<<X<<"\e[m"
|
|
// Regular Red, etc.
|
|
#define REDGIN(X) "\e[31m"<<X<<"\e[m"
|
|
#define GREENGIN(X) "\e[32m"<<X<<"\e[m"
|
|
#define YELLOWGIN(X) "\e[33m"<<X<<"\e[m"
|
|
#define BLUEGIN(X) "\e[34m"<<X<<"\e[m"
|
|
#define MAGENTAGIN(X) "\e[35m"<<X<<"\e[m"
|
|
#define CYANGIN(X) "\e[36m"<<X<<"\e[m"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_remove_duplicate_vertices = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_REMOVE_DUPLICATE_VERTICES_H
|
|
#define IGL_REMOVE_DUPLICATE_VERTICES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// REMOVE_DUPLICATE_VERTICES Remove duplicate vertices upto a uniqueness
|
|
// tolerance (epsilon)
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// epsilon uniqueness tolerance (significant digit), can probably think of
|
|
// this as a tolerance on L1 distance
|
|
// Outputs:
|
|
// SV #SV by dim new list of vertex positions
|
|
// SVI #V by 1 list of indices so SV = V(SVI,:)
|
|
// SVJ #SV by 1 list of indices so V = SV(SVJ,:)
|
|
//
|
|
// Example:
|
|
// % Mesh in (V,F)
|
|
// [SV,SVI,SVJ] = remove_duplicate_vertices(V,1e-7);
|
|
// % remap faces
|
|
// SF = SVJ(F);
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedSV,
|
|
typename DerivedSVI,
|
|
typename DerivedSVJ>
|
|
IGL_INLINE void remove_duplicate_vertices(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const double epsilon,
|
|
Eigen::PlainObjectBase<DerivedSV>& SV,
|
|
Eigen::PlainObjectBase<DerivedSVI>& SVI,
|
|
Eigen::PlainObjectBase<DerivedSVJ>& SVJ);
|
|
// Wrapper that also remaps given faces (F) --> (SF) so that SF index SV
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedSV,
|
|
typename DerivedSVI,
|
|
typename DerivedSVJ,
|
|
typename DerivedSF>
|
|
IGL_INLINE void remove_duplicate_vertices(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const double epsilon,
|
|
Eigen::PlainObjectBase<DerivedSV>& SV,
|
|
Eigen::PlainObjectBase<DerivedSVI>& SVI,
|
|
Eigen::PlainObjectBase<DerivedSVJ>& SVJ,
|
|
Eigen::PlainObjectBase<DerivedSF>& SF);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "remove_duplicate_vertices.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_remove_duplicates = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_REMOVE_DUPLICATES_H
|
|
#define IGL_REMOVE_DUPLICATES_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// [ NV, NF ] = remove_duplicates( V,F,epsilon )
|
|
// Merge the duplicate vertices from V, fixing the topology accordingly
|
|
//
|
|
// Input:
|
|
// V,F: mesh description
|
|
// epsilon: minimal distance to consider two vertices identical
|
|
//
|
|
// Output:
|
|
// NV, NF: new mesh without duplicate vertices
|
|
|
|
// template <typename T, typename S>
|
|
// IGL_INLINE void remove_duplicates(
|
|
// const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
|
|
// const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &F,
|
|
// Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &NV,
|
|
// Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &NF,
|
|
// Eigen::Matrix<S, Eigen::Dynamic, 1> &I,
|
|
// const double epsilon = 2.2204e-15);
|
|
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE void remove_duplicates(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
Eigen::PlainObjectBase<DerivedV> &NV,
|
|
Eigen::PlainObjectBase<DerivedF> &NF,
|
|
Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 1> &I,
|
|
const double epsilon = 2.2204e-15);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "remove_duplicates.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_remove_unreferenced = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
//
|
|
// remove_unreferenced.h
|
|
// Preview3D
|
|
//
|
|
// Created by Daniele Panozzo on 17/11/11.
|
|
|
|
#ifndef IGL_REMOVE_UNREFERENCED_H
|
|
#define IGL_REMOVE_UNREFERENCED_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Remove unreferenced vertices from V, updating F accordingly
|
|
//
|
|
// Input:
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by ss list of simplices (Values of -1 are quitely skipped)
|
|
// Outputs:
|
|
// NV #NV by dim list of mesh vertex positions
|
|
// NF #NF by ss list of simplices
|
|
// IM #V by 1 list of indices such that: NF = IM(F) and NT = IM(T)
|
|
// and V(find(IM<=size(NV,1)),:) = NV
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedNV,
|
|
typename DerivedNF,
|
|
typename DerivedI>
|
|
IGL_INLINE void remove_unreferenced(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
Eigen::PlainObjectBase<DerivedNV> &NV,
|
|
Eigen::PlainObjectBase<DerivedNF> &NF,
|
|
Eigen::PlainObjectBase<DerivedI> &I);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedNV,
|
|
typename DerivedNF,
|
|
typename DerivedI,
|
|
typename DerivedJ>
|
|
IGL_INLINE void remove_unreferenced(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
Eigen::PlainObjectBase<DerivedNV> &NV,
|
|
Eigen::PlainObjectBase<DerivedNF> &NF,
|
|
Eigen::PlainObjectBase<DerivedI> &I,
|
|
Eigen::PlainObjectBase<DerivedJ> &J);
|
|
// Inputs:
|
|
// n number of vertices (possibly greater than F.maxCoeff()+1)
|
|
// F #F by ss list of simplices
|
|
// Outputs:
|
|
// IM #V by 1 list of indices such that: NF = IM(F) and NT = IM(T)
|
|
// and V(find(IM<=size(NV,1)),:) = NV
|
|
// J #RV by 1 list, such that RV = V(J,:)
|
|
//
|
|
template <
|
|
typename DerivedF,
|
|
typename DerivedI,
|
|
typename DerivedJ>
|
|
IGL_INLINE void remove_unreferenced(
|
|
const size_t n,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
Eigen::PlainObjectBase<DerivedI> &I,
|
|
Eigen::PlainObjectBase<DerivedJ> &J);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "remove_unreferenced.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_reorder = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_REORDER_H
|
|
#define IGL_REORDER_H
|
|
#include "igl_inline.h"
|
|
#include <vector>
|
|
// For size_t
|
|
#include <stddef.h>
|
|
#include <cstdlib>
|
|
|
|
namespace igl
|
|
{
|
|
// Act like matlab's Y = X(I) for std vectors
|
|
// where I contains a vector of indices so that after,
|
|
// Y[j] = X[I[j]] for index j
|
|
// this implies that Y.size() == I.size()
|
|
// X and Y are allowed to be the same reference
|
|
template< class T >
|
|
IGL_INLINE void reorder(
|
|
const std::vector<T> & unordered,
|
|
std::vector<size_t> const & index_map,
|
|
std::vector<T> & ordered);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "reorder.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_repdiag = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_REPDIAG_H
|
|
#define IGL_REPDIAG_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// REPDIAG repeat a matrix along the diagonal a certain number of times, so
|
|
// that if A is a m by n matrix and we want to repeat along the diagonal d
|
|
// times, we get a m*d by n*d matrix B such that:
|
|
// B( (k*m+1):(k*m+1+m-1), (k*n+1):(k*n+1+n-1)) = A
|
|
// for k from 0 to d-1
|
|
//
|
|
// Inputs:
|
|
// A m by n matrix we are repeating along the diagonal. May be dense or
|
|
// sparse
|
|
// d number of times to repeat A along the diagonal
|
|
// Outputs:
|
|
// B m*d by n*d matrix with A repeated d times along the diagonal,
|
|
// will be dense or sparse to match A
|
|
//
|
|
|
|
// Sparse version
|
|
template <typename T>
|
|
IGL_INLINE void repdiag(
|
|
const Eigen::SparseMatrix<T>& A,
|
|
const int d,
|
|
Eigen::SparseMatrix<T>& B);
|
|
// Dense version
|
|
template <typename T>
|
|
IGL_INLINE void repdiag(
|
|
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
|
|
const int d,
|
|
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B);
|
|
// Wrapper with B as output
|
|
template <class Mat>
|
|
IGL_INLINE Mat repdiag(const Mat & A, const int d);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "repdiag.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_repmat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_REPMAT_H
|
|
#define IGL_REPMAT_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// At least for Dense matrices this is replaced by `replicate` e.g., dst = src.replicate(n,m);
|
|
// http://forum.kde.org/viewtopic.php?f=74&t=90876#p173517
|
|
|
|
// Ideally this is a super overloaded function that behaves just like
|
|
// matlab's repmat
|
|
|
|
// Replicate and tile a matrix
|
|
//
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// A m by n input matrix
|
|
// r number of row-direction copies
|
|
// c number of col-direction copies
|
|
// Outputs:
|
|
// B r*m by c*n output matrix
|
|
//
|
|
template <typename DerivedA,typename DerivedB>
|
|
IGL_INLINE void repmat(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const int r,
|
|
const int c,
|
|
Eigen::PlainObjectBase<DerivedB> & B);
|
|
template <typename T>
|
|
IGL_INLINE void repmat(
|
|
const Eigen::SparseMatrix<T> & A,
|
|
const int r,
|
|
const int c,
|
|
Eigen::SparseMatrix<T> & B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "repmat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_rgb_to_hsv = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_RGB_TO_HSV_H
|
|
#define IGL_RGB_TO_HSV_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Convert RGB to HSV
|
|
//
|
|
// Inputs:
|
|
// r red value ([0,1])
|
|
// g green value ([0,1])
|
|
// b blue value ([0,1])
|
|
// Outputs:
|
|
// h hue value (degrees: [0,360])
|
|
// s saturation value ([0,1])
|
|
// v value value ([0,1])
|
|
template <typename R,typename H>
|
|
IGL_INLINE void rgb_to_hsv(const R * rgb, H * hsv);
|
|
template <typename DerivedR,typename DerivedH>
|
|
IGL_INLINE void rgb_to_hsv(
|
|
const Eigen::PlainObjectBase<DerivedR> & R,
|
|
Eigen::PlainObjectBase<DerivedH> & H);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "rgb_to_hsv.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_rotate_by_quat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ROTATE_BY_QUAT_H
|
|
#define IGL_ROTATE_BY_QUAT_H
|
|
#include "igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
// Compute rotation of a given vector/point by a quaternion
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
// Inputs:
|
|
// v input 3d point/vector
|
|
// q input quaternion
|
|
// Outputs:
|
|
// out result of rotation, allowed to be same as v
|
|
template <typename Q_type>
|
|
IGL_INLINE void rotate_by_quat(
|
|
const Q_type *v,
|
|
const Q_type *q,
|
|
Q_type *out);
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "rotate_by_quat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_rotate_vectors = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_ROTATE_VECTORS_H
|
|
#define IGL_ROTATE_VECTORS_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Rotate the vectors V by A radiants on the tangent plane spanned by B1 and
|
|
// B2
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of vectors
|
|
// A #V eigen vector of rotation angles or a single angle to be applied
|
|
// to all vectors
|
|
// B1 #V by 3 eigen Matrix of base vector 1
|
|
// B2 #V by 3 eigen Matrix of base vector 2
|
|
//
|
|
// Output:
|
|
// Returns the rotated vectors
|
|
//
|
|
IGL_INLINE Eigen::MatrixXd rotate_vectors(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::VectorXd& A,
|
|
const Eigen::MatrixXd& B1,
|
|
const Eigen::MatrixXd& B2);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "rotate_vectors.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_rotation_matrix_from_directions = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_ROTATION_MATRIX_FROM_DIRECTIONS
|
|
#define IGL_ROTATION_MATRIX_FROM_DIRECTIONS
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl {
|
|
/// Given 2 vectors centered on origin calculate the rotation matrix from first to the second
|
|
|
|
// Inputs:
|
|
// v0, v1 the two #3 by 1 vectors
|
|
// normalized boolean, if false, then the vectors are normalized prior to the calculation
|
|
// Output:
|
|
// 3 by 3 rotation matrix that takes v0 to v1
|
|
//
|
|
template <typename Scalar>
|
|
IGL_INLINE Eigen::Matrix<Scalar, 3, 3> rotation_matrix_from_directions(const Eigen::Matrix<Scalar, 3, 1> v0,
|
|
const Eigen::Matrix<Scalar, 3, 1> v1,
|
|
const bool normalized=true);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "rotation_matrix_from_directions.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_ROTATION_MATRIX_FROM_DIRECTIONS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_round = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ROUND_H
|
|
#define IGL_ROUND_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Round a scalar value
|
|
//
|
|
// Inputs:
|
|
// x number
|
|
// Returns x rounded to integer
|
|
template <typename DerivedX>
|
|
DerivedX round(const DerivedX r);
|
|
// Round a given matrix to nearest integers
|
|
//
|
|
// Inputs:
|
|
// X m by n matrix of scalars
|
|
// Outputs:
|
|
// Y m by n matrix of rounded integers
|
|
template < typename DerivedX, typename DerivedY>
|
|
IGL_INLINE void round(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
Eigen::PlainObjectBase<DerivedY>& Y);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "round.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_rows_to_matrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ROWS_TO_MATRIX_H
|
|
#define IGL_ROWS_TO_MATRIX_H
|
|
#include "igl_inline.h"
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Convert a list (std::vector) of row vectors of the same length to a matrix
|
|
// Template:
|
|
// Row row vector type, must implement:
|
|
// .size()
|
|
// Mat Matrix type, must implement:
|
|
// .resize(m,n)
|
|
// .row(i) = Row
|
|
// Inputs:
|
|
// V a m-long list of vectors of size n
|
|
// Outputs:
|
|
// M an m by n matrix
|
|
// Returns true on success, false on errors
|
|
template <class Row, class Mat>
|
|
IGL_INLINE bool rows_to_matrix(const std::vector<Row> & V,Mat & M);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "rows_to_matrix.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sample_edges = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SAMPLE_EDGES_H
|
|
#define IGL_SAMPLE_EDGES_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Compute samples_per_edge extra points along each edge in E defined over
|
|
// vertices of V.
|
|
//
|
|
// Inputs:
|
|
// V vertices over which edges are defined, # vertices by dim
|
|
// E edge list, # edges by 2
|
|
// k number of extra samples to be computed along edge not
|
|
// including start and end points
|
|
// Output:
|
|
// S sampled vertices, size less than # edges * (2+k) by dim always begins
|
|
// with V so that E is also defined over S
|
|
IGL_INLINE void sample_edges(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & E,
|
|
const int k,
|
|
Eigen::MatrixXd & S);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "sample_edges.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_serialize = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SERIALIZE_H
|
|
#define IGL_SERIALIZE_H
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Functions to save and load a serialization of fundamental c++ data types to
|
|
// and from a binary file. STL containers, Eigen matrix types and nested data
|
|
// structures are also supported. To serialize a user defined class implement
|
|
// the interface Serializable or SerializableBase.
|
|
//
|
|
// See also: xml/serialize_xml.h
|
|
// -----------------------------------------------------------------------------
|
|
// TODOs:
|
|
// * arbitrary pointer graph structures
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Known issues: This is not written in libigl-style so it isn't (easily)
|
|
// "dualized" into the static library.
|
|
//
|
|
|
|
#include <type_traits>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <cstdint>
|
|
#include <numeric>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <cstdint>
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
#include "igl_inline.h"
|
|
|
|
// non-intrusive serialization helper macros
|
|
|
|
#define SERIALIZE_TYPE(Type,Params) \
|
|
namespace igl { namespace serialization { \
|
|
void _serialization(bool s,Type& obj,std::vector<char>& buffer) {Params} \
|
|
void serialize(const Type& obj,std::vector<char>& buffer) { \
|
|
_serialization(true,const_cast<Type&>(obj),buffer); \
|
|
} \
|
|
void deserialize(Type& obj,const std::vector<char>& buffer) { \
|
|
_serialization(false,obj,const_cast<std::vector<char>&>(buffer)); \
|
|
} \
|
|
}}
|
|
|
|
#define SERIALIZE_MEMBER(Object) ::igl::serializer(s,obj.##Object,std::string(#Object),buffer);
|
|
#define SERIALIZE_MEMBER_NAME(Object,Name) ::igl::serializer(s,obj.##Object,std::string(Name),buffer);
|
|
|
|
namespace igl
|
|
{
|
|
struct IndexedPointerBase;
|
|
|
|
// Serializes the given object either to a file or to a provided buffer
|
|
// Templates:
|
|
// T type of the object to serialize
|
|
// Inputs:
|
|
// obj object to serialize
|
|
// objectName unique object name,used for the identification
|
|
// overwrite set to true to overwrite an existing file
|
|
// filename name of the file containing the serialization
|
|
// Outputs:
|
|
// buffer binary serialization
|
|
//
|
|
template <typename T>
|
|
inline bool serialize(const T& obj,const std::string& filename);
|
|
template <typename T>
|
|
inline bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite = false);
|
|
template <typename T>
|
|
inline bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer);
|
|
template <typename T>
|
|
inline bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer);
|
|
|
|
// Deserializes the given data from a file or buffer back to the provided object
|
|
//
|
|
// Templates:
|
|
// T type of the object to serialize
|
|
// Inputs:
|
|
// buffer binary serialization
|
|
// objectName unique object name, used for the identification
|
|
// filename name of the file containing the serialization
|
|
// Outputs:
|
|
// obj object to load back serialization to
|
|
//
|
|
template <typename T>
|
|
inline bool deserialize(T& obj,const std::string& filename);
|
|
template <typename T>
|
|
inline bool deserialize(T& obj,const std::string& objectName,const std::string& filename);
|
|
template <typename T>
|
|
inline bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer);
|
|
|
|
// Wrapper to expose both, the de- and serialization as one function
|
|
//
|
|
template <typename T>
|
|
inline bool serializer(bool serialize,T& obj,std::string& filename);
|
|
template <typename T>
|
|
inline bool serializer(bool serialize,T& obj,std::string& objectName,const std::string& filename,bool overwrite = false);
|
|
template <typename T>
|
|
inline bool serializer(bool serialize,T& obj,std::string& objectName,std::vector<char>& buffer);
|
|
|
|
// User defined types have to either overload the function igl::serialization::serialize()
|
|
// and igl::serialization::deserialize() for their type (non-intrusive serialization):
|
|
//
|
|
// namespace igl { namespace serialization
|
|
// {
|
|
// inline void serialize(const UserType& obj,std::vector<char>& buffer) {
|
|
// ::igl::serialize(obj.var,"var",buffer);
|
|
// }
|
|
//
|
|
// inline void deserialize(UserType& obj,const std::vector<char>& buffer) {
|
|
// ::igl::deserialize(obj.var,"var",buffer);
|
|
// }
|
|
// }}
|
|
//
|
|
// or use this macro for convenience:
|
|
//
|
|
// SERIALIZE_TYPE(UserType,
|
|
// SERIALIZE_MEMBER(var)
|
|
// )
|
|
//
|
|
// or to derive from the class Serializable and add their the members
|
|
// in InitSerialization like the following:
|
|
//
|
|
// class UserType : public igl::Serializable {
|
|
//
|
|
// int var;
|
|
//
|
|
// void InitSerialization() {
|
|
// this->Add(var,"var");
|
|
// }
|
|
// };
|
|
|
|
// Base interface for user defined types
|
|
struct SerializableBase
|
|
{
|
|
virtual void Serialize(std::vector<char>& buffer) const = 0;
|
|
virtual void Deserialize(const std::vector<char>& buffer) = 0;
|
|
};
|
|
|
|
// Convenient interface for user defined types
|
|
class Serializable: public SerializableBase
|
|
{
|
|
private:
|
|
|
|
template <typename T>
|
|
struct SerializationObject : public SerializableBase
|
|
{
|
|
bool Binary;
|
|
std::string Name;
|
|
std::unique_ptr<T> Object;
|
|
|
|
void Serialize(std::vector<char>& buffer) const override {
|
|
igl::serialize(*Object,Name,buffer);
|
|
}
|
|
|
|
void Deserialize(const std::vector<char>& buffer) override {
|
|
igl::deserialize(*Object,Name,buffer);
|
|
}
|
|
};
|
|
|
|
mutable bool initialized;
|
|
mutable std::vector<SerializableBase*> objects;
|
|
|
|
public:
|
|
|
|
// Override this function to add your member variables which should be serialized
|
|
inline virtual void InitSerialization() = 0;
|
|
|
|
// Following functions can be overridden to handle the specific events.
|
|
// Return false to prevent the de-/serialization of an object.
|
|
inline virtual bool PreSerialization() const;
|
|
inline virtual void PostSerialization() const;
|
|
inline virtual bool PreDeserialization();
|
|
inline virtual void PostDeserialization();
|
|
|
|
// Default implementation of SerializableBase interface
|
|
inline void Serialize(std::vector<char>& buffer) const override final;
|
|
inline void Deserialize(const std::vector<char>& buffer) override final;
|
|
|
|
// Default constructor, destructor, assignment and copy constructor
|
|
inline Serializable();
|
|
inline Serializable(const Serializable& obj);
|
|
inline ~Serializable();
|
|
inline Serializable& operator=(const Serializable& obj);
|
|
|
|
// Use this function to add your variables which should be serialized
|
|
template <typename T>
|
|
inline void Add(T& obj,std::string name,bool binary = false);
|
|
};
|
|
|
|
// structure for pointer handling
|
|
struct IndexedPointerBase
|
|
{
|
|
enum { BEGIN,END } Type;
|
|
size_t Index;
|
|
};
|
|
template<typename T>
|
|
struct IndexedPointer: public IndexedPointerBase
|
|
{
|
|
const T* Object;
|
|
};
|
|
|
|
// internal functions
|
|
namespace serialization
|
|
{
|
|
// compile time type checks
|
|
template <typename T>
|
|
struct is_stl_container { static const bool value = false; };
|
|
template <typename T1,typename T2>
|
|
struct is_stl_container<std::pair<T1,T2> > { static const bool value = true; };
|
|
template <typename T1,typename T2>
|
|
struct is_stl_container<std::vector<T1,T2> > { static const bool value = true; };
|
|
template <typename T>
|
|
struct is_stl_container<std::set<T> > { static const bool value = true; };
|
|
template <typename T1,typename T2>
|
|
struct is_stl_container<std::map<T1,T2> > { static const bool value = true; };
|
|
|
|
template <typename T>
|
|
struct is_eigen_type { static const bool value = false; };
|
|
template <typename T,int R,int C,int P,int MR,int MC>
|
|
struct is_eigen_type<Eigen::Matrix<T,R,C,P,MR,MC> > { static const bool value = true; };
|
|
template <typename T,int P,typename I>
|
|
struct is_eigen_type<Eigen::SparseMatrix<T,P,I> > { static const bool value = true; };
|
|
|
|
template <typename T>
|
|
struct is_smart_ptr { static const bool value = false; };
|
|
template <typename T>
|
|
struct is_smart_ptr<std::shared_ptr<T> > { static const bool value = true; };
|
|
template <typename T>
|
|
struct is_smart_ptr<std::unique_ptr<T> > { static const bool value = true; };
|
|
template <typename T>
|
|
struct is_smart_ptr<std::weak_ptr<T> > { static const bool value = true; };
|
|
|
|
template <typename T>
|
|
struct is_serializable {
|
|
static const bool value = std::is_fundamental<T>::value || std::is_same<std::string,T>::value || std::is_enum<T>::value || std::is_base_of<SerializableBase,T>::value
|
|
|| is_stl_container<T>::value || is_eigen_type<T>::value || std::is_pointer<T>::value || serialization::is_smart_ptr<T>::value;
|
|
};
|
|
|
|
// non serializable types
|
|
template <typename T>
|
|
inline typename std::enable_if<!is_serializable<T>::value,size_t>::type getByteSize(const T& obj);
|
|
template <typename T>
|
|
inline typename std::enable_if<!is_serializable<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T>
|
|
inline typename std::enable_if<!is_serializable<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// fundamental types
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_fundamental<T>::value,size_t>::type getByteSize(const T& obj);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// std::string
|
|
inline size_t getByteSize(const std::string& obj);
|
|
inline void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
inline void deserialize(std::string& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// enum types
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_enum<T>::value,size_t>::type getByteSize(const T& obj);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_enum<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_enum<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// SerializableBase
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value,size_t>::type getByteSize(const T& obj);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// stl containers
|
|
// std::pair
|
|
template <typename T1,typename T2>
|
|
inline size_t getByteSize(const std::pair<T1,T2>& obj);
|
|
template <typename T1,typename T2>
|
|
inline void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T1,typename T2>
|
|
inline void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// std::vector
|
|
template <typename T1,typename T2>
|
|
inline size_t getByteSize(const std::vector<T1,T2>& obj);
|
|
template <typename T1,typename T2>
|
|
inline void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T1,typename T2>
|
|
inline void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter);
|
|
template <typename T2>
|
|
inline void deserialize(std::vector<bool,T2>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// std::set
|
|
template <typename T>
|
|
inline size_t getByteSize(const std::set<T>& obj);
|
|
template <typename T>
|
|
inline void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T>
|
|
inline void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// std::map
|
|
template <typename T1,typename T2>
|
|
inline size_t getByteSize(const std::map<T1,T2>& obj);
|
|
template <typename T1,typename T2>
|
|
inline void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T1,typename T2>
|
|
inline void deserialize(std::map<T1,T2>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// Eigen types
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
inline size_t getByteSize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj);
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
inline void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
inline void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
template<typename T,int P,typename I>
|
|
inline size_t getByteSize(const Eigen::SparseMatrix<T,P,I>& obj);
|
|
template<typename T,int P,typename I>
|
|
inline void serialize(const Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template<typename T,int P,typename I>
|
|
inline void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// raw pointers
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_pointer<T>::value,size_t>::type getByteSize(const T& obj);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// std::shared_ptr and std::unique_ptr
|
|
template <typename T>
|
|
inline typename std::enable_if<serialization::is_smart_ptr<T>::value,size_t>::type getByteSize(const T& obj);
|
|
template <typename T>
|
|
inline typename std::enable_if<serialization::is_smart_ptr<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <template<typename> class T0, typename T1>
|
|
inline typename std::enable_if<serialization::is_smart_ptr<T0<T1> >::value>::type deserialize(T0<T1>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// std::weak_ptr
|
|
template <typename T>
|
|
inline size_t getByteSize(const std::weak_ptr<T>& obj);
|
|
template <typename T>
|
|
inline void serialize(const std::weak_ptr<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
|
|
template <typename T>
|
|
inline void deserialize(std::weak_ptr<T>& obj,std::vector<char>::const_iterator& iter);
|
|
|
|
// functions to overload for non-intrusive serialization
|
|
template <typename T>
|
|
inline void serialize(const T& obj,std::vector<char>& buffer);
|
|
template <typename T>
|
|
inline void deserialize(T& obj,const std::vector<char>& buffer);
|
|
|
|
// helper functions
|
|
template <typename T>
|
|
inline void updateMemoryMap(T& obj,size_t size);
|
|
}
|
|
}
|
|
|
|
// Always include inlines for these functions
|
|
|
|
// IMPLEMENTATION
|
|
|
|
namespace igl
|
|
{
|
|
template <typename T>
|
|
inline bool serialize(const T& obj,const std::string& filename)
|
|
{
|
|
return serialize(obj,"obj",filename,true);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite)
|
|
{
|
|
bool success = false;
|
|
|
|
std::vector<char> buffer;
|
|
|
|
std::ios_base::openmode mode = std::ios::out | std::ios::binary;
|
|
|
|
if(overwrite)
|
|
mode |= std::ios::trunc;
|
|
else
|
|
mode |= std::ios::app;
|
|
|
|
std::ofstream file(filename.c_str(),mode);
|
|
|
|
if(file.is_open())
|
|
{
|
|
serialize(obj,objectName,buffer);
|
|
|
|
file.write(&buffer[0],buffer.size());
|
|
|
|
file.close();
|
|
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "serialization: file " << filename << " not found!" << std::endl;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer)
|
|
{
|
|
// serialize object data
|
|
size_t size = serialization::getByteSize(obj);
|
|
std::vector<char> tmp(size);
|
|
auto it = tmp.begin();
|
|
serialization::serialize(obj,tmp,it);
|
|
|
|
std::string objectType(typeid(obj).name());
|
|
size_t newObjectSize = tmp.size();
|
|
size_t newHeaderSize = serialization::getByteSize(objectName) + serialization::getByteSize(objectType) + sizeof(size_t);
|
|
size_t curSize = buffer.size();
|
|
size_t newSize = curSize + newHeaderSize + newObjectSize;
|
|
|
|
buffer.resize(newSize);
|
|
|
|
std::vector<char>::iterator iter = buffer.begin()+curSize;
|
|
|
|
// serialize object header (name/type/size)
|
|
serialization::serialize(objectName,buffer,iter);
|
|
serialization::serialize(objectType,buffer,iter);
|
|
serialization::serialize(newObjectSize,buffer,iter);
|
|
|
|
// copy serialized data to buffer
|
|
iter = std::copy(tmp.begin(),tmp.end(),iter);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool deserialize(T& obj,const std::string& filename)
|
|
{
|
|
return deserialize(obj,"obj",filename);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool deserialize(T& obj,const std::string& objectName,const std::string& filename)
|
|
{
|
|
bool success = false;
|
|
|
|
std::ifstream file(filename.c_str(),std::ios::binary);
|
|
|
|
if(file.is_open())
|
|
{
|
|
file.seekg(0,std::ios::end);
|
|
std::streamoff size = file.tellg();
|
|
file.seekg(0,std::ios::beg);
|
|
|
|
std::vector<char> buffer(size);
|
|
file.read(&buffer[0],size);
|
|
|
|
deserialize(obj,objectName,buffer);
|
|
file.close();
|
|
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "serialization: file " << filename << " not found!" << std::endl;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer)
|
|
{
|
|
bool success = false;
|
|
|
|
// find suitable object header
|
|
auto objectIter = buffer.cend();
|
|
auto iter = buffer.cbegin();
|
|
while(iter != buffer.end())
|
|
{
|
|
std::string name;
|
|
std::string type;
|
|
size_t size;
|
|
serialization::deserialize(name,iter);
|
|
serialization::deserialize(type,iter);
|
|
serialization::deserialize(size,iter);
|
|
|
|
if(name == objectName && type == typeid(obj).name())
|
|
{
|
|
objectIter = iter;
|
|
//break; // find first suitable object header
|
|
}
|
|
|
|
iter+=size;
|
|
}
|
|
|
|
if(objectIter != buffer.end())
|
|
{
|
|
serialization::deserialize(obj,objectIter);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
obj = T();
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Wrapper function which combines both, de- and serialization
|
|
template <typename T>
|
|
inline bool serializer(bool s,T& obj,std::string& filename)
|
|
{
|
|
return s ? serialize(obj,filename) : deserialize(obj,filename);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool serializer(bool s,T& obj,std::string& objectName,const std::string& filename,bool overwrite)
|
|
{
|
|
return s ? serialize(obj,objectName,filename,overwrite) : deserialize(obj,objectName,filename);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool serializer(bool s,T& obj,std::string& objectName,std::vector<char>& buffer)
|
|
{
|
|
return s ? serialize(obj,objectName,buffer) : deserialize(obj,objectName,buffer);
|
|
}
|
|
|
|
inline bool Serializable::PreSerialization() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
inline void Serializable::PostSerialization() const
|
|
{
|
|
}
|
|
|
|
inline bool Serializable::PreDeserialization()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
inline void Serializable::PostDeserialization()
|
|
{
|
|
}
|
|
|
|
inline void Serializable::Serialize(std::vector<char>& buffer) const
|
|
{
|
|
if(this->PreSerialization())
|
|
{
|
|
if(initialized == false)
|
|
{
|
|
objects.clear();
|
|
(const_cast<Serializable*>(this))->InitSerialization();
|
|
initialized = true;
|
|
}
|
|
|
|
for(const auto& v : objects)
|
|
{
|
|
v->Serialize(buffer);
|
|
}
|
|
|
|
this->PostSerialization();
|
|
}
|
|
}
|
|
|
|
inline void Serializable::Deserialize(const std::vector<char>& buffer)
|
|
{
|
|
if(this->PreDeserialization())
|
|
{
|
|
if(initialized == false)
|
|
{
|
|
objects.clear();
|
|
(const_cast<Serializable*>(this))->InitSerialization();
|
|
initialized = true;
|
|
}
|
|
|
|
for(auto& v : objects)
|
|
{
|
|
v->Deserialize(buffer);
|
|
}
|
|
|
|
this->PostDeserialization();
|
|
}
|
|
}
|
|
|
|
inline Serializable::Serializable()
|
|
{
|
|
initialized = false;
|
|
}
|
|
|
|
inline Serializable::Serializable(const Serializable& obj)
|
|
{
|
|
initialized = false;
|
|
objects.clear();
|
|
}
|
|
|
|
inline Serializable::~Serializable()
|
|
{
|
|
initialized = false;
|
|
objects.clear();
|
|
}
|
|
|
|
inline Serializable& Serializable::operator=(const Serializable& obj)
|
|
{
|
|
if(this != &obj)
|
|
{
|
|
if(initialized)
|
|
{
|
|
initialized = false;
|
|
objects.clear();
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
inline void Serializable::Add(T& obj,std::string name,bool binary)
|
|
{
|
|
auto object = new SerializationObject<T>();
|
|
object->Binary = binary;
|
|
object->Name = name;
|
|
object->Object = std::unique_ptr<T>(&obj);
|
|
|
|
objects.push_back(object);
|
|
}
|
|
|
|
namespace serialization
|
|
{
|
|
template <typename T>
|
|
inline typename std::enable_if<!is_serializable<T>::value,size_t>::type getByteSize(const T& obj)
|
|
{
|
|
return sizeof(std::vector<char>::size_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<!is_serializable<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
// data
|
|
std::vector<char> tmp;
|
|
serialize(obj,tmp);
|
|
|
|
// size
|
|
size_t size = buffer.size();
|
|
serialization::serialize(tmp.size(),buffer,iter);
|
|
size_t cur = iter - buffer.begin();
|
|
|
|
buffer.resize(size+tmp.size());
|
|
iter = buffer.begin()+cur;
|
|
iter = std::copy(tmp.begin(),tmp.end(),iter);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<!is_serializable<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
std::vector<char>::size_type size;
|
|
serialization::deserialize(size,iter);
|
|
|
|
std::vector<char> tmp;
|
|
tmp.resize(size);
|
|
std::copy(iter,iter+size,tmp.begin());
|
|
|
|
deserialize(obj,tmp);
|
|
iter += size;
|
|
}
|
|
|
|
// fundamental types
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_fundamental<T>::value,size_t>::type getByteSize(const T& obj)
|
|
{
|
|
return sizeof(T);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
//serialization::updateMemoryMap(obj,sizeof(T));
|
|
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&obj);
|
|
iter = std::copy(ptr,ptr+sizeof(T),iter);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
uint8_t* ptr = reinterpret_cast<uint8_t*>(&obj);
|
|
std::copy(iter,iter+sizeof(T),ptr);
|
|
iter += sizeof(T);
|
|
}
|
|
|
|
// std::string
|
|
|
|
inline size_t getByteSize(const std::string& obj)
|
|
{
|
|
return getByteSize(obj.length())+obj.length()*sizeof(uint8_t);
|
|
}
|
|
|
|
inline void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialization::serialize(obj.length(),buffer,iter);
|
|
for(const auto& cur : obj)
|
|
{
|
|
serialization::serialize(cur,buffer,iter);
|
|
}
|
|
}
|
|
|
|
inline void deserialize(std::string& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
size_t size;
|
|
serialization::deserialize(size,iter);
|
|
|
|
std::string str(size,'\0');
|
|
for(size_t i=0; i<size; ++i)
|
|
{
|
|
serialization::deserialize(str.at(i),iter);
|
|
}
|
|
|
|
obj = str;
|
|
}
|
|
|
|
// enum types
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_enum<T>::value,size_t>::type getByteSize(const T& obj)
|
|
{
|
|
return sizeof(T);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_enum<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&obj);
|
|
iter = std::copy(ptr,ptr+sizeof(T),iter);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_enum<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
uint8_t* ptr = reinterpret_cast<uint8_t*>(&obj);
|
|
std::copy(iter,iter+sizeof(T),ptr);
|
|
iter += sizeof(T);
|
|
}
|
|
|
|
// SerializableBase
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value,size_t>::type getByteSize(const T& obj)
|
|
{
|
|
return sizeof(std::vector<char>::size_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
// data
|
|
std::vector<char> tmp;
|
|
obj.Serialize(tmp);
|
|
|
|
// size
|
|
size_t size = buffer.size();
|
|
serialization::serialize(tmp.size(),buffer,iter);
|
|
size_t cur = iter - buffer.begin();
|
|
|
|
buffer.resize(size+tmp.size());
|
|
iter = buffer.begin()+cur;
|
|
iter = std::copy(tmp.begin(),tmp.end(),iter);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
std::vector<char>::size_type size;
|
|
serialization::deserialize(size,iter);
|
|
|
|
std::vector<char> tmp;
|
|
tmp.resize(size);
|
|
std::copy(iter,iter+size,tmp.begin());
|
|
|
|
obj.Deserialize(tmp);
|
|
iter += size;
|
|
}
|
|
|
|
// STL containers
|
|
|
|
// std::pair
|
|
|
|
template <typename T1,typename T2>
|
|
inline size_t getByteSize(const std::pair<T1,T2>& obj)
|
|
{
|
|
return getByteSize(obj.first)+getByteSize(obj.second);
|
|
}
|
|
|
|
template <typename T1,typename T2>
|
|
inline void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialization::serialize(obj.first,buffer,iter);
|
|
serialization::serialize(obj.second,buffer,iter);
|
|
}
|
|
|
|
template <typename T1,typename T2>
|
|
inline void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
serialization::deserialize(obj.first,iter);
|
|
serialization::deserialize(obj.second,iter);
|
|
}
|
|
|
|
// std::vector
|
|
|
|
template <typename T1,typename T2>
|
|
inline size_t getByteSize(const std::vector<T1,T2>& obj)
|
|
{
|
|
return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const T1& cur) { return acc+getByteSize(cur); });
|
|
}
|
|
|
|
template <typename T1,typename T2>
|
|
inline void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
size_t size = obj.size();
|
|
serialization::serialize(size,buffer,iter);
|
|
for(const T1& cur : obj)
|
|
{
|
|
serialization::serialize(cur,buffer,iter);
|
|
}
|
|
}
|
|
|
|
template <typename T1,typename T2>
|
|
inline void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
size_t size;
|
|
serialization::deserialize(size,iter);
|
|
|
|
obj.resize(size);
|
|
for(T1& v : obj)
|
|
{
|
|
serialization::deserialize(v,iter);
|
|
}
|
|
}
|
|
|
|
template <typename T2>
|
|
inline void deserialize(std::vector<bool,T2>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
size_t size;
|
|
serialization::deserialize(size,iter);
|
|
|
|
obj.resize(size);
|
|
for(int i=0;i<obj.size();i++)
|
|
{
|
|
bool val;
|
|
serialization::deserialize(val,iter);
|
|
obj[i] = val;
|
|
}
|
|
}
|
|
|
|
//std::set
|
|
|
|
template <typename T>
|
|
inline size_t getByteSize(const std::set<T>& obj)
|
|
{
|
|
return std::accumulate(obj.begin(),obj.end(),getByteSize(obj.size()),[](const size_t& acc,const T& cur) { return acc+getByteSize(cur); });
|
|
}
|
|
|
|
template <typename T>
|
|
inline void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialization::serialize(obj.size(),buffer,iter);
|
|
for(const T& cur : obj)
|
|
{
|
|
serialization::serialize(cur,buffer,iter);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
size_t size;
|
|
serialization::deserialize(size,iter);
|
|
|
|
obj.clear();
|
|
for(size_t i=0; i<size; ++i)
|
|
{
|
|
T val;
|
|
serialization::deserialize(val,iter);
|
|
obj.insert(val);
|
|
}
|
|
}
|
|
|
|
// std::map
|
|
|
|
template <typename T1,typename T2>
|
|
inline size_t getByteSize(const std::map<T1,T2>& obj)
|
|
{
|
|
return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const std::pair<T1,T2>& cur) { return acc+getByteSize(cur); });
|
|
}
|
|
|
|
template <typename T1,typename T2>
|
|
inline void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialization::serialize(obj.size(),buffer,iter);
|
|
for(const auto& cur : obj)
|
|
{
|
|
serialization::serialize(cur,buffer,iter);
|
|
}
|
|
}
|
|
|
|
template <typename T1,typename T2>
|
|
inline void deserialize(std::map<T1,T2>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
size_t size;
|
|
serialization::deserialize(size,iter);
|
|
|
|
obj.clear();
|
|
for(size_t i=0; i<size; ++i)
|
|
{
|
|
std::pair<T1,T2> pair;
|
|
serialization::deserialize(pair,iter);
|
|
obj.insert(pair);
|
|
}
|
|
}
|
|
|
|
// Eigen types
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
inline size_t getByteSize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj)
|
|
{
|
|
// space for numbers of rows,cols and data
|
|
return 2*sizeof(typename Eigen::Matrix<T,R,C,P,MR,MC>::Index)+sizeof(T)*obj.rows()*obj.cols();
|
|
}
|
|
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
inline void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialization::serialize(obj.rows(),buffer,iter);
|
|
serialization::serialize(obj.cols(),buffer,iter);
|
|
size_t size = sizeof(T)*obj.rows()*obj.cols();
|
|
auto ptr = reinterpret_cast<const uint8_t*>(obj.data());
|
|
iter = std::copy(ptr,ptr+size,iter);
|
|
}
|
|
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
inline void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
typename Eigen::Matrix<T,R,C,P,MR,MC>::Index rows,cols;
|
|
serialization::deserialize(rows,iter);
|
|
serialization::deserialize(cols,iter);
|
|
size_t size = sizeof(T)*rows*cols;
|
|
obj.resize(rows,cols);
|
|
auto ptr = reinterpret_cast<uint8_t*>(obj.data());
|
|
std::copy(iter,iter+size,ptr);
|
|
iter+=size;
|
|
}
|
|
|
|
template<typename T,int P,typename I>
|
|
inline size_t getByteSize(const Eigen::SparseMatrix<T,P,I>& obj)
|
|
{
|
|
// space for numbers of rows,cols,nonZeros and tripplets with data (rowIdx,colIdx,value)
|
|
size_t size = sizeof(typename Eigen::SparseMatrix<T,P,I>::Index);
|
|
return 3*size+(sizeof(T)+2*size)*obj.nonZeros();
|
|
}
|
|
|
|
template<typename T,int P,typename I>
|
|
inline void serialize(const Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialization::serialize(obj.rows(),buffer,iter);
|
|
serialization::serialize(obj.cols(),buffer,iter);
|
|
serialization::serialize(obj.nonZeros(),buffer,iter);
|
|
|
|
for(int k=0;k<obj.outerSize();++k)
|
|
{
|
|
for(typename Eigen::SparseMatrix<T,P,I>::InnerIterator it(obj,k);it;++it)
|
|
{
|
|
serialization::serialize(it.row(),buffer,iter);
|
|
serialization::serialize(it.col(),buffer,iter);
|
|
serialization::serialize(it.value(),buffer,iter);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T,int P,typename I>
|
|
inline void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
typename Eigen::SparseMatrix<T,P,I>::Index rows,cols,nonZeros;
|
|
serialization::deserialize(rows,iter);
|
|
serialization::deserialize(cols,iter);
|
|
serialization::deserialize(nonZeros,iter);
|
|
|
|
obj.resize(rows,cols);
|
|
obj.setZero();
|
|
|
|
std::vector<Eigen::Triplet<T,I> > triplets;
|
|
for(int i=0;i<nonZeros;i++)
|
|
{
|
|
typename Eigen::SparseMatrix<T,P,I>::Index rowId,colId;
|
|
serialization::deserialize(rowId,iter);
|
|
serialization::deserialize(colId,iter);
|
|
T value;
|
|
serialization::deserialize(value,iter);
|
|
triplets.push_back(Eigen::Triplet<T,I>(rowId,colId,value));
|
|
}
|
|
obj.setFromTriplets(triplets.begin(),triplets.end());
|
|
}
|
|
|
|
// pointers
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_pointer<T>::value,size_t>::type getByteSize(const T& obj)
|
|
{
|
|
size_t size = sizeof(bool);
|
|
|
|
if(obj)
|
|
size += getByteSize(*obj);
|
|
|
|
return size;
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialization::serialize(obj == nullptr,buffer,iter);
|
|
|
|
if(obj)
|
|
serialization::serialize(*obj,buffer,iter);
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
bool isNullPtr;
|
|
serialization::deserialize(isNullPtr,iter);
|
|
|
|
if(isNullPtr)
|
|
{
|
|
if(obj)
|
|
{
|
|
std::cout << "serialization: possible memory leak in serialization for '" << typeid(obj).name() << "'" << std::endl;
|
|
obj = nullptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(obj)
|
|
{
|
|
std::cout << "serialization: possible memory corruption in deserialization for '" << typeid(obj).name() << "'" << std::endl;
|
|
}
|
|
else
|
|
{
|
|
obj = new typename std::remove_pointer<T>::type();
|
|
}
|
|
serialization::deserialize(*obj,iter);
|
|
}
|
|
}
|
|
|
|
// std::shared_ptr and std::unique_ptr
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<serialization::is_smart_ptr<T>::value,size_t>::type getByteSize(const T& obj)
|
|
{
|
|
return getByteSize(obj.get());
|
|
}
|
|
|
|
template <typename T>
|
|
inline typename std::enable_if<serialization::is_smart_ptr<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
serialize(obj.get(),buffer,iter);
|
|
}
|
|
|
|
template <template<typename> class T0,typename T1>
|
|
inline typename std::enable_if<serialization::is_smart_ptr<T0<T1> >::value>::type deserialize(T0<T1>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
bool isNullPtr;
|
|
serialization::deserialize(isNullPtr,iter);
|
|
|
|
if(isNullPtr)
|
|
{
|
|
obj.reset();
|
|
}
|
|
else
|
|
{
|
|
obj = T0<T1>(new T1());
|
|
serialization::deserialize(*obj,iter);
|
|
}
|
|
}
|
|
|
|
// std::weak_ptr
|
|
|
|
template <typename T>
|
|
inline size_t getByteSize(const std::weak_ptr<T>& obj)
|
|
{
|
|
return sizeof(size_t);
|
|
}
|
|
|
|
template <typename T>
|
|
inline void serialize(const std::weak_ptr<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
|
|
{
|
|
|
|
}
|
|
|
|
template <typename T>
|
|
inline void deserialize(std::weak_ptr<T>& obj,std::vector<char>::const_iterator& iter)
|
|
{
|
|
|
|
}
|
|
|
|
// functions to overload for non-intrusive serialization
|
|
template <typename T>
|
|
inline void serialize(const T& obj,std::vector<char>& buffer)
|
|
{
|
|
std::cerr << typeid(obj).name() << " is not serializable: derive from igl::Serializable or overload the function igl::serialization::serialize(const T& obj,std::vector<char>& buffer)" << std::endl;
|
|
}
|
|
|
|
template <typename T>
|
|
inline void deserialize(T& obj,const std::vector<char>& buffer)
|
|
{
|
|
std::cerr << typeid(obj).name() << " is not deserializable: derive from igl::Serializable or overload the function igl::serialization::deserialize(T& obj, const std::vector<char>& buffer)" << std::endl;
|
|
}
|
|
|
|
// helper functions
|
|
|
|
template <typename T>
|
|
inline void updateMemoryMap(T& obj,size_t size,std::map<std::uintptr_t,IndexedPointerBase*>& memoryMap)
|
|
{
|
|
// check if object is already serialized
|
|
auto startPtr = new IndexedPointer<T>();
|
|
startPtr->Object = &obj;
|
|
auto startBasePtr = static_cast<IndexedPointerBase*>(startPtr);
|
|
startBasePtr->Type = IndexedPointerBase::BEGIN;
|
|
auto startAddress = reinterpret_cast<std::uintptr_t>(&obj);
|
|
auto p = std::pair<std::uintptr_t,IndexedPointerBase*>(startAddress,startBasePtr);
|
|
|
|
auto el = memoryMap.insert(p);
|
|
auto iter = ++el.first; // next elememt
|
|
if(el.second && (iter == memoryMap.end() || iter->second->Type != IndexedPointerBase::END))
|
|
{
|
|
// not yet serialized
|
|
auto endPtr = new IndexedPointer<T>();
|
|
auto endBasePtr = static_cast<IndexedPointerBase*>(endPtr);
|
|
endBasePtr->Type = IndexedPointerBase::END;
|
|
auto endAddress = reinterpret_cast<std::uintptr_t>(&obj) + size - 1;
|
|
auto p = std::pair<std::uintptr_t,IndexedPointerBase*>(endAddress,endBasePtr);
|
|
|
|
// insert end address
|
|
memoryMap.insert(el.first,p);
|
|
}
|
|
else
|
|
{
|
|
// already serialized
|
|
|
|
// remove inserted address
|
|
memoryMap.erase(el.first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_setdiff = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SETDIFF_H
|
|
#define IGL_SETDIFF_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Set difference of elements of matrices
|
|
//
|
|
// Inputs:
|
|
// A m-long vector of indices
|
|
// B n-long vector of indices
|
|
// Outputs:
|
|
// C (k<=m)-long vector of unique elements appearing in A but not in B
|
|
// IA (k<=m)-long list of indices into A so that C = A(IA)
|
|
//
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedB,
|
|
typename DerivedC,
|
|
typename DerivedIA>
|
|
IGL_INLINE void setdiff(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::PlainObjectBase<DerivedIA> & IA);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "setdiff.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_signed_distance = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SIGNED_DISTANCE_H
|
|
#define IGL_SIGNED_DISTANCE_H
|
|
|
|
#include "igl_inline.h"
|
|
#include "AABB.h"
|
|
#include "WindingNumberAABB.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
enum SignedDistanceType
|
|
{
|
|
// Use fast pseudo-normal test [Bærentzen & Aanæs 2005]
|
|
SIGNED_DISTANCE_TYPE_PSEUDONORMAL = 0,
|
|
SIGNED_DISTANCE_TYPE_WINDING_NUMBER = 1,
|
|
SIGNED_DISTANCE_TYPE_DEFAULT = 2,
|
|
SIGNED_DISTANCE_TYPE_UNSIGNED = 3,
|
|
NUM_SIGNED_DISTANCE_TYPE = 4
|
|
};
|
|
// Computes signed distance to a mesh
|
|
//
|
|
// Inputs:
|
|
// P #P by 3 list of query point positions
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by ss list of triangle indices, ss should be 3 unless sign_type ==
|
|
// SIGNED_DISTANCE_TYPE_UNSIGNED
|
|
// sign_type method for computing distance _sign_ S
|
|
// Outputs:
|
|
// S #P list of smallest signed distances
|
|
// I #P list of facet indices corresponding to smallest distances
|
|
// C #P by 3 list of closest points
|
|
// N #P by 3 list of closest normals (only set if
|
|
// sign_type=SIGNED_DISTANCE_TYPE_PSEUDONORMAL)
|
|
//
|
|
// Known bugs: This only computes distances to triangles. So unreferenced
|
|
// vertices and degenerate triangles are ignored.
|
|
IGL_INLINE void signed_distance(
|
|
const Eigen::MatrixXd & P,
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const SignedDistanceType sign_type,
|
|
Eigen::VectorXd & S,
|
|
Eigen::VectorXi & I,
|
|
Eigen::MatrixXd & C,
|
|
Eigen::MatrixXd & N);
|
|
// Computes signed distance to mesh
|
|
//
|
|
// Inputs:
|
|
// tree AABB acceleration tree (see AABB.h)
|
|
// F #F by 3 list of triangle indices
|
|
// FN #F by 3 list of triangle normals
|
|
// VN #V by 3 list of vertex normals (ANGLE WEIGHTING)
|
|
// EN #E by 3 list of edge normals (UNIFORM WEIGHTING)
|
|
// EMAP #F*3 mapping edges in F to E
|
|
// q Query point
|
|
// Returns signed distance to mesh
|
|
//
|
|
IGL_INLINE double signed_distance_pseudonormal(
|
|
const AABB<Eigen::MatrixXd,3> & tree,
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & FN,
|
|
const Eigen::MatrixXd & VN,
|
|
const Eigen::MatrixXd & EN,
|
|
const Eigen::VectorXi & EMAP,
|
|
const Eigen::RowVector3d & q);
|
|
// Outputs:
|
|
// s sign
|
|
// sqrd squared distance
|
|
// i closest primitive
|
|
// c closest point
|
|
// n normal
|
|
IGL_INLINE void signed_distance_pseudonormal(
|
|
const AABB<Eigen::MatrixXd,3> & tree,
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & FN,
|
|
const Eigen::MatrixXd & VN,
|
|
const Eigen::MatrixXd & EN,
|
|
const Eigen::VectorXi & EMAP,
|
|
const Eigen::RowVector3d & q,
|
|
double & s,
|
|
double & sqrd,
|
|
int & i,
|
|
Eigen::RowVector3d & c,
|
|
Eigen::RowVector3d & n);
|
|
IGL_INLINE void signed_distance_pseudonormal(
|
|
const Eigen::MatrixXd & P,
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const AABB<Eigen::MatrixXd,3> & tree,
|
|
const Eigen::MatrixXd & FN,
|
|
const Eigen::MatrixXd & VN,
|
|
const Eigen::MatrixXd & EN,
|
|
const Eigen::VectorXi & EMAP,
|
|
Eigen::VectorXd & S,
|
|
Eigen::VectorXi & I,
|
|
Eigen::MatrixXd & C,
|
|
Eigen::MatrixXd & N);
|
|
|
|
// Inputs:
|
|
// tree AABB acceleration tree (see cgal/point_mesh_squared_distance.h)
|
|
// hier Winding number evaluation hierarchy
|
|
// q Query point
|
|
// Returns signed distance to mesh
|
|
IGL_INLINE double signed_distance_winding_number(
|
|
const AABB<Eigen::MatrixXd,3> & tree,
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
|
|
const Eigen::RowVector3d & q);
|
|
// Outputs:
|
|
// s sign
|
|
// sqrd squared distance
|
|
// pp closest point and primitve
|
|
IGL_INLINE void signed_distance_winding_number(
|
|
const AABB<Eigen::MatrixXd,3> & tree,
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const igl::WindingNumberAABB<Eigen::Vector3d> & hier,
|
|
const Eigen::RowVector3d & q,
|
|
double & s,
|
|
double & sqrd,
|
|
int & i,
|
|
Eigen::RowVector3d & c);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "signed_distance.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_slice = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SLICE_H
|
|
#define IGL_SLICE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Act like the matlab X(row_indices,col_indices) operator, where
|
|
// row_indices, col_indices are non-negative integer indices.
|
|
//
|
|
// Inputs:
|
|
// X m by n matrix
|
|
// R list of row indices
|
|
// C list of column indices
|
|
// Output:
|
|
// Y #R by #C matrix
|
|
//
|
|
// See also: slice_mask
|
|
template <typename TX, typename TY>
|
|
IGL_INLINE void slice(
|
|
const Eigen::SparseMatrix<TX>& X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
|
|
Eigen::SparseMatrix<TY>& Y);
|
|
// Wrapper to only slice in one direction
|
|
//
|
|
// Inputs:
|
|
// dim dimension to slice in 1 or 2, dim=1 --> X(R,:), dim=2 --> X(:,R)
|
|
//
|
|
// Note: For now this is just a cheap wrapper.
|
|
template <typename MatX, typename MatY>
|
|
IGL_INLINE void slice(
|
|
const MatX& X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
const int dim,
|
|
MatY& Y);
|
|
template <typename DerivedX, typename DerivedY>
|
|
IGL_INLINE void slice(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
|
|
Eigen::PlainObjectBase<DerivedY> & Y);
|
|
|
|
template <typename DerivedX, typename DerivedY>
|
|
IGL_INLINE void slice(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
Eigen::PlainObjectBase<DerivedY> & Y);
|
|
// VectorXi Y = slice(X,R);
|
|
template <typename DerivedX>
|
|
IGL_INLINE Eigen::PlainObjectBase<DerivedX> slice(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R);
|
|
template <typename DerivedX>
|
|
IGL_INLINE Eigen::PlainObjectBase<DerivedX> slice(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
const int dim);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "slice.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_slice_into = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SLICE_INTO_H
|
|
#define IGL_SLICE_INTO_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Act like the matlab Y(row_indices,col_indices) = X
|
|
//
|
|
// Inputs:
|
|
// X xm by xn rhs matrix
|
|
// R list of row indices
|
|
// C list of column indices
|
|
// Y ym by yn lhs matrix
|
|
// Output:
|
|
// Y ym by yn lhs matrix, same as input but Y(R,C) = X
|
|
template <typename T>
|
|
IGL_INLINE void slice_into(
|
|
const Eigen::SparseMatrix<T>& X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
|
|
Eigen::SparseMatrix<T>& Y);
|
|
|
|
template <typename DerivedX>
|
|
IGL_INLINE void slice_into(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
|
|
Eigen::PlainObjectBase<DerivedX> & Y);
|
|
// Wrapper to only slice in one direction
|
|
//
|
|
// Inputs:
|
|
// dim dimension to slice in 1 or 2, dim=1 --> X(R,:), dim=2 --> X(:,R)
|
|
//
|
|
// Note: For now this is just a cheap wrapper.
|
|
template <typename Mat>
|
|
IGL_INLINE void slice_into(
|
|
const Mat& X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
const int dim,
|
|
Mat& Y);
|
|
|
|
template <typename DerivedX>
|
|
IGL_INLINE void slice_into(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
|
|
Eigen::PlainObjectBase<DerivedX> & Y);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "slice_into.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_slice_mask = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SLICE_MASK_H
|
|
#define IGL_SLICE_MASK_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Sparse>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Act like the matlab X(row_mask,col_mask) operator, where
|
|
// row_mask, col_mask are non-negative integer indices.
|
|
//
|
|
// Inputs:
|
|
// X m by n matrix
|
|
// R m list of row bools
|
|
// C n list of column bools
|
|
// Output:
|
|
// Y #trues-in-R by #trues-in-C matrix
|
|
//
|
|
// See also: slice_mask
|
|
|
|
template <typename DerivedX>
|
|
IGL_INLINE void slice_mask(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Array<bool,Eigen::Dynamic,1> & R,
|
|
const Eigen::Array<bool,Eigen::Dynamic,1> & C,
|
|
Eigen::PlainObjectBase<DerivedX> & Y);
|
|
template <typename DerivedX>
|
|
IGL_INLINE void slice_mask(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Array<bool,Eigen::Dynamic,1> & R,
|
|
const int dim,
|
|
Eigen::PlainObjectBase<DerivedX> & Y);
|
|
|
|
template <typename DerivedX>
|
|
IGL_INLINE Eigen::PlainObjectBase<DerivedX> slice_mask(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Array<bool,Eigen::Dynamic,1> & R,
|
|
const Eigen::Array<bool,Eigen::Dynamic,1> & C);
|
|
template <typename DerivedX>
|
|
IGL_INLINE Eigen::PlainObjectBase<DerivedX> slice_mask(
|
|
const Eigen::PlainObjectBase<DerivedX> & X,
|
|
const Eigen::Array<bool,Eigen::Dynamic,1> & R,
|
|
const int dim);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "slice_mask.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_slice_tets = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SLICE_TETS_H
|
|
#define IGL_SLICE_TETS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// SLICE_TETS Slice through a tet mesh (V,T) along a given plane (via its
|
|
// implicit equation).
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of tet mesh vertices
|
|
// T #T by 4 list of tet indices into V
|
|
// plane list of 4 coefficients in the plane equation: [x y z 1]'*plane = 0
|
|
// Optional:
|
|
// 'Manifold' followed by whether to stitch together triangles into a
|
|
// manifold mesh {true}: results in more compact U but slightly slower.
|
|
// Outputs:
|
|
// U #U by 3 list of triangle mesh vertices along slice
|
|
// G #G by 3 list of triangles indices into U
|
|
// J #G list of indices into T revealing from which tet each faces comes
|
|
// BC #U by #V list of barycentric coordinates (or more generally: linear
|
|
// interpolation coordinates) so that U = BC*V
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedT,
|
|
typename Derivedplane,
|
|
typename DerivedU,
|
|
typename DerivedG,
|
|
typename DerivedJ,
|
|
typename BCType>
|
|
IGL_INLINE void slice_tets(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedT>& T,
|
|
const Eigen::PlainObjectBase<Derivedplane> & plane,
|
|
Eigen::PlainObjectBase<DerivedU>& U,
|
|
Eigen::PlainObjectBase<DerivedG>& G,
|
|
Eigen::PlainObjectBase<DerivedJ>& J,
|
|
Eigen::SparseMatrix<BCType> & BC);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "slice_tets.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_snap_points = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SNAP_POINTS_H
|
|
#define IGL_SNAP_POINTS_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// SNAP_POINTS snap list of points C to closest of another list of points V
|
|
//
|
|
// [I,minD,VI] = snap_points(C,V)
|
|
//
|
|
// Inputs:
|
|
// C #C by dim list of query point positions
|
|
// V #V by dim list of data point positions
|
|
// Outputs:
|
|
// I #C list of indices into V of closest points to C
|
|
// minD #C list of squared (^p) distances to closest points
|
|
// VI #C by dim list of new point positions, VI = V(I,:)
|
|
template <
|
|
typename DerivedC,
|
|
typename DerivedV,
|
|
typename DerivedI,
|
|
typename DerivedminD,
|
|
typename DerivedVI>
|
|
IGL_INLINE void snap_points(
|
|
const Eigen::PlainObjectBase<DerivedC > & C,
|
|
const Eigen::PlainObjectBase<DerivedV > & V,
|
|
Eigen::PlainObjectBase<DerivedI > & I,
|
|
Eigen::PlainObjectBase<DerivedminD > & minD,
|
|
Eigen::PlainObjectBase<DerivedVI > & VI);
|
|
template <
|
|
typename DerivedC,
|
|
typename DerivedV,
|
|
typename DerivedI,
|
|
typename DerivedminD>
|
|
IGL_INLINE void snap_points(
|
|
const Eigen::PlainObjectBase<DerivedC > & C,
|
|
const Eigen::PlainObjectBase<DerivedV > & V,
|
|
Eigen::PlainObjectBase<DerivedI > & I,
|
|
Eigen::PlainObjectBase<DerivedminD > & minD);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "snap_points.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_snap_to_canonical_view_quat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SNAP_TO_CANONICAL_VIEW_QUAT_H
|
|
#define IGL_SNAP_TO_CANONICAL_VIEW_QUAT_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Geometry>
|
|
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
|
|
// such that q = x*i + y*j + z*k + w
|
|
namespace igl
|
|
{
|
|
// Snap the quaternion q to the nearest canonical view quaternion
|
|
// Input:
|
|
// q quaternion to be snapped (also see Outputs)
|
|
// threshold (optional) threshold:
|
|
// 1.0 --> snap any input
|
|
// 0.5 --> snap inputs somewhat close to canonical views
|
|
// 0.0 --> snap no input
|
|
// Output:
|
|
// q quaternion possibly set to nearest canonical view
|
|
// Return:
|
|
// true only if q was snapped to the nearest canonical view
|
|
template <typename Q_type>
|
|
IGL_INLINE bool snap_to_canonical_view_quat(
|
|
const Q_type* q,
|
|
const Q_type threshold,
|
|
Q_type* s);
|
|
|
|
template <typename Scalarq, typename Scalars>
|
|
IGL_INLINE bool snap_to_canonical_view_quat(
|
|
const Eigen::Quaternion<Scalarq> & q,
|
|
const double threshold,
|
|
Eigen::Quaternion<Scalars> & s);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "snap_to_canonical_view_quat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_snap_to_fixed_up = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SNAP_TO_FIXED_UP_H
|
|
#define IGL_SNAP_TO_FIXED_UP_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
|
|
namespace igl
|
|
{
|
|
// Snap an arbitrary rotation to a rotation resulting from a rotation about
|
|
// the y-axis then the x-axis (maintaining fixed up like
|
|
// two_axis_valuator_fixed_up.)
|
|
//
|
|
// Inputs:
|
|
// q General rotation as quaternion
|
|
// Outputs:
|
|
// s the resulting rotation (as quaternion)
|
|
//
|
|
// See also: two_axis_valuator_fixed_up
|
|
IGL_INLINE void snap_to_fixed_up(
|
|
const Eigen::Quaterniond & q,
|
|
Eigen::Quaterniond & s);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "snap_to_fixed_up.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_SolverStatus = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SOLVER_STATUS_H
|
|
#define IGL_SOLVER_STATUS_H
|
|
namespace igl
|
|
{
|
|
enum SolverStatus
|
|
{
|
|
// Good
|
|
SOLVER_STATUS_CONVERGED = 0,
|
|
// OK
|
|
SOLVER_STATUS_MAX_ITER = 1,
|
|
// Bad
|
|
SOLVER_STATUS_ERROR = 2,
|
|
NUM_SOLVER_STATUSES = 3,
|
|
};
|
|
};
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sort = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SORT_H
|
|
#define IGL_SORT_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
|
|
// Sort the elements of a matrix X along a given dimension like matlabs sort
|
|
// function
|
|
//
|
|
// Templates:
|
|
// DerivedX derived scalar type, e.g. MatrixXi or MatrixXd
|
|
// DerivedIX derived integer type, e.g. MatrixXi
|
|
// Inputs:
|
|
// X m by n matrix whose entries are to be sorted
|
|
// dim dimensional along which to sort:
|
|
// 1 sort each column (matlab default)
|
|
// 2 sort each row
|
|
// ascending sort ascending (true, matlab default) or descending (false)
|
|
// Outputs:
|
|
// Y m by n matrix whose entries are sorted
|
|
// IX m by n matrix of indices so that if dim = 1, then in matlab notation
|
|
// for j = 1:n, Y(:,j) = X(I(:,j),j); end
|
|
template <typename DerivedX, typename DerivedY, typename DerivedIX>
|
|
IGL_INLINE void sort(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const int dim,
|
|
const bool ascending,
|
|
Eigen::PlainObjectBase<DerivedY>& Y,
|
|
Eigen::PlainObjectBase<DerivedIX>& IX);
|
|
template <typename DerivedX, typename DerivedY, typename DerivedIX>
|
|
// Only better if size(X,dim) is small
|
|
IGL_INLINE void sort_new(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const int dim,
|
|
const bool ascending,
|
|
Eigen::PlainObjectBase<DerivedY>& Y,
|
|
Eigen::PlainObjectBase<DerivedIX>& IX);
|
|
// Special case if size(X,dim) == 2
|
|
template <typename DerivedX, typename DerivedY, typename DerivedIX>
|
|
IGL_INLINE void sort2(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const int dim,
|
|
const bool ascending,
|
|
Eigen::PlainObjectBase<DerivedY>& Y,
|
|
Eigen::PlainObjectBase<DerivedIX>& IX);
|
|
|
|
// Act like matlab's [Y,I] = SORT(X) for std library vectors
|
|
// Templates:
|
|
// T should be a class that implements the '<' comparator operator
|
|
// Input:
|
|
// unsorted unsorted vector
|
|
// ascending sort ascending (true, matlab default) or descending (false)
|
|
// Output:
|
|
// sorted sorted vector, allowed to be same as unsorted
|
|
// index_map an index map such that sorted[i] = unsorted[index_map[i]]
|
|
template <class T>
|
|
IGL_INLINE void sort(
|
|
const std::vector<T> &unsorted,
|
|
const bool ascending,
|
|
std::vector<T> &sorted,
|
|
std::vector<size_t> &index_map);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "sort.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sort_angles = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef SORT_ANGLES_H
|
|
#define SORT_ANGLES_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl {
|
|
// Sort angles in ascending order in a numerically robust way.
|
|
//
|
|
// Instead of computing angles using atan2(y, x), sort directly on (y, x).
|
|
//
|
|
// Inputs:
|
|
// M: m by n matrix of scalars. (n >= 2). Assuming the first column of M
|
|
// contains values for y, and the second column is x. Using the rest
|
|
// of the columns as tie-breaker.
|
|
// R: an array of m indices. M.row(R[i]) contains the i-th smallest
|
|
// angle.
|
|
template<typename DerivedM, typename DerivedR>
|
|
IGL_INLINE void sort_angles(
|
|
const Eigen::PlainObjectBase<DerivedM>& M,
|
|
Eigen::PlainObjectBase<DerivedR>& R);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "sort_angles.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sort_triangles = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SORT_TRIANGLES_H
|
|
#define IGL_SORT_TRIANGLES_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Inputs:
|
|
// V #V by **4** list of homogeneous vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// MV 4 by 4 model view matrix
|
|
// P 4 by 4 projection matrix
|
|
// Outputs:
|
|
// FF #F by 3 list of sorted triangles indices
|
|
// I #F list of sorted indices
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedMV,
|
|
typename DerivedP,
|
|
typename DerivedFF,
|
|
typename DerivedI>
|
|
IGL_INLINE void sort_triangles(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedMV> & MV,
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedI> & I);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "sort_triangles.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sort_vectors_ccw = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_SORT_VECTORS_CCW
|
|
#define IGL_SORT_VECTORS_CCW
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl {
|
|
// Sorts a set of N coplanar vectors in a ccw order, and returns their order.
|
|
// Optionally it also returns a copy of the ordered vector set, or the indices,
|
|
// in the original unordered set, of the vectors in the ordered set (called here
|
|
// the "inverse" set of indices).
|
|
|
|
// Inputs:
|
|
// P 1 by 3N row vector of the vectors to be sorted, stacked horizontally
|
|
// N #1 by 3 normal of the plane where the vectors lie
|
|
// do_sorted boolean flag, determines whether to return the sorted vector set
|
|
// do_inv_order boolean flag, determines whether to return the "inverse" set of indices
|
|
// Output:
|
|
// order N by 1 order of the vectors (indices of the unordered vectors into
|
|
// the ordered vector set)
|
|
// sorted 1 by 3N row vector of the ordered vectors, stacked horizontally
|
|
// inv_order N by 1 "inverse" order of the vectors (the indices of the ordered
|
|
// vectors into the unordered vector set)
|
|
//
|
|
template <typename DerivedS, typename DerivedI>
|
|
IGL_INLINE void sort_vectors_ccw(
|
|
const Eigen::PlainObjectBase<DerivedS>& P,
|
|
const Eigen::PlainObjectBase<DerivedS>& N,
|
|
Eigen::PlainObjectBase<DerivedI> &order,
|
|
const bool do_sorted = false,
|
|
Eigen::PlainObjectBase<DerivedS> &sorted = *(Eigen::PlainObjectBase<DerivedS>*)NULL,
|
|
const bool do_inv_order = false,
|
|
Eigen::PlainObjectBase<DerivedI> &inv_order = *(Eigen::PlainObjectBase<DerivedI> *)NULL);
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "sort_vectors_ccw.cpp"
|
|
#endif
|
|
|
|
|
|
#endif /* defined(IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS) */
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_SortableRow = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SORTABLE_ROW_H
|
|
#define IGL_SORTABLE_ROW_H
|
|
|
|
// Simple class to contain a rowvector which allows rowwise sorting and
|
|
// reordering
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Templates:
|
|
// T should be a matrix that implments .size(), and operator(int i)
|
|
template <typename T>
|
|
class SortableRow
|
|
{
|
|
public:
|
|
T data;
|
|
public:
|
|
SortableRow():data(){};
|
|
SortableRow(const T & data):data(data){};
|
|
bool operator<(const SortableRow & that) const
|
|
{
|
|
// Get reference so that I can use parenthesis
|
|
const SortableRow<T> & THIS = *this;
|
|
// Lexicographical
|
|
int minc = (THIS.data.size() < that.data.size()?
|
|
THIS.data.size() : that.data.size());
|
|
// loop over columns
|
|
for(int i = 0;i<minc;i++)
|
|
{
|
|
if(THIS.data(i) == that.data(i))
|
|
{
|
|
continue;
|
|
}
|
|
return THIS.data(i) < that.data(i);
|
|
}
|
|
// All characters the same, comes done to length
|
|
return THIS.data.size()<that.data.size();
|
|
};
|
|
bool operator==(const SortableRow & that) const
|
|
{
|
|
// Get reference so that I can use parenthesis
|
|
const SortableRow<T> & THIS = *this;
|
|
if(THIS.data.size() != that.data.size())
|
|
{
|
|
return false;
|
|
}
|
|
for(int i = 0;i<THIS.data.size();i++)
|
|
{
|
|
if(THIS.data(i) != that.data(i))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
bool operator!=(const SortableRow & that) const
|
|
{
|
|
return !(*this == that);
|
|
};
|
|
};
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sortrows = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SORTROWS_H
|
|
#define IGL_SORTROWS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Act like matlab's [Y,I] = sortrows(X)
|
|
//
|
|
// Templates:
|
|
// DerivedX derived scalar type, e.g. MatrixXi or MatrixXd
|
|
// DerivedI derived integer type, e.g. MatrixXi
|
|
// Inputs:
|
|
// X m by n matrix whose entries are to be sorted
|
|
// ascending sort ascending (true, matlab default) or descending (false)
|
|
// Outputs:
|
|
// Y m by n matrix whose entries are sorted (**should not** be same
|
|
// reference as X)
|
|
// I m list of indices so that
|
|
// Y = X(I,:);
|
|
template <typename DerivedX, typename DerivedI>
|
|
IGL_INLINE void sortrows(
|
|
const Eigen::PlainObjectBase<DerivedX>& X,
|
|
const bool ascending,
|
|
Eigen::PlainObjectBase<DerivedX>& Y,
|
|
Eigen::PlainObjectBase<DerivedI>& I);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "sortrows.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sparse = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SPARSE_H
|
|
#define IGL_SPARSE_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
namespace igl
|
|
{
|
|
// Build a sparse matrix from list of indices and values (I,J,V), functions
|
|
// like the sparse function in matlab
|
|
//
|
|
// Templates:
|
|
// IndexVector list of indices, value should be non-negative and should
|
|
// expect to be cast to an index. Must implement operator(i) to retrieve
|
|
// ith element
|
|
// ValueVector list of values, value should be expect to be cast to type
|
|
// T. Must implement operator(i) to retrieve ith element
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Input:
|
|
// I nnz vector of row indices of non zeros entries in X
|
|
// J nnz vector of column indices of non zeros entries in X
|
|
// V nnz vector of non-zeros entries in X
|
|
// Optional:
|
|
// m number of rows
|
|
// n number of cols
|
|
// Outputs:
|
|
// X m by n matrix of type T whose entries are to be found
|
|
//
|
|
template <class IndexVector, class ValueVector, typename T>
|
|
IGL_INLINE void sparse(
|
|
const IndexVector & I,
|
|
const IndexVector & J,
|
|
const ValueVector & V,
|
|
Eigen::SparseMatrix<T>& X);
|
|
template <class IndexVector, class ValueVector, typename T>
|
|
IGL_INLINE void sparse(
|
|
const IndexVector & I,
|
|
const IndexVector & J,
|
|
const ValueVector & V,
|
|
const size_t m,
|
|
const size_t n,
|
|
Eigen::SparseMatrix<T>& X);
|
|
// THIS MAY BE SUPERSEDED BY EIGEN'S .sparseView Indeed it is.
|
|
// Convert a full, dense matrix to a sparse one
|
|
//
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Input:
|
|
// D m by n full, dense matrix
|
|
// Output:
|
|
// X m by n sparse matrix
|
|
template <typename DerivedD, typename T>
|
|
IGL_INLINE void sparse(
|
|
const Eigen::PlainObjectBase<DerivedD>& D,
|
|
Eigen::SparseMatrix<T>& X);
|
|
// Wrapper with return
|
|
template <typename DerivedD>
|
|
IGL_INLINE Eigen::SparseMatrix<typename DerivedD::Scalar > sparse(
|
|
const Eigen::PlainObjectBase<DerivedD>& D);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "sparse.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_speye = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SPEYE_H
|
|
#define IGL_SPEYE_H
|
|
#include "igl_inline.h"
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Builds an m by n sparse identity matrix like matlab's speye function
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// m number of rows
|
|
// n number of cols
|
|
// Outputs:
|
|
// I m by n sparse matrix with 1's on the main diagonal
|
|
template <typename T>
|
|
IGL_INLINE void speye(const int n,const int m, Eigen::SparseMatrix<T> & I);
|
|
// Builds an n by n sparse identity matrix like matlab's speye function
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// n number of rows and cols
|
|
// Outputs:
|
|
// I n by n sparse matrix with 1's on the main diagonal
|
|
template <typename T>
|
|
IGL_INLINE void speye(const int n, Eigen::SparseMatrix<T> & I);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "speye.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_stdin_to_temp = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_STDIN_TO_TEMP_H
|
|
#define IGL_STDIN_TO_TEMP_H
|
|
#include "igl_inline.h"
|
|
#include <cstdio>
|
|
namespace igl
|
|
{
|
|
// Write stdin/piped input to a temporary file which can than be preprocessed as it
|
|
// is (a normal file). This is often useful if you want to process stdin/piped
|
|
// with library functions that expect to be able to fseek(), rewind() etc..
|
|
//
|
|
// If your application is not using fseek(), rewind(), etc. but just reading
|
|
// from stdin then this will likely cause a bottle neck as it defeats the whole
|
|
// purpose of piping.
|
|
//
|
|
// Outputs:
|
|
// temp_file pointer to temp file pointer, rewound to beginning of file so
|
|
// its ready to be read
|
|
// Return true only if no errors were found
|
|
//
|
|
// Note: Caller is responsible for closing the file (tmpfile() automatically
|
|
// unlinks the file so there is no need to remove/delete/unlink the file)
|
|
IGL_INLINE bool stdin_to_temp(FILE ** temp_file);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "stdin_to_temp.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_STR = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_STR_H
|
|
#define IGL_STR_H
|
|
// http://stackoverflow.com/a/2433143/148668
|
|
#include <string>
|
|
#include <sstream>
|
|
// Suppose you have a function:
|
|
// void func(std::string c);
|
|
// Then you can write:
|
|
// func(STR("foo"<<1<<"bar"));
|
|
#define STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str()
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_sum = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SUM_H
|
|
#define IGL_SUM_H
|
|
#include "igl_inline.h"
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Note: If your looking for dense matrix matlab like sum for eigen matrics
|
|
// just use:
|
|
// M.colwise().sum() or M.rowwise().sum()
|
|
//
|
|
|
|
// Sum the columns or rows of a sparse matrix
|
|
// Templates:
|
|
// T should be a eigen sparse matrix primitive type like int or double
|
|
// Inputs:
|
|
// X m by n sparse matrix
|
|
// dim dimension along which to sum (1 or 2)
|
|
// Output:
|
|
// S n-long sparse vector (if dim == 1)
|
|
// or
|
|
// S m-long sparse vector (if dim == 2)
|
|
template <typename T>
|
|
IGL_INLINE void sum(
|
|
const Eigen::SparseMatrix<T>& X,
|
|
const int dim,
|
|
Eigen::SparseVector<T>& S);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "sum.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_svd3x3 = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SVD3X3_H
|
|
#define IGL_SVD3X3_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Super fast 3x3 SVD according to http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html
|
|
// The resulting decomposition is A = U * diag(S[0], S[1], S[2]) * V'
|
|
// BEWARE: this SVD algorithm guarantees that det(U) = det(V) = 1, but this
|
|
// comes at the cost that 'sigma3' can be negative
|
|
// for computing polar decomposition it's great because all we need to do is U*V'
|
|
// and the result will automatically have positive determinant
|
|
//
|
|
// Inputs:
|
|
// A 3x3 matrix
|
|
// Outputs:
|
|
// U 3x3 left singular vectors
|
|
// S 3x1 singular values
|
|
// V 3x3 right singular vectors
|
|
//
|
|
// Known bugs: this will not work correctly for double precision.
|
|
template<typename T>
|
|
IGL_INLINE void svd3x3(
|
|
const Eigen::Matrix<T, 3, 3>& A,
|
|
Eigen::Matrix<T, 3, 3> &U,
|
|
Eigen::Matrix<T, 3, 1> &S,
|
|
Eigen::Matrix<T, 3, 3>&V);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "svd3x3.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_svd3x3_avx = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SVD3X3_AVX_H
|
|
#define IGL_SVD3X3_AVX_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Super fast 3x3 SVD according to
|
|
// http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html This is AVX
|
|
// version of svd3x3 (see svd3x3.h) which works on 8 matrices at a time These
|
|
// eight matrices are simply stacked in columns, the rest is the same as for
|
|
// svd3x3
|
|
//
|
|
// Inputs:
|
|
// A 12 by 3 stack of 3x3 matrices
|
|
// Outputs:
|
|
// U 12x3 left singular vectors stacked
|
|
// S 12x1 singular values stacked
|
|
// V 12x3 right singular vectors stacked
|
|
//
|
|
// Known bugs: this will not work correctly for double precision.
|
|
template<typename T>
|
|
IGL_INLINE void svd3x3_avx(
|
|
const Eigen::Matrix<T, 3*8, 3>& A,
|
|
Eigen::Matrix<T, 3*8, 3> &U,
|
|
Eigen::Matrix<T, 3*8, 1> &S,
|
|
Eigen::Matrix<T, 3*8, 3>&V);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "svd3x3_avx.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_svd3x3_sse = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_SVD3X3_SSE_H
|
|
#define IGL_SVD3X3_SSE_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
|
|
namespace igl
|
|
{
|
|
// Super fast 3x3 SVD according to http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html
|
|
// This is SSE version of svd3x3 (see svd3x3.h) which works on 4 matrices at a time
|
|
// These four matrices are simply stacked in columns, the rest is the same as for svd3x3
|
|
//
|
|
// Inputs:
|
|
// A 12 by 3 stack of 3x3 matrices
|
|
// Outputs:
|
|
// U 12x3 left singular vectors stacked
|
|
// S 12x1 singular values stacked
|
|
// V 12x3 right singular vectors stacked
|
|
//
|
|
// Known bugs: this will not work correctly for double precision.
|
|
template<typename T>
|
|
IGL_INLINE void svd3x3_sse(
|
|
const Eigen::Matrix<T, 3*4, 3>& A,
|
|
Eigen::Matrix<T, 3*4, 3> &U,
|
|
Eigen::Matrix<T, 3*4, 1> &S,
|
|
Eigen::Matrix<T, 3*4, 3>&V);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "svd3x3_sse.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_Timer = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
// High Resolution Timer.
|
|
//
|
|
// Resolution on Mac (clock tick)
|
|
// Resolution on Linux (1 us not tested)
|
|
// Resolution on Windows (clock tick not tested)
|
|
|
|
#ifndef IGL_TIMER_H
|
|
#define IGL_TIMER_H
|
|
|
|
#ifdef WIN32 // Windows system specific
|
|
#include <windows.h>
|
|
#elif __APPLE__ // Unix based system specific
|
|
#include <mach/mach_time.h> // for mach_absolute_time
|
|
#else
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
namespace igl
|
|
{
|
|
class Timer
|
|
{
|
|
public:
|
|
// default constructor
|
|
Timer():
|
|
stopped(0),
|
|
#ifdef WIN32
|
|
frequency(),
|
|
startCount(),
|
|
endCount()
|
|
#elif __APPLE__
|
|
startCount(0),
|
|
endCount(0)
|
|
#else
|
|
startCount(),
|
|
endCount()
|
|
#endif
|
|
{
|
|
#ifdef WIN32
|
|
QueryPerformanceFrequency(&frequency);
|
|
startCount.QuadPart = 0;
|
|
endCount.QuadPart = 0;
|
|
#elif __APPLE__
|
|
startCount = 0;
|
|
endCount = 0;
|
|
#else
|
|
startCount.tv_sec = startCount.tv_usec = 0;
|
|
endCount.tv_sec = endCount.tv_usec = 0;
|
|
#endif
|
|
|
|
stopped = 0;
|
|
}
|
|
// default destructor
|
|
~Timer()
|
|
{
|
|
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
//Raw mach_absolute_times going in, difference in seconds out
|
|
double subtractTimes( uint64_t endTime, uint64_t startTime )
|
|
{
|
|
uint64_t difference = endTime - startTime;
|
|
static double conversion = 0.0;
|
|
|
|
if( conversion == 0.0 )
|
|
{
|
|
mach_timebase_info_data_t info;
|
|
kern_return_t err = mach_timebase_info( &info );
|
|
|
|
//Convert the timebase into seconds
|
|
if( err == 0 )
|
|
conversion = 1e-9 * (double) info.numer / (double) info.denom;
|
|
}
|
|
|
|
return conversion * (double) difference;
|
|
}
|
|
#endif
|
|
|
|
// start timer
|
|
void start()
|
|
{
|
|
stopped = 0; // reset stop flag
|
|
#ifdef WIN32
|
|
QueryPerformanceCounter(&startCount);
|
|
#elif __APPLE__
|
|
startCount = mach_absolute_time();
|
|
#else
|
|
gettimeofday(&startCount, NULL);
|
|
#endif
|
|
|
|
}
|
|
|
|
// stop the timer
|
|
void stop()
|
|
{
|
|
stopped = 1; // set timer stopped flag
|
|
|
|
#ifdef WIN32
|
|
QueryPerformanceCounter(&endCount);
|
|
#elif __APPLE__
|
|
endCount = mach_absolute_time();
|
|
#else
|
|
gettimeofday(&endCount, NULL);
|
|
#endif
|
|
|
|
}
|
|
// get elapsed time in second
|
|
double getElapsedTime()
|
|
{
|
|
return this->getElapsedTimeInSec();
|
|
}
|
|
// get elapsed time in second (same as getElapsedTime)
|
|
double getElapsedTimeInSec()
|
|
{
|
|
return this->getElapsedTimeInMicroSec() * 0.000001;
|
|
}
|
|
|
|
// get elapsed time in milli-second
|
|
double getElapsedTimeInMilliSec()
|
|
{
|
|
return this->getElapsedTimeInMicroSec() * 0.001;
|
|
}
|
|
// get elapsed time in micro-second
|
|
double getElapsedTimeInMicroSec()
|
|
{
|
|
double startTimeInMicroSec = 0;
|
|
double endTimeInMicroSec = 0;
|
|
|
|
#ifdef WIN32
|
|
if(!stopped)
|
|
QueryPerformanceCounter(&endCount);
|
|
|
|
startTimeInMicroSec =
|
|
startCount.QuadPart * (1000000.0 / frequency.QuadPart);
|
|
endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);
|
|
#elif __APPLE__
|
|
if (!stopped)
|
|
endCount = mach_absolute_time();
|
|
|
|
return subtractTimes(endCount,startCount)/1e-6;
|
|
#else
|
|
if(!stopped)
|
|
gettimeofday(&endCount, NULL);
|
|
|
|
startTimeInMicroSec =
|
|
(startCount.tv_sec * 1000000.0) + startCount.tv_usec;
|
|
endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;
|
|
#endif
|
|
|
|
return endTimeInMicroSec - startTimeInMicroSec;
|
|
}
|
|
|
|
private:
|
|
// stop flag
|
|
int stopped;
|
|
#ifdef WIN32
|
|
// ticks per second
|
|
LARGE_INTEGER frequency;
|
|
LARGE_INTEGER startCount;
|
|
LARGE_INTEGER endCount;
|
|
#elif __APPLE__
|
|
uint64_t startCount;
|
|
uint64_t endCount;
|
|
#else
|
|
timeval startCount;
|
|
timeval endCount;
|
|
#endif
|
|
};
|
|
}
|
|
#endif // TIMER_H_DEF
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_trackball = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TRACKBALL_H
|
|
#define IGL_TRACKBALL_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
|
|
namespace igl
|
|
{
|
|
// Applies a trackball drag to identity
|
|
// Inputs:
|
|
// w width of the trackball context
|
|
// h height of the trackball context
|
|
// speed_factor controls how fast the trackball feels, 1 is normal
|
|
// down_mouse_x x position of mouse down
|
|
// down_mouse_y y position of mouse down
|
|
// mouse_x current x position of mouse
|
|
// mouse_y current y position of mouse
|
|
// Outputs:
|
|
// quat the resulting rotation (as quaternion)
|
|
template <typename Q_type>
|
|
IGL_INLINE void trackball(
|
|
const double w,
|
|
const double h,
|
|
const Q_type speed_factor,
|
|
const double down_mouse_x,
|
|
const double down_mouse_y,
|
|
const double mouse_x,
|
|
const double mouse_y,
|
|
Q_type * quat);
|
|
|
|
// Applies a trackball drag to a given rotation
|
|
// Inputs:
|
|
// w width of the trackball context
|
|
// h height of the trackball context
|
|
// speed_factor controls how fast the trackball feels, 1 is normal
|
|
// down_quat rotation at mouse down, i.e. the rotation we're applying the
|
|
// trackball motion to (as quaternion)
|
|
// down_mouse_x x position of mouse down
|
|
// down_mouse_y y position of mouse down
|
|
// mouse_x current x position of mouse
|
|
// mouse_y current y position of mouse
|
|
// Outputs:
|
|
// quat the resulting rotation (as quaternion)
|
|
template <typename Q_type>
|
|
IGL_INLINE void trackball(
|
|
const double w,
|
|
const double h,
|
|
const Q_type speed_factor,
|
|
const Q_type * down_quat,
|
|
const double down_mouse_x,
|
|
const double down_mouse_y,
|
|
const double mouse_x,
|
|
const double mouse_y,
|
|
Q_type * quat);
|
|
// Eigen wrapper.
|
|
template <typename Scalardown_quat, typename Scalarquat>
|
|
IGL_INLINE void trackball(
|
|
const double w,
|
|
const double h,
|
|
const double speed_factor,
|
|
const Eigen::Quaternion<Scalardown_quat> & down_quat,
|
|
const double down_mouse_x,
|
|
const double down_mouse_y,
|
|
const double mouse_x,
|
|
const double mouse_y,
|
|
Eigen::Quaternion<Scalarquat> & quat);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "trackball.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_transpose_blocks = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TRANSPOSE_BLOCKS_H
|
|
#define IGL_TRANSPOSE_BLOCKS_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// A m*k by n (dim: 1) or m by n*k (dim: 2) eigen Matrix of type T values
|
|
// k number of blocks
|
|
// dim dimension in which to transpose
|
|
// Output
|
|
// B n*k by m (dim: 1) or n by m*k (dim: 2) eigen Matrix of type T values,
|
|
// NOT allowed to be the same as A
|
|
//
|
|
// Example:
|
|
// A = [
|
|
// 1 2 3 4
|
|
// 5 6 7 8
|
|
// 101 102 103 104
|
|
// 105 106 107 108
|
|
// 201 202 203 204
|
|
// 205 206 207 208];
|
|
// transpose_blocks(A,1,3,B);
|
|
// B -> [
|
|
// 1 5
|
|
// 2 6
|
|
// 3 7
|
|
// 4 8
|
|
// 101 105
|
|
// 102 106
|
|
// 103 107
|
|
// 104 108
|
|
// 201 205
|
|
// 202 206
|
|
// 203 207
|
|
// 204 208];
|
|
//
|
|
template <typename T>
|
|
IGL_INLINE void transpose_blocks(
|
|
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
|
|
const size_t k,
|
|
const size_t dim,
|
|
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "transpose_blocks.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_triangle_fan = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TRIANGLE_FAN_H
|
|
#define IGL_TRIANGLE_FAN_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Given a list of faces tesselate all of the "exterior" edges forming another
|
|
// list of
|
|
//
|
|
// Inputs:
|
|
// E #E by simplex_size-1 list of exterior edges (see exterior_edges.h)
|
|
// Outputs:
|
|
// cap #cap by simplex_size list of "faces" tessleating the boundary edges
|
|
IGL_INLINE void triangle_fan(
|
|
const Eigen::MatrixXi & E,
|
|
Eigen::MatrixXi & cap);
|
|
// In-line version
|
|
IGL_INLINE Eigen::MatrixXi triangle_fan( const Eigen::MatrixXi & E);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "triangle_fan.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_triangle_triangle_adjacency = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TRIANGLE_TRIANGLE_ADJACENCY_H
|
|
#define IGL_TRIANGLE_TRIANGLE_ADJACENCY_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Constructs the triangle-triangle adjacency matrix for a given
|
|
// mesh (V,F).
|
|
//
|
|
// Templates:
|
|
// Scalar derived type of eigen matrix for V (e.g. derived from
|
|
// MatrixXd)
|
|
// Index derived type of eigen matrix for F (e.g. derived from
|
|
// MatrixXi)
|
|
// Inputs:
|
|
// V #V by dim list of mesh vertex positions
|
|
// F #F by simplex_size list of mesh faces (must be triangles)
|
|
// Outputs:
|
|
// TT #F by #3 adjacent matrix, the element i,j is the id of the triangle adjacent to the j edge of triangle i
|
|
// TTi #F by #3 adjacent matrix, the element i,j is the id of edge of the triangle TT(i,j) that is adjacent with triangle i
|
|
// NOTE: the first edge of a triangle is [0,1] the second [1,2] and the third [2,3].
|
|
// this convention is DIFFERENT from cotmatrix_entries.h
|
|
// Known bug: this should not need to take V as input.
|
|
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE void triangle_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<Scalar>& V,
|
|
const Eigen::PlainObjectBase<Index>& F,
|
|
Eigen::PlainObjectBase<Index>& TT);
|
|
// Compute triangle-triangle adjacency with indices
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE void triangle_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<Scalar>& V,
|
|
const Eigen::PlainObjectBase<Index>& F,
|
|
Eigen::PlainObjectBase<Index>& TT,
|
|
Eigen::PlainObjectBase<Index>& TTi);
|
|
|
|
template <typename DerivedF, typename DerivedTT, typename DerivedTTi>
|
|
IGL_INLINE void triangle_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedTT>& TT,
|
|
Eigen::PlainObjectBase<DerivedTTi>& TTi);
|
|
|
|
|
|
// Preprocessing
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE void triangle_triangle_adjacency_preprocess(
|
|
const Eigen::PlainObjectBase<Scalar>& V,
|
|
const Eigen::PlainObjectBase<Index>& F,
|
|
std::vector<std::vector<int> >& TTT);
|
|
template <typename DerivedF>
|
|
IGL_INLINE void triangle_triangle_adjacency_preprocess(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::vector<std::vector<int> >& TTT);
|
|
// Extract the face adjacencies
|
|
template <typename DerivedF, typename DerivedTT>
|
|
IGL_INLINE void triangle_triangle_adjacency_extractTT(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::vector<std::vector<int> >& TTT,
|
|
Eigen::PlainObjectBase<DerivedTT>& TT);
|
|
// Extract the face adjacencies indices (needed for fast traversal)
|
|
template <typename DerivedF, typename DerivedTTi>
|
|
IGL_INLINE void triangle_triangle_adjacency_extractTTi(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::vector<std::vector<int> >& TTT,
|
|
Eigen::PlainObjectBase<DerivedTTi>& TTi);
|
|
// Adjacency list version, which works with non-manifold meshes
|
|
//
|
|
// Inputs:
|
|
// F #F by 3 list of triangle indices
|
|
// Outputs:
|
|
// TT #F by 3 list of lists so that TT[i][c] --> {j,k,...} means that faces j and
|
|
// k etc. are edge-neighbors of face i on face i's edge opposite corner c
|
|
// TTj #F list of lists so that TTj[i][c] --> {j,k,...} means that face
|
|
// TT[i][c][0] is an edge-neighbor of face i incident on the edge of face
|
|
// TT[i][c][0] opposite corner j, and TT[i][c][1] " corner k, etc.
|
|
template <
|
|
typename DerivedF,
|
|
typename TTIndex,
|
|
typename TTiIndex>
|
|
IGL_INLINE void triangle_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
std::vector<std::vector<std::vector<TTIndex> > > & TT,
|
|
std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
|
|
template < typename DerivedF, typename TTIndex>
|
|
IGL_INLINE void triangle_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
std::vector<std::vector<std::vector<TTIndex> > > & TT);
|
|
// Wrapper with bool to choose whether to compute TTi (this prototype should
|
|
// be "hidden").
|
|
template <
|
|
typename DerivedF,
|
|
typename TTIndex,
|
|
typename TTiIndex>
|
|
IGL_INLINE void triangle_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const bool construct_TTi,
|
|
std::vector<std::vector<std::vector<TTIndex> > > & TT,
|
|
std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
|
|
// Inputs:
|
|
// E #F*3 by 2 list of all of directed edges in order (see `all_edges`)
|
|
// EMAP #F*3 list of indices into uE, mapping each directed edge to unique
|
|
// undirected edge
|
|
// uE2E #uE list of lists of indices into E of coexisting edges
|
|
// See also: unique_edge_map, all_edges
|
|
template <
|
|
typename DerivedE,
|
|
typename DerivedEMAP,
|
|
typename uE2EType,
|
|
typename TTIndex,
|
|
typename TTiIndex>
|
|
IGL_INLINE void triangle_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<DerivedE> & E,
|
|
const Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
|
|
const std::vector<std::vector<uE2EType > > & uE2E,
|
|
const bool construct_TTi,
|
|
std::vector<std::vector<std::vector<TTIndex> > > & TT,
|
|
std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "triangle_triangle_adjacency.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_triangles_from_strip = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TRIANGLES_FROM_STRIP_H
|
|
#define IGL_TRIANGLES_FROM_STRIP_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// TRIANGLES_FROM_STRIP Create a list of triangles from a stream of indices
|
|
// along a strip.
|
|
//
|
|
// Inputs:
|
|
// S #S list of indices
|
|
// Outputs:
|
|
// F #S-2 by 3 list of triangle indices
|
|
//
|
|
template <typename DerivedS, typename DerivedF>
|
|
IGL_INLINE void triangles_from_strip(
|
|
const Eigen::MatrixBase<DerivedS>& S,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "triangles_from_strip.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_two_axis_valuator_fixed_up = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TWO_AXIS_VALUATOR_FIXED_AXIS_UP_H
|
|
#define IGL_TWO_AXIS_VALUATOR_FIXED_AXIS_UP_H
|
|
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
|
|
namespace igl
|
|
{
|
|
// Applies a two-axis valuator drag rotation (as seen in Maya/Studio max) to a given rotation.
|
|
// Inputs:
|
|
// w width of the trackball context
|
|
// h height of the trackball context
|
|
// speed controls how fast the trackball feels, 1 is normal
|
|
// down_quat rotation at mouse down, i.e. the rotation we're applying the
|
|
// trackball motion to (as quaternion). **Note:** Up-vector that is fixed
|
|
// is with respect to this rotation.
|
|
// down_x position of mouse down
|
|
// down_y position of mouse down
|
|
// mouse_x current x position of mouse
|
|
// mouse_y current y position of mouse
|
|
// Outputs:
|
|
// quat the resulting rotation (as quaternion)
|
|
//
|
|
// See also: snap_to_fixed_up
|
|
template <typename Scalardown_quat, typename Scalarquat>
|
|
IGL_INLINE void two_axis_valuator_fixed_up(
|
|
const int w,
|
|
const int h,
|
|
const double speed,
|
|
const Eigen::Quaternion<Scalardown_quat> & down_quat,
|
|
const int down_x,
|
|
const int down_y,
|
|
const int mouse_x,
|
|
const int mouse_y,
|
|
Eigen::Quaternion<Scalarquat> & quat);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "two_axis_valuator_fixed_up.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_uniformly_sample_two_manifold = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_UNIFORMLY_SAMPLE_TWO_MANIFOLD_H
|
|
#define IGL_UNIFORMLY_SAMPLE_TWO_MANIFOLD_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// UNIFORMLY_SAMPLE_TWO_MANIFOLD Attempt to sample a mesh uniformly by furthest
|
|
// point relaxation as described in "Fast Automatic Skinning Transformations"
|
|
// [Jacobson et al. 12] Section 3.3.
|
|
//
|
|
// Inputs:
|
|
// W #W by dim positions of mesh in weight space
|
|
// F #F by 3 indices of triangles
|
|
// k number of samplse
|
|
// push factor by which corners should be pushed away
|
|
// Outputs
|
|
// WS k by dim locations in weights space
|
|
//
|
|
IGL_INLINE void uniformly_sample_two_manifold(
|
|
const Eigen::MatrixXd & W,
|
|
const Eigen::MatrixXi & F,
|
|
const int k,
|
|
const double push,
|
|
Eigen::MatrixXd & WS);
|
|
// Find uniform sampling up to placing samples on mesh vertices
|
|
IGL_INLINE void uniformly_sample_two_manifold_at_vertices(
|
|
const Eigen::MatrixXd & OW,
|
|
const int k,
|
|
const double push,
|
|
Eigen::VectorXi & S);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "uniformly_sample_two_manifold.h"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_unique = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_UNIQUE_H
|
|
#define IGL_UNIQUE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Act like matlab's [C,IA,IC] = unique(X)
|
|
//
|
|
// Templates:
|
|
// T comparable type T
|
|
// Inputs:
|
|
// A #A vector of type T
|
|
// Outputs:
|
|
// C #C vector of unique entries in A
|
|
// IA #C index vector so that C = A(IA);
|
|
// IC #A index vector so that A = C(IC);
|
|
template <typename T>
|
|
IGL_INLINE void unique(
|
|
const std::vector<T> & A,
|
|
std::vector<T> & C,
|
|
std::vector<size_t> & IA,
|
|
std::vector<size_t> & IC);
|
|
template <typename T>
|
|
IGL_INLINE void unique(
|
|
const std::vector<T> & A,
|
|
std::vector<T> & C);
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedC,
|
|
typename DerivedIA,
|
|
typename DerivedIC>
|
|
IGL_INLINE void unique(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
Eigen::PlainObjectBase<DerivedC> & C,
|
|
Eigen::PlainObjectBase<DerivedIA> & IA,
|
|
Eigen::PlainObjectBase<DerivedIC> & IC);
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedC,
|
|
typename DerivedIA,
|
|
typename DerivedIC>
|
|
IGL_INLINE void unique(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
// Act like matlab's [C,IA,IC] = unique(X,'rows')
|
|
//
|
|
// Templates:
|
|
// DerivedA derived scalar type, e.g. MatrixXi or MatrixXd
|
|
// DerivedIA derived integer type, e.g. MatrixXi
|
|
// DerivedIC derived integer type, e.g. MatrixXi
|
|
// Inputs:
|
|
// A m by n matrix whose entries are to unique'd according to rows
|
|
// Outputs:
|
|
// C #C vector of unique rows in A
|
|
// IA #C index vector so that C = A(IA,:);
|
|
// IC #A index vector so that A = C(IC,:);
|
|
template <typename DerivedA, typename DerivedIA, typename DerivedIC>
|
|
IGL_INLINE void unique_rows(
|
|
const Eigen::PlainObjectBase<DerivedA>& A,
|
|
Eigen::PlainObjectBase<DerivedA>& C,
|
|
Eigen::PlainObjectBase<DerivedIA>& IA,
|
|
Eigen::PlainObjectBase<DerivedIC>& IC);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unique.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_unique_edge_map = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_UNIQUE_EDGE_MAP_H
|
|
#define IGL_UNIQUE_EDGE_MAP_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Constuct relationships between facet "half"-(or rather "viewed")-edges E
|
|
// to unique edges of the mesh seen as a graph.
|
|
//
|
|
// Inputs:
|
|
// F #F by 3 list of simplices
|
|
// Outputs:
|
|
// E #F*3 by 2 list of all of directed edges
|
|
// uE #uE by 2 list of unique undirected edges
|
|
// EMAP #F*3 list of indices into uE, mapping each directed edge to unique
|
|
// undirected edge
|
|
// uE2E #uE list of lists of indices into E of coexisting edges
|
|
template <
|
|
typename DerivedF,
|
|
typename DerivedE,
|
|
typename DeriveduE,
|
|
typename DerivedEMAP,
|
|
typename uE2EType>
|
|
IGL_INLINE void unique_edge_map(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedE> & E,
|
|
Eigen::PlainObjectBase<DeriveduE> & uE,
|
|
Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
|
|
std::vector<std::vector<uE2EType> > & uE2E);
|
|
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unique_edge_map.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_unique_simplices = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_UNIQUE_SIMPLICES_H
|
|
#define IGL_UNIQUE_SIMPLICES_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
// Find *combinatorially* unique simplices in F. **Order independent**
|
|
//
|
|
// Inputs:
|
|
// F #F by simplex-size list of simplices
|
|
// Outputs:
|
|
// FF #FF by simplex-size list of unique simplices in F
|
|
// IA #FF index vector so that FF == sort(F(IA,:),2);
|
|
// IC #F index vector so that sort(F,2) == FF(IC,:);
|
|
template <
|
|
typename DerivedF,
|
|
typename DerivedFF,
|
|
typename DerivedIA,
|
|
typename DerivedIC>
|
|
IGL_INLINE void unique_simplices(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedFF>& FF,
|
|
Eigen::PlainObjectBase<DerivedIA>& IA,
|
|
Eigen::PlainObjectBase<DerivedIC>& IC);
|
|
template <
|
|
typename DerivedF,
|
|
typename DerivedFF>
|
|
IGL_INLINE void unique_simplices(
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedFF>& FF);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unique_simplices.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_unproject = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_UNPROJECT_H
|
|
#define IGL_UNPROJECT_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// Eigen reimplementation of gluUnproject
|
|
// Inputs:
|
|
// win screen space x, y, and z coordinates
|
|
// Returns:
|
|
// the unprojected x, y, and z coordinates
|
|
// Returns return value of gluUnProject call
|
|
template <typename Scalar>
|
|
IGL_INLINE Eigen::Matrix<Scalar,3,1> unproject(
|
|
const Eigen::Matrix<Scalar,3,1>& win,
|
|
const Eigen::Matrix<Scalar,4,4>& model,
|
|
const Eigen::Matrix<Scalar,4,4>& proj,
|
|
const Eigen::Matrix<Scalar,4,1>& viewport);
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unproject.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_upsample = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_UPSAMPLE_H
|
|
#define IGL_UPSAMPLE_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
|
|
// History:
|
|
// changed templates from generic matrices to PlainObjectBase Alec May 7, 2011
|
|
namespace igl
|
|
{
|
|
// Subdivide a mesh without moving vertices: loop subdivision but odd
|
|
// vertices stay put and even vertices are just edge midpoints
|
|
//
|
|
// Templates:
|
|
// MatV matrix for vertex positions, e.g. MatrixXd
|
|
// MatF matrix for vertex positions, e.g. MatrixXi
|
|
// Inputs:
|
|
// V #V by dim mesh vertices
|
|
// F #F by 3 mesh triangles
|
|
// Outputs:
|
|
// NV new vertex positions, V is guaranteed to be at top
|
|
// NF new list of face indices
|
|
//
|
|
// NOTE: V should not be the same as NV,
|
|
// NOTE: F should not be the same as NF, use other proto
|
|
//
|
|
// Known issues:
|
|
// - assumes (V,F) is edge-manifold.
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedNV,
|
|
typename DerivedNF>
|
|
IGL_INLINE void upsample(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
Eigen::PlainObjectBase<DerivedNV>& NV,
|
|
Eigen::PlainObjectBase<DerivedNF>& NF);
|
|
// Virtually in place wrapper
|
|
template <
|
|
typename MatV,
|
|
typename MatF>
|
|
IGL_INLINE void upsample(
|
|
MatV& V,
|
|
MatF& F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "upsample.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_vector_area_matrix = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_AREAMATRIX_H
|
|
#define IGL_AREAMATRIX_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
// Constructs the symmetric area matrix A, s.t. [V.col(0)' V.col(1)'] * A *
|
|
// [V.col(0); V.col(1)] is the **vector area** of the mesh (V,F).
|
|
//
|
|
// Templates:
|
|
// DerivedV derived type of eigen matrix for V (e.g. derived from
|
|
// MatrixXd)
|
|
// DerivedF derived type of eigen matrix for F (e.g. derived from
|
|
// MatrixXi)
|
|
// Scalar scalar type for eigen sparse matrix (e.g. double)
|
|
// Inputs:
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// Outputs:
|
|
// A #Vx2 by #Vx2 area matrix
|
|
//
|
|
template <typename DerivedF, typename Scalar>
|
|
IGL_INLINE void vector_area_matrix(
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::SparseMatrix<Scalar>& A);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "vector_area_matrix.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_verbose = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VERBOSE_H
|
|
#define IGL_VERBOSE_H
|
|
|
|
// This function is only useful as a header-only inlined function
|
|
|
|
namespace igl
|
|
{
|
|
// Provide a wrapper for printf, called verbose that functions exactly like
|
|
// printf if VERBOSE is defined and does exactly nothing if VERBOSE is
|
|
// undefined
|
|
inline int verbose(const char * msg,...);
|
|
}
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
#ifdef VERBOSE
|
|
# include <cstdarg>
|
|
#endif
|
|
|
|
#include <string>
|
|
// http://channel9.msdn.com/forums/techoff/254707-wrapping-printf-in-c/
|
|
#ifdef VERBOSE
|
|
inline int igl::verbose(const char * msg,...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, msg);
|
|
int count = vprintf(msg, argList);
|
|
va_end(argList);
|
|
return count;
|
|
}
|
|
#else
|
|
inline int igl::verbose(const char * /*msg*/,...)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_vertex_triangle_adjacency = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VERTEX_TRIANGLE_ADJACENCY_H
|
|
#define IGL_VERTEX_TRIANGLE_ADJACENCY_H
|
|
#include <igl/igl_inline.h>
|
|
|
|
#include <Eigen/Dense>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// vertex_face_adjacency constructs the vertex-face topology of a given mesh (V,F)
|
|
//
|
|
// Inputs:
|
|
// //V #V by 3 list of vertex coordinates
|
|
// n number of vertices #V (e.g. `F.maxCoeff()+1` or `V.rows()`)
|
|
// F #F by dim list of mesh faces (must be triangles)
|
|
// Outputs:
|
|
// VF #V list of lists of incident faces (adjacency list)
|
|
// VI #V list of lists of index of incidence within incident faces listed
|
|
// in VF
|
|
//
|
|
// See also: edges, cotmatrix, diag, vv
|
|
//
|
|
// Known bugs: this should not take V as an input parameter.
|
|
// Known bugs/features: if a facet is combinatorially degenerate then faces
|
|
// will appear multiple times in VF and correpondingly in VFI (j appears
|
|
// twice in F.row(i) then i will appear twice in VF[j])
|
|
template <typename DerivedF, typename VFType, typename VFiType>
|
|
IGL_INLINE void vertex_triangle_adjacency(
|
|
const typename DerivedF::Scalar n,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::vector<std::vector<VFType> >& VF,
|
|
std::vector<std::vector<VFiType> >& VFi);
|
|
template <typename DerivedV, typename DerivedF, typename IndexType>
|
|
IGL_INLINE void vertex_triangle_adjacency(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
std::vector<std::vector<IndexType> >& VF,
|
|
std::vector<std::vector<IndexType> >& VFi);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "vertex_triangle_adjacency.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_Viewport = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VIEWPORT_H
|
|
#define IGL_VIEWPORT_H
|
|
|
|
namespace igl
|
|
{
|
|
struct Viewport
|
|
{
|
|
int x,y,width,height;
|
|
// Constructors
|
|
Viewport(
|
|
const int x=0,
|
|
const int y=0,
|
|
const int width=0,
|
|
const int height=0):
|
|
x(x),
|
|
y(y),
|
|
width(width),
|
|
height(height)
|
|
{
|
|
};
|
|
virtual ~Viewport(){}
|
|
void reshape(
|
|
const int x,
|
|
const int y,
|
|
const int width,
|
|
const int height)
|
|
{
|
|
this->x = x;
|
|
this->y = y;
|
|
this->width = width;
|
|
this->height = height;
|
|
};
|
|
// Given mouse_x,mouse_y on the entire window return mouse_x, mouse_y in
|
|
// this viewport.
|
|
//
|
|
// Inputs:
|
|
// my mouse y-coordinate
|
|
// wh window height
|
|
// Returns y-coordinate in viewport
|
|
int mouse_y(const int my,const int wh)
|
|
{
|
|
return my - (wh - height - y);
|
|
}
|
|
// Inputs:
|
|
// mx mouse x-coordinate
|
|
// Returns x-coordinate in viewport
|
|
int mouse_x(const int mx)
|
|
{
|
|
return mx - x;
|
|
}
|
|
// Returns whether point (mx,my) is in extend of Viewport
|
|
bool inside(const int mx, const int my) const
|
|
{
|
|
return
|
|
mx >= x && my >= y &&
|
|
mx < x+width && my < y+height;
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_volume = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VOLUME_H
|
|
#define IGL_VOLUME_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
// VOLUME Compute volume for all tets of a given tet mesh
|
|
// (V,T)
|
|
//
|
|
// vol = volume(V,T)
|
|
//
|
|
// Inputs:
|
|
// V #V by dim list of vertex positions
|
|
// T #V by 4 list of tet indices
|
|
// Outputs:
|
|
// vol #T list of dihedral angles (in radians)
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedT,
|
|
typename Derivedvol>
|
|
IGL_INLINE void volume(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedT>& T,
|
|
Eigen::PlainObjectBase<Derivedvol>& vol);
|
|
template <
|
|
typename DerivedA,
|
|
typename DerivedB,
|
|
typename DerivedC,
|
|
typename DerivedD,
|
|
typename Derivedvol>
|
|
IGL_INLINE void volume(
|
|
const Eigen::PlainObjectBase<DerivedA> & A,
|
|
const Eigen::PlainObjectBase<DerivedB> & B,
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedD> & D,
|
|
Eigen::PlainObjectBase<Derivedvol> & vol);
|
|
// Single tet
|
|
template <
|
|
typename VecA,
|
|
typename VecB,
|
|
typename VecC,
|
|
typename VecD>
|
|
IGL_INLINE typename VecA::Scalar volume_single(
|
|
const VecA & a,
|
|
const VecB & b,
|
|
const VecC & c,
|
|
const VecD & d);
|
|
// Intrinsic version:
|
|
//
|
|
// Inputs:
|
|
// L #V by 6 list of edge lengths (see edge_lengths)
|
|
template <
|
|
typename DerivedL,
|
|
typename Derivedvol>
|
|
IGL_INLINE void volume(
|
|
const Eigen::PlainObjectBase<DerivedL>& L,
|
|
Eigen::PlainObjectBase<Derivedvol>& vol);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "volume.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_winding_number = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WINDING_NUMBER_H
|
|
#define IGL_WINDING_NUMBER_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
// Minimum number of iterms per openmp thread
|
|
#ifndef IGL_WINDING_NUMBER_OMP_MIN_VALUE
|
|
# define IGL_WINDING_NUMBER_OMP_MIN_VALUE 1000
|
|
#endif
|
|
namespace igl
|
|
{
|
|
// WINDING_NUMBER Compute the sum of solid angles of a triangle/tetrahedron
|
|
// described by points (vectors) V
|
|
//
|
|
// Templates:
|
|
// dim dimension of input
|
|
// Inputs:
|
|
// V n by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices, minimum index is 0
|
|
// O no by 3 list of origin positions
|
|
// Outputs:
|
|
// S no by 1 list of winding numbers
|
|
//
|
|
// 3d
|
|
IGL_INLINE void winding_number(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & O,
|
|
Eigen::VectorXd & W);
|
|
// Inputs:
|
|
// V pointer to array containing #V by 3 vertex positions along rows,
|
|
// given in column major order
|
|
// n number of mesh vertices
|
|
// F pointer to array containing #F by 3 face indices along rows,
|
|
// given in column major order
|
|
// m number of faces
|
|
// O pointer to array containing #O by 3 query positions along rows,
|
|
// given in column major order
|
|
// no number of origins
|
|
// Outputs:
|
|
// S no by 1 list of winding numbers
|
|
template <typename Scalar, typename DerivedF>
|
|
IGL_INLINE void winding_number_3(
|
|
const Scalar * V,
|
|
const int n,
|
|
const DerivedF * F,
|
|
const int m,
|
|
const Scalar * O,
|
|
const int no,
|
|
Scalar * S);
|
|
//// Only one evaluation origin
|
|
//template <typename DerivedF>
|
|
//IGL_INLINE void winding_number_3(
|
|
// const double * V,
|
|
// const int n,
|
|
// const DerivedF * F,
|
|
// const int m,
|
|
// const double * O,
|
|
// double * S);
|
|
// 2d
|
|
template <typename DerivedF>
|
|
IGL_INLINE void winding_number_2(
|
|
const double * V,
|
|
const int n,
|
|
const DerivedF * F,
|
|
const int m,
|
|
const double * O,
|
|
const int no,
|
|
double * S);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "winding_number.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_WindingNumberAABB = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
// # MUTUAL DEPENDENCY ISSUE FOR HEADER ONLY VERSION
|
|
// MUST INCLUDE winding_number.h first before guard:
|
|
#include "winding_number.h"
|
|
|
|
#ifndef IGL_WINDINGNUMBERAABB_H
|
|
#define IGL_WINDINGNUMBERAABB_H
|
|
#include "WindingNumberTree.h"
|
|
|
|
namespace igl
|
|
{
|
|
template <typename Point>
|
|
class WindingNumberAABB : public WindingNumberTree<Point>
|
|
{
|
|
protected:
|
|
Point min_corner;
|
|
Point max_corner;
|
|
double total_positive_area;
|
|
public:
|
|
enum SplitMethod
|
|
{
|
|
CENTER_ON_LONGEST_AXIS = 0,
|
|
MEDIAN_ON_LONGEST_AXIS = 1,
|
|
NUM_SPLIT_METHODS = 2
|
|
} split_method;
|
|
public:
|
|
inline WindingNumberAABB():
|
|
total_positive_area(std::numeric_limits<double>::infinity()),
|
|
split_method(MEDIAN_ON_LONGEST_AXIS)
|
|
{}
|
|
inline WindingNumberAABB(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F);
|
|
inline WindingNumberAABB(
|
|
const WindingNumberTree<Point> & parent,
|
|
const Eigen::MatrixXi & F);
|
|
// Initialize some things
|
|
inline void set_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F);
|
|
inline void init();
|
|
inline bool inside(const Point & p) const;
|
|
inline virtual void grow();
|
|
// Compute min and max corners
|
|
inline void compute_min_max_corners();
|
|
inline double max_abs_winding_number(const Point & p) const;
|
|
inline double max_simple_abs_winding_number(const Point & p) const;
|
|
};
|
|
}
|
|
|
|
// Implementation
|
|
|
|
#include "winding_number.h"
|
|
|
|
#include "barycenter.h"
|
|
#include "median.h"
|
|
#include "doublearea.h"
|
|
#include "per_face_normals.h"
|
|
|
|
#include <limits>
|
|
#include <vector>
|
|
#include <iostream>
|
|
|
|
// Minimum number of faces in a hierarchy element (this is probably dependent
|
|
// on speed of machine and compiler optimization)
|
|
#ifndef WindingNumberAABB_MIN_F
|
|
# define WindingNumberAABB_MIN_F 100
|
|
#endif
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberAABB<Point>::set_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F)
|
|
{
|
|
igl::WindingNumberTree<Point>::set_mesh(V,F);
|
|
init();
|
|
}
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberAABB<Point>::init()
|
|
{
|
|
using namespace Eigen;
|
|
assert(max_corner.size() == 3);
|
|
assert(min_corner.size() == 3);
|
|
compute_min_max_corners();
|
|
VectorXd dblA;
|
|
doublearea(this->getV(),this->getF(),dblA);
|
|
total_positive_area = dblA.sum()/2.0;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline igl::WindingNumberAABB<Point>::WindingNumberAABB(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F):
|
|
WindingNumberTree<Point>(V,F),
|
|
min_corner(),
|
|
max_corner(),
|
|
total_positive_area(std::numeric_limits<double>::infinity()),
|
|
split_method(MEDIAN_ON_LONGEST_AXIS)
|
|
{
|
|
init();
|
|
}
|
|
|
|
template <typename Point>
|
|
inline igl::WindingNumberAABB<Point>::WindingNumberAABB(
|
|
const WindingNumberTree<Point> & parent,
|
|
const Eigen::MatrixXi & F):
|
|
WindingNumberTree<Point>(parent,F),
|
|
min_corner(),
|
|
max_corner(),
|
|
total_positive_area(std::numeric_limits<double>::infinity()),
|
|
split_method(MEDIAN_ON_LONGEST_AXIS)
|
|
{
|
|
init();
|
|
}
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberAABB<Point>::grow()
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
//cout<<"cap.rows(): "<<this->getcap().rows()<<endl;
|
|
//cout<<"F.rows(): "<<this->getF().rows()<<endl;
|
|
|
|
// Base cases
|
|
if(
|
|
this->getF().rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) ||
|
|
(this->getcap().rows() - 2) >= this->getF().rows())
|
|
{
|
|
// Don't grow
|
|
return;
|
|
}
|
|
|
|
// Compute longest direction
|
|
int max_d = -1;
|
|
double max_len = -numeric_limits<double>::infinity();
|
|
for(int d = 0;d<min_corner.size();d++)
|
|
{
|
|
if( (max_corner[d] - min_corner[d]) > max_len )
|
|
{
|
|
max_len = (max_corner[d] - min_corner[d]);
|
|
max_d = d;
|
|
}
|
|
}
|
|
// Compute facet barycenters
|
|
MatrixXd BC;
|
|
barycenter(this->getV(),this->getF(),BC);
|
|
|
|
|
|
// Blerg, why is selecting rows so difficult
|
|
|
|
double split_value;
|
|
// Split in longest direction
|
|
switch(split_method)
|
|
{
|
|
case MEDIAN_ON_LONGEST_AXIS:
|
|
// Determine median
|
|
median(BC.col(max_d),split_value);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
case CENTER_ON_LONGEST_AXIS:
|
|
split_value = 0.5*(max_corner[max_d] + min_corner[max_d]);
|
|
break;
|
|
}
|
|
//cout<<"c: "<<0.5*(max_corner[max_d] + min_corner[max_d])<<" "<<
|
|
// "m: "<<split_value<<endl;;
|
|
|
|
vector<int> id( this->getF().rows());
|
|
for(int i = 0;i<this->getF().rows();i++)
|
|
{
|
|
if(BC(i,max_d) <= split_value)
|
|
{
|
|
id[i] = 0; //left
|
|
}else
|
|
{
|
|
id[i] = 1; //right
|
|
}
|
|
}
|
|
|
|
const int lefts = (int) count(id.begin(),id.end(),0);
|
|
const int rights = (int) count(id.begin(),id.end(),1);
|
|
if(lefts == 0 || rights == 0)
|
|
{
|
|
// badly balanced base case (could try to recut)
|
|
return;
|
|
}
|
|
assert(lefts+rights == this->getF().rows());
|
|
MatrixXi leftF(lefts, this->getF().cols());
|
|
MatrixXi rightF(rights,this->getF().cols());
|
|
int left_i = 0;
|
|
int right_i = 0;
|
|
for(int i = 0;i<this->getF().rows();i++)
|
|
{
|
|
if(id[i] == 0)
|
|
{
|
|
leftF.row(left_i++) = this->getF().row(i);
|
|
}else if(id[i] == 1)
|
|
{
|
|
rightF.row(right_i++) = this->getF().row(i);
|
|
}else
|
|
{
|
|
assert(false);
|
|
}
|
|
}
|
|
assert(right_i == rightF.rows());
|
|
assert(left_i == leftF.rows());
|
|
// Finally actually grow children and Recursively grow
|
|
WindingNumberAABB<Point> * leftWindingNumberAABB = new WindingNumberAABB<Point>(*this,leftF);
|
|
leftWindingNumberAABB->grow();
|
|
this->children.push_back(leftWindingNumberAABB);
|
|
WindingNumberAABB<Point> * rightWindingNumberAABB = new WindingNumberAABB<Point>(*this,rightF);
|
|
rightWindingNumberAABB->grow();
|
|
this->children.push_back(rightWindingNumberAABB);
|
|
}
|
|
|
|
template <typename Point>
|
|
inline bool igl::WindingNumberAABB<Point>::inside(const Point & p) const
|
|
{
|
|
assert(p.size() == max_corner.size());
|
|
assert(p.size() == min_corner.size());
|
|
for(int i = 0;i<p.size();i++)
|
|
{
|
|
//// Perfect matching is **not** robust
|
|
//if( p(i) < min_corner(i) || p(i) >= max_corner(i))
|
|
// **MUST** be conservative
|
|
if( p(i) < min_corner(i) || p(i) > max_corner(i))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberAABB<Point>::compute_min_max_corners()
|
|
{
|
|
using namespace std;
|
|
// initialize corners
|
|
for(int d = 0;d<min_corner.size();d++)
|
|
{
|
|
min_corner[d] = numeric_limits<double>::infinity();
|
|
max_corner[d] = -numeric_limits<double>::infinity();
|
|
}
|
|
|
|
this->center = Point(0,0,0);
|
|
// Loop over facets
|
|
for(int i = 0;i<this->getF().rows();i++)
|
|
{
|
|
for(int j = 0;j<this->getF().cols();j++)
|
|
{
|
|
for(int d = 0;d<min_corner.size();d++)
|
|
{
|
|
min_corner[d] =
|
|
this->getV()(this->getF()(i,j),d) < min_corner[d] ?
|
|
this->getV()(this->getF()(i,j),d) : min_corner[d];
|
|
max_corner[d] =
|
|
this->getV()(this->getF()(i,j),d) > max_corner[d] ?
|
|
this->getV()(this->getF()(i,j),d) : max_corner[d];
|
|
}
|
|
// This is biased toward vertices incident on more than one face, but
|
|
// perhaps that's good
|
|
this->center += this->getV().row(this->getF()(i,j));
|
|
}
|
|
}
|
|
// Average
|
|
this->center.array() /= this->getF().size();
|
|
|
|
//cout<<"min_corner: "<<this->min_corner.transpose()<<endl;
|
|
//cout<<"Center: "<<this->center.transpose()<<endl;
|
|
//cout<<"max_corner: "<<this->max_corner.transpose()<<endl;
|
|
//cout<<"Diag center: "<<((this->max_corner + this->min_corner)*0.5).transpose()<<endl;
|
|
//cout<<endl;
|
|
|
|
this->radius = (max_corner-min_corner).norm()/2.0;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberAABB<Point>::max_abs_winding_number(const Point & p) const
|
|
{
|
|
using namespace std;
|
|
// Only valid if not inside
|
|
if(inside(p))
|
|
{
|
|
return numeric_limits<double>::infinity();
|
|
}
|
|
// Q: we know the total positive area so what's the most this could project
|
|
// to? Remember it could be layered in the same direction.
|
|
return numeric_limits<double>::infinity();
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberAABB<Point>::max_simple_abs_winding_number(const Point & p) const
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
// Only valid if not inside
|
|
if(inside(p))
|
|
{
|
|
return numeric_limits<double>::infinity();
|
|
}
|
|
// Max simple is the same as sum of positive winding number contributions of
|
|
// bounding box
|
|
|
|
// begin precomputation
|
|
//MatrixXd BV((int)pow(2,3),3);
|
|
MatrixXd BV((int)(1<<3),3);
|
|
BV <<
|
|
min_corner[0],min_corner[1],min_corner[2],
|
|
min_corner[0],min_corner[1],max_corner[2],
|
|
min_corner[0],max_corner[1],min_corner[2],
|
|
min_corner[0],max_corner[1],max_corner[2],
|
|
max_corner[0],min_corner[1],min_corner[2],
|
|
max_corner[0],min_corner[1],max_corner[2],
|
|
max_corner[0],max_corner[1],min_corner[2],
|
|
max_corner[0],max_corner[1],max_corner[2];
|
|
MatrixXi BF(2*2*3,3);
|
|
BF <<
|
|
0,6,4,
|
|
0,2,6,
|
|
0,3,2,
|
|
0,1,3,
|
|
2,7,6,
|
|
2,3,7,
|
|
4,6,7,
|
|
4,7,5,
|
|
0,4,5,
|
|
0,5,1,
|
|
1,5,7,
|
|
1,7,3;
|
|
MatrixXd BFN;
|
|
per_face_normals(BV,BF,BFN);
|
|
// end of precomputation
|
|
|
|
// Only keep those with positive dot products
|
|
MatrixXi PBF(BF.rows(),BF.cols());
|
|
int pbfi = 0;
|
|
Point p2c = 0.5*(min_corner+max_corner)-p;
|
|
for(int i = 0;i<BFN.rows();i++)
|
|
{
|
|
if(p2c.dot(BFN.row(i)) > 0)
|
|
{
|
|
PBF.row(pbfi++) = BF.row(i);
|
|
}
|
|
}
|
|
PBF.conservativeResize(pbfi,PBF.cols());
|
|
double w = numeric_limits<double>::infinity();
|
|
igl::winding_number_3(
|
|
BV.data(),
|
|
BV.rows(),
|
|
PBF.data(),
|
|
PBF.rows(),
|
|
p.data(),
|
|
1,
|
|
&w);
|
|
return w;
|
|
}
|
|
|
|
//// Explicit instanciation
|
|
//template class igl::WindingNumberAABB<Eigen::Vector3d >;
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_WindingNumberMethod = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WINDINGNUMBERMETHOD_H
|
|
#define IGL_WINDINGNUMBERMETHOD_H
|
|
namespace igl
|
|
{
|
|
enum WindingNumberMethod
|
|
{
|
|
EXACT_WINDING_NUMBER_METHOD = 0, // Exact hierarchical evaluation
|
|
APPROX_SIMPLE_WINDING_NUMBER_METHOD = 1,
|
|
APPROX_CACHE_WINDING_NUMBER_METHOD = 2, // Approximate hierarchical evaluation
|
|
NUM_WINDING_NUMBER_METHODS = 3
|
|
};
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_WindingNumberTree = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WINDINGNUMBERTREE_H
|
|
#define IGL_WINDINGNUMBERTREE_H
|
|
#include <list>
|
|
#include <map>
|
|
#include <Eigen/Dense>
|
|
#include "WindingNumberMethod.h"
|
|
|
|
static Eigen::MatrixXd dummyV;
|
|
namespace igl
|
|
{
|
|
// Templates:
|
|
// Point type for points in space, e.g. Eigen::Vector3d
|
|
template <typename Point>
|
|
class WindingNumberTree
|
|
{
|
|
public:
|
|
// Method to use (see enum above)
|
|
//static double min_max_w;
|
|
static std::map<
|
|
std::pair<const WindingNumberTree*,const WindingNumberTree*>, double>
|
|
cached;
|
|
protected:
|
|
WindingNumberMethod method;
|
|
const WindingNumberTree * parent;
|
|
std::list<WindingNumberTree * > children;
|
|
//// List of boundary edges (recall edges are vertices in 2d)
|
|
//const Eigen::MatrixXi boundary;
|
|
// Base mesh vertices
|
|
Eigen::MatrixXd & V;
|
|
// Base mesh vertices with duplicates removed
|
|
Eigen::MatrixXd SV;
|
|
// Facets in this bounding volume
|
|
Eigen::MatrixXi F;
|
|
// Tesselated boundary curve
|
|
Eigen::MatrixXi cap;
|
|
// Upper Bound on radius of enclosing ball
|
|
double radius;
|
|
// (Approximate) center (of mass)
|
|
Point center;
|
|
public:
|
|
inline WindingNumberTree();
|
|
// For root
|
|
inline WindingNumberTree(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F);
|
|
// For chilluns
|
|
inline WindingNumberTree(
|
|
const WindingNumberTree<Point> & parent,
|
|
const Eigen::MatrixXi & F);
|
|
inline virtual ~WindingNumberTree();
|
|
inline virtual void set_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F);
|
|
// Set method
|
|
inline void set_method( const WindingNumberMethod & m);
|
|
public:
|
|
inline const Eigen::MatrixXd & getV() const;
|
|
inline const Eigen::MatrixXi & getF() const;
|
|
inline const Eigen::MatrixXi & getcap() const;
|
|
// Grow the Tree recursively
|
|
inline virtual void grow();
|
|
// Determine whether a given point is inside the bounding
|
|
//
|
|
// Inputs:
|
|
// p query point
|
|
// Returns true if the point p is inside this bounding volume
|
|
inline virtual bool inside(const Point & p) const;
|
|
// Compute the (partial) winding number of a given point p
|
|
// According to method
|
|
//
|
|
// Inputs:
|
|
// p query point
|
|
// Returns winding number
|
|
inline double winding_number(const Point & p) const;
|
|
// Same as above, but always computes winding number using exact method
|
|
// (sum over every facet)
|
|
inline double winding_number_all(const Point & p) const;
|
|
// Same as above, but always computes using sum over tesslated boundary
|
|
inline double winding_number_boundary(const Point & p) const;
|
|
//// Same as winding_number above, but if max_simple_abs_winding_number is
|
|
//// less than some threshold min_max_w just return 0 (colloquially the "fast
|
|
//// multipole method)
|
|
////
|
|
////
|
|
//// Inputs:
|
|
//// p query point
|
|
//// min_max_w minimum max simple w to be processed
|
|
//// Returns approximate winding number
|
|
//double winding_number_approx_simple(
|
|
// const Point & p,
|
|
// const double min_max_w);
|
|
// Print contents of Tree
|
|
//
|
|
// Optional input:
|
|
// tab tab to show depth
|
|
inline void print(const char * tab="");
|
|
// Determine max absolute winding number
|
|
//
|
|
// Inputs:
|
|
// p query point
|
|
// Returns max winding number of
|
|
inline virtual double max_abs_winding_number(const Point & p) const;
|
|
// Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
|
|
// simple polyhedron
|
|
inline virtual double max_simple_abs_winding_number(const Point & p) const;
|
|
// Compute or read cached winding number for point p with respect to mesh
|
|
// in bounding box, recursing according to approximation criteria
|
|
//
|
|
// Inputs:
|
|
// p query point
|
|
// that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
|
|
// Returns cached winding number
|
|
inline virtual double cached_winding_number(const WindingNumberTree & that, const Point & p) const;
|
|
};
|
|
}
|
|
|
|
// Implementation
|
|
|
|
#include "WindingNumberTree.h"
|
|
#include "winding_number.h"
|
|
#include "triangle_fan.h"
|
|
#include "exterior_edges.h"
|
|
|
|
#include <igl/PI.h>
|
|
#include <igl/remove_duplicate_vertices.h>
|
|
|
|
#include <iostream>
|
|
#include <limits>
|
|
|
|
//template <typename Point>
|
|
//WindingNumberMethod WindingNumberTree<Point>::method = EXACT_WINDING_NUMBER_METHOD;
|
|
//template <typename Point>
|
|
//double WindingNumberTree<Point>::min_max_w = 0;
|
|
template <typename Point>
|
|
std::map< std::pair<const igl::WindingNumberTree<Point>*,const igl::WindingNumberTree<Point>*>, double>
|
|
igl::WindingNumberTree<Point>::cached;
|
|
|
|
template <typename Point>
|
|
inline igl::WindingNumberTree<Point>::WindingNumberTree():
|
|
method(EXACT_WINDING_NUMBER_METHOD),
|
|
parent(NULL),
|
|
V(dummyV),
|
|
SV(),
|
|
F(),
|
|
//boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
|
|
cap(),
|
|
radius(std::numeric_limits<double>::infinity()),
|
|
center(0,0,0)
|
|
{
|
|
}
|
|
|
|
template <typename Point>
|
|
inline igl::WindingNumberTree<Point>::WindingNumberTree(
|
|
const Eigen::MatrixXd & _V,
|
|
const Eigen::MatrixXi & _F):
|
|
method(EXACT_WINDING_NUMBER_METHOD),
|
|
parent(NULL),
|
|
V(dummyV),
|
|
SV(),
|
|
F(),
|
|
//boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
|
|
cap(),
|
|
radius(std::numeric_limits<double>::infinity()),
|
|
center(0,0,0)
|
|
{
|
|
set_mesh(_V,_F);
|
|
}
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberTree<Point>::set_mesh(
|
|
const Eigen::MatrixXd & _V,
|
|
const Eigen::MatrixXi & _F)
|
|
{
|
|
using namespace std;
|
|
// Remove any exactly duplicate vertices
|
|
// Q: Can this ever increase the complexity of the boundary?
|
|
// Q: Would we gain even more by remove almost exactly duplicate vertices?
|
|
Eigen::MatrixXi SF,SVI,SVJ;
|
|
igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F);
|
|
triangle_fan(igl::exterior_edges(F),cap);
|
|
V = SV;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline igl::WindingNumberTree<Point>::WindingNumberTree(
|
|
const igl::WindingNumberTree<Point> & parent,
|
|
const Eigen::MatrixXi & _F):
|
|
method(parent.method),
|
|
parent(&parent),
|
|
V(parent.V),
|
|
SV(),
|
|
F(_F),
|
|
cap(triangle_fan(igl::exterior_edges(_F)))
|
|
{
|
|
}
|
|
|
|
template <typename Point>
|
|
inline igl::WindingNumberTree<Point>::~WindingNumberTree()
|
|
{
|
|
using namespace std;
|
|
// Delete children
|
|
typename list<WindingNumberTree<Point>* >::iterator cit = children.begin();
|
|
while(cit != children.end())
|
|
{
|
|
// clear the memory of this item
|
|
delete (* cit);
|
|
// erase from list, returns next element in iterator
|
|
cit = children.erase(cit);
|
|
}
|
|
}
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberTree<Point>::set_method(const WindingNumberMethod & m)
|
|
{
|
|
this->method = m;
|
|
for(auto child : children)
|
|
{
|
|
child->set_method(m);
|
|
}
|
|
}
|
|
|
|
template <typename Point>
|
|
inline const Eigen::MatrixXd & igl::WindingNumberTree<Point>::getV() const
|
|
{
|
|
return V;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline const Eigen::MatrixXi & igl::WindingNumberTree<Point>::getF() const
|
|
{
|
|
return F;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline const Eigen::MatrixXi & igl::WindingNumberTree<Point>::getcap() const
|
|
{
|
|
return cap;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberTree<Point>::grow()
|
|
{
|
|
// Don't grow
|
|
return;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline bool igl::WindingNumberTree<Point>::inside(const Point & /*p*/) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberTree<Point>::winding_number(const Point & p) const
|
|
{
|
|
using namespace std;
|
|
//cout<<"+"<<boundary.rows();
|
|
// If inside then we need to be careful
|
|
if(inside(p))
|
|
{
|
|
// If not a leaf then recurse
|
|
if(children.size()>0)
|
|
{
|
|
// Recurse on each child and accumulate
|
|
double sum = 0;
|
|
for(
|
|
typename list<WindingNumberTree<Point>* >::const_iterator cit = children.begin();
|
|
cit != children.end();
|
|
cit++)
|
|
{
|
|
switch(method)
|
|
{
|
|
case EXACT_WINDING_NUMBER_METHOD:
|
|
sum += (*cit)->winding_number(p);
|
|
break;
|
|
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
|
|
case APPROX_CACHE_WINDING_NUMBER_METHOD:
|
|
//if((*cit)->max_simple_abs_winding_number(p) > min_max_w)
|
|
//{
|
|
sum += (*cit)->winding_number(p);
|
|
//}
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
return sum;
|
|
}else
|
|
{
|
|
return winding_number_all(p);
|
|
}
|
|
}else{
|
|
// Otherwise we can just consider boundary
|
|
// Q: If we using the "multipole" method should we also subdivide the
|
|
// boundary case?
|
|
if((cap.rows() - 2) < F.rows())
|
|
{
|
|
switch(method)
|
|
{
|
|
case EXACT_WINDING_NUMBER_METHOD:
|
|
return winding_number_boundary(p);
|
|
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
|
|
{
|
|
double dist = (p-center).norm();
|
|
// Radius is already an overestimate of inside
|
|
if(dist>1.0*radius)
|
|
{
|
|
return 0;
|
|
}else
|
|
{
|
|
return winding_number_boundary(p);
|
|
}
|
|
}
|
|
case APPROX_CACHE_WINDING_NUMBER_METHOD:
|
|
{
|
|
return parent->cached_winding_number(*this,p);
|
|
}
|
|
default: assert(false);break;
|
|
}
|
|
}else
|
|
{
|
|
// doesn't pay off to use boundary
|
|
return winding_number_all(p);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberTree<Point>::winding_number_all(const Point & p) const
|
|
{
|
|
double w = 0;
|
|
igl::winding_number_3(
|
|
V.data(),
|
|
V.rows(),
|
|
F.data(),
|
|
F.rows(),
|
|
p.data(),
|
|
1,
|
|
&w);
|
|
return w;
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberTree<Point>::winding_number_boundary(const Point & p) const
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
|
|
double w = 0;
|
|
// `cap` is already flipped inside out, so we don't need to flip sign of w
|
|
igl::winding_number_3(
|
|
V.data(),
|
|
V.rows(),
|
|
cap.data(),
|
|
cap.rows(),
|
|
&p[0],
|
|
1,
|
|
&w);
|
|
return w;
|
|
}
|
|
|
|
//template <typename Point>
|
|
//inline double igl::WindingNumberTree<Point>::winding_number_approx_simple(
|
|
// const Point & p,
|
|
// const double min_max_w)
|
|
//{
|
|
// using namespace std;
|
|
// if(max_simple_abs_winding_number(p) > min_max_w)
|
|
// {
|
|
// return winding_number(p);
|
|
// }else
|
|
// {
|
|
// cout<<"Skipped! "<<max_simple_abs_winding_number(p)<<"<"<<min_max_w<<endl;
|
|
// return 0;
|
|
// }
|
|
//}
|
|
|
|
template <typename Point>
|
|
inline void igl::WindingNumberTree<Point>::print(const char * tab)
|
|
{
|
|
using namespace std;
|
|
// Print all facets
|
|
cout<<tab<<"["<<endl<<F<<endl<<"]";
|
|
// Print children
|
|
for(
|
|
typename list<WindingNumberTree<Point>* >::iterator cit = children.begin();
|
|
cit != children.end();
|
|
cit++)
|
|
{
|
|
cout<<","<<endl;
|
|
(*cit)->print((string(tab)+"").c_str());
|
|
}
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberTree<Point>::max_abs_winding_number(const Point & p) const
|
|
{
|
|
return std::numeric_limits<double>::infinity();
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberTree<Point>::max_simple_abs_winding_number(const Point & p) const
|
|
{
|
|
using namespace std;
|
|
return numeric_limits<double>::infinity();
|
|
}
|
|
|
|
template <typename Point>
|
|
inline double igl::WindingNumberTree<Point>::cached_winding_number(
|
|
const igl::WindingNumberTree<Point> & that,
|
|
const Point & p) const
|
|
{
|
|
using namespace std;
|
|
// Simple metric for "far".
|
|
// this that
|
|
// --------
|
|
// ----- / | \ .
|
|
// / r \ / R \ .
|
|
// | p ! | | ! |
|
|
// \_____/ \ /
|
|
// \________/
|
|
//
|
|
//
|
|
// a = angle formed by trapazoid formed by raising sides with lengths r and R
|
|
// at respective centers.
|
|
//
|
|
// a = atan2(R-r,d), where d is the distance between centers
|
|
|
|
// That should be bigger (what about parent? what about sister?)
|
|
bool far = this->radius<that.radius;
|
|
if(far)
|
|
{
|
|
double a = atan2(
|
|
that.radius - this->radius,
|
|
(that.center - this->center).norm());
|
|
assert(a>0);
|
|
far = (a<PI/8.0);
|
|
}
|
|
|
|
if(far)
|
|
{
|
|
// Not implemented yet
|
|
pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
|
|
// Need to compute it for first time?
|
|
if(cached.count(this_that)==0)
|
|
{
|
|
cached[this_that] =
|
|
that.winding_number_boundary(this->center);
|
|
}
|
|
return cached[this_that];
|
|
}else if(children.size() == 0)
|
|
{
|
|
// not far and hierarchy ended too soon: can't use cache
|
|
return that.winding_number_boundary(p);
|
|
}else
|
|
{
|
|
for(
|
|
typename list<WindingNumberTree<Point>* >::const_iterator cit = children.begin();
|
|
cit != children.end();
|
|
cit++)
|
|
{
|
|
if((*cit)->inside(p))
|
|
{
|
|
return (*cit)->cached_winding_number(that,p);
|
|
}
|
|
}
|
|
// Not inside any children? This can totally happen because bounding boxes
|
|
// are set to bound contained facets. So sibilings may overlap and their
|
|
// union may not contain their parent (though, their union is certainly a
|
|
// subset of their parent).
|
|
assert(false);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Explicit instanciation
|
|
//template class igl::WindingNumberTree<Eigen::Vector3d >;
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_write_triangle_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITE_TRIANGLE_MESH_H
|
|
#define IGL_WRITE_TRIANGLE_MESH_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// write mesh to a file with automatic detection of file format. supported:
|
|
// obj, off, stl, wrl, ply, mesh).
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Index type for indices (will be read as int and cast to Index)
|
|
// Inputs:
|
|
// str path to file
|
|
// V eigen double matrix #V by 3
|
|
// F eigen int matrix #F by 3
|
|
// Returns true iff success
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool write_triangle_mesh(
|
|
const std::string str,
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const bool ascii = true);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "write_triangle_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writeDMAT = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITEDMAT_H
|
|
#define IGL_WRITEDMAT_H
|
|
#include "igl_inline.h"
|
|
// See writeDMAT.h for a description of the .dmat file type
|
|
#include <string>
|
|
#include <vector>
|
|
namespace igl
|
|
{
|
|
// Write a matrix using ascii dmat file type
|
|
//
|
|
// Template:
|
|
// Mat matrix type that supports .rows(), .cols(), operator(i,j)
|
|
// Inputs:
|
|
// file_name path to .dmat file
|
|
// W eigen matrix containing to-be-written coefficients
|
|
// ascii write ascii file {true}
|
|
// Returns true on success, false on error
|
|
//
|
|
template <class Mat>
|
|
IGL_INLINE bool writeDMAT(
|
|
const std::string file_name,
|
|
const Mat & W,
|
|
const bool ascii=true);
|
|
template <typename Scalar>
|
|
IGL_INLINE bool writeDMAT(
|
|
const std::string file_name,
|
|
const std::vector<std::vector<Scalar> > W);
|
|
template <typename Scalar>
|
|
IGL_INLINE bool writeDMAT(
|
|
const std::string file_name,
|
|
const std::vector<Scalar > W);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "writeDMAT.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writeMESH = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITEMESH_H
|
|
#define IGL_WRITEMESH_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
// save a tetrahedral volume mesh to a .mesh file
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be cast as double)
|
|
// Index type for indices (will be cast to int)
|
|
// Input:
|
|
// mesh_file_name path of .mesh file
|
|
// V double matrix of vertex positions #V by 3
|
|
// T #T list of tet indices into vertex positions
|
|
// F #F list of face indices into vertex positions
|
|
//
|
|
// Known bugs: Holes and regions are not supported
|
|
template <typename Scalar, typename Index>
|
|
IGL_INLINE bool writeMESH(
|
|
const std::string mesh_file_name,
|
|
const std::vector<std::vector<Scalar > > & V,
|
|
const std::vector<std::vector<Index > > & T,
|
|
const std::vector<std::vector<Index > > & F);
|
|
|
|
// Templates:
|
|
// DerivedV real-value: i.e. from MatrixXd
|
|
// DerivedT integer-value: i.e. from MatrixXi
|
|
// DerivedF integer-value: i.e. from MatrixXi
|
|
// Input:
|
|
// mesh_file_name path of .mesh file
|
|
// V eigen double matrix #V by 3
|
|
// T eigen int matrix #T by 4
|
|
// F eigen int matrix #F by 3
|
|
template <typename DerivedV, typename DerivedT, typename DerivedF>
|
|
IGL_INLINE bool writeMESH(
|
|
const std::string str,
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedT> & T,
|
|
const Eigen::PlainObjectBase<DerivedF> & F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "writeMESH.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writeOBJ = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITEOBJ_H
|
|
#define IGL_WRITEOBJ_H
|
|
#include "igl_inline.h"
|
|
// History:
|
|
// return type changed from void to bool Alec 20 Sept 2011
|
|
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// Write a mesh in an ascii obj file
|
|
// Inputs:
|
|
// str path to outputfile
|
|
// V #V by 3 mesh vertex positions
|
|
// F #F by 3|4 mesh indices into V
|
|
// CN #CN by 3 normal vectors
|
|
// FN #F by 3|4 corner normal indices into CN
|
|
// TC #TC by 2|3 texture coordinates
|
|
// FTC #F by 3|4 corner texture coord indices into TC
|
|
// Returns true on success, false on error
|
|
template <typename DerivedV, typename DerivedF, typename DerivedT>
|
|
IGL_INLINE bool writeOBJ(
|
|
const std::string str,
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedV>& CN,
|
|
const Eigen::PlainObjectBase<DerivedF>& FN,
|
|
const Eigen::PlainObjectBase<DerivedT>& TC,
|
|
const Eigen::PlainObjectBase<DerivedF>& FTC);
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool writeOBJ(
|
|
const std::string str,
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F);
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "writeOBJ.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writeOFF = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITEOFF_H
|
|
#define IGL_WRITEOFF_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool writeOFF(
|
|
const std::string str,
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "writeOFF.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writePLY = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITEPLY_H
|
|
#define IGL_WRITEPLY_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
// Write a mesh to a .ply file.
|
|
//
|
|
// Inputs:
|
|
// filename path to .ply file
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// N #V by 3 list of vertex normals
|
|
// UV #V by 2 list of vertex texture coordinates
|
|
// Returns true iff success
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedUV>
|
|
IGL_INLINE bool writePLY(
|
|
const std::string & filename,
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedN> & N,
|
|
const Eigen::PlainObjectBase<DerivedUV> & UV,
|
|
const bool ascii = true);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF>
|
|
IGL_INLINE bool writePLY(
|
|
const std::string & filename,
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const bool ascii = true);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "writePLY.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writeSTL = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITESTL_H
|
|
#define IGL_WRITESTL_H
|
|
#include "igl_inline.h"
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
# include <Eigen/Core>
|
|
#endif
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
// Write a mesh to an stl file.
|
|
//
|
|
// Templates:
|
|
// Scalar type for positions and vectors (will be read as double and cast
|
|
// to Scalar)
|
|
// Inputs:
|
|
// filename path to .obj file
|
|
// V double matrix of vertex positions #F*3 by 3
|
|
// F index matrix of triangle indices #F by 3
|
|
// N double matrix of vertex positions #F by 3
|
|
// asci write ascii file {true}
|
|
// Returns true on success, false on errors
|
|
//
|
|
template <typename DerivedV, typename DerivedF, typename DerivedN>
|
|
IGL_INLINE bool writeSTL(
|
|
const std::string & filename,
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedN> & N,
|
|
const bool ascii=true);
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool writeSTL(
|
|
const std::string & filename,
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const bool ascii=true);
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "writeSTL.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writeTGF = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITETGF_H
|
|
#define IGL_WRITETGF_H
|
|
#include "igl_inline.h"
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#ifndef IGL_NO_EIGEN
|
|
#include <Eigen/Dense>
|
|
#endif
|
|
|
|
namespace igl
|
|
{
|
|
// WRITETGF
|
|
//
|
|
// Write a graph to a .tgf file
|
|
//
|
|
// Input:
|
|
// filename .tgf file name
|
|
// V # vertices by 3 list of vertex positions
|
|
// E # edges by 2 list of edge indices
|
|
//
|
|
// Assumes that graph vertices are 3 dimensional
|
|
IGL_INLINE bool writeTGF(
|
|
const std::string tgf_filename,
|
|
const std::vector<std::vector<double> > & C,
|
|
const std::vector<std::vector<int> > & E);
|
|
|
|
#ifndef IGL_NO_EIGEN
|
|
IGL_INLINE bool writeTGF(
|
|
const std::string tgf_filename,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & E);
|
|
#endif
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "writeTGF.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_writeWRL = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_WRITE_WRL_H
|
|
#define IGL_WRITE_WRL_H
|
|
#include "igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
// Write mesh to a .wrl file
|
|
//
|
|
// Inputs:
|
|
// str path to .wrl file
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// Returns true iff succes
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool writeWRL(
|
|
const std::string & str,
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F);
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "writeWRL.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_ZERO = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ZERO_H
|
|
#define IGL_ZERO_H
|
|
// Often one needs a reference to a dummy variable containing zero as its
|
|
// value, for example when using AntTweakBar's
|
|
// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ZERO);
|
|
namespace igl
|
|
{
|
|
const char CHAR_ZERO = 0;
|
|
const int INT_ZERO = 0;
|
|
const unsigned int UNSIGNED_INT_ZERO = 0;
|
|
const double DOUBLE_ZERO = 0;
|
|
const float FLOAT_ZERO = 0;
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_anttweakbar_cocoa_key_to_anttweakbar_key = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
|
|
#define IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
|
|
#include "../igl_inline.h"
|
|
|
|
|
|
namespace igl
|
|
{
|
|
namespace anttweakbar
|
|
{
|
|
// Convert an unsigned char (like that from Cocoa apps) to AntTweakBar key
|
|
// code.
|
|
// See also: TranslateKey() in TwMgr.cpp in AntTweakBar source
|
|
// Inputs:
|
|
// key unsigned char key from keyboard
|
|
// Returns int of new key code
|
|
IGL_INLINE int cocoa_key_to_anttweakbar_key(int key);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "cocoa_key_to_anttweakbar_key.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_anttweakbar_ReAntTweakBar = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
|
|
#define IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
|
|
#include "../igl_inline.h"
|
|
// ReAntTweakBar is a minimal wrapper for the AntTweakBar library that allows
|
|
// "bars" to be saved and load from disk. Changing your existing app that uses
|
|
// AntTweakBar to use ReAntTweakBar is trivial.
|
|
//
|
|
// Many (but not all) variable types are supported. I'll try to keep track them
|
|
// here:
|
|
// TW_TYPE_BOOLCPP
|
|
// TW_TYPE_QUAT4F
|
|
// TW_TYPE_QUAT4D
|
|
// TW_TYPE_COLOR4F
|
|
// TW_TYPE_COLOR4D
|
|
// TW_TYPE_COLOR3F
|
|
// TW_TYPE_DIR3F
|
|
// TW_TYPE_DIR3D
|
|
// TW_TYPE_BOOL32
|
|
// TW_TYPE_INT32
|
|
// TW_TYPE_UINT32
|
|
// TW_TYPE_FLOAT
|
|
// TW_TYPE_DOUBLE
|
|
// TW_TYPE_UINT8
|
|
// and
|
|
// custom TwTypes made with TwDefineEnum
|
|
//
|
|
// I'm working on adding the rest on an as-needed basis. Adding a new type only
|
|
// requires changes in a few places...
|
|
//
|
|
//
|
|
//
|
|
|
|
// This allows the user to have a non-global, static installation of
|
|
// AntTweakBar
|
|
#include <AntTweakBar.h>
|
|
// Instead of including AntTweakBar.h, just define the necessary types
|
|
// Types used:
|
|
// - TwType
|
|
// - TwEnumVal
|
|
// - TwSetVarCallback
|
|
// - TwGetVarCallback
|
|
// - TwBar
|
|
// - TwButtonCallback
|
|
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#define REANTTWEAKBAR_MAX_CB_VAR_SIZE 1000
|
|
// Max line size for reading files
|
|
#define REANTTWEAKBAR_MAX_LINE 1000
|
|
#define REANTTWEAKBAR_MAX_WORD 100
|
|
|
|
namespace igl
|
|
{
|
|
namespace anttweakbar
|
|
{
|
|
TwType ReTwDefineEnum(
|
|
const char *name,
|
|
const TwEnumVal *enumValues,
|
|
unsigned int nbValues);
|
|
TwType ReTwDefineEnumFromString(const char * name,const char * enumString);
|
|
|
|
struct ReTwRWItem
|
|
{
|
|
//const char * name;
|
|
std::string name;
|
|
TwType type;
|
|
void * var;
|
|
// Default constructor
|
|
IGL_INLINE ReTwRWItem(
|
|
const std::string _name,
|
|
TwType _type,
|
|
void *_var):
|
|
name(_name),
|
|
type(_type),
|
|
var(_var)
|
|
{
|
|
}
|
|
// Shallow copy constructor
|
|
// I solemnly swear it's OK to copy var this way
|
|
// Q: Is it really?
|
|
IGL_INLINE ReTwRWItem(const ReTwRWItem & that):
|
|
name(that.name),
|
|
type(that.type),
|
|
var(that.var)
|
|
{
|
|
}
|
|
// Shallow assignment
|
|
// I solemnly swear it's OK to copy var this way
|
|
IGL_INLINE ReTwRWItem & operator=(const ReTwRWItem & that)
|
|
{
|
|
if(this != &that)
|
|
{
|
|
this->name = that.name;
|
|
this->type = that.type;
|
|
this->var = that.var;
|
|
}
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
struct ReTwCBItem
|
|
{
|
|
//const char * name;
|
|
std::string name;
|
|
TwType type;
|
|
TwSetVarCallback setCallback;
|
|
TwGetVarCallback getCallback;
|
|
void * clientData;
|
|
// Default constructor
|
|
IGL_INLINE ReTwCBItem(
|
|
const std::string _name,
|
|
TwType _type,
|
|
TwSetVarCallback _setCallback,
|
|
TwGetVarCallback _getCallback,
|
|
void * _clientData):
|
|
name(_name),
|
|
type(_type),
|
|
setCallback(_setCallback),
|
|
getCallback(_getCallback),
|
|
clientData(_clientData)
|
|
{
|
|
}
|
|
// Shallow copy
|
|
// I solemnly swear it's OK to copy clientData this way
|
|
IGL_INLINE ReTwCBItem(const ReTwCBItem & that):
|
|
name(that.name),
|
|
type(that.type),
|
|
setCallback(that.setCallback),
|
|
getCallback(that.getCallback),
|
|
clientData(that.clientData)
|
|
{
|
|
}
|
|
// Shallow assignment
|
|
// I solemnly swear it's OK to copy clientData this way
|
|
IGL_INLINE ReTwCBItem & operator=(const ReTwCBItem & that)
|
|
{
|
|
if(this != &that)
|
|
{
|
|
name = that.name;
|
|
type = that.type;
|
|
setCallback = that.setCallback;
|
|
getCallback = that.getCallback;
|
|
clientData = that.clientData;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
};
|
|
|
|
class ReTwBar
|
|
{
|
|
// VARIABLES
|
|
// Should be private, but seeing as I'm not going to implement all of the
|
|
// AntTweakBar public functions right away, I'll expose this so that at
|
|
// anytime AntTweakBar functions can be called directly on the bar
|
|
public:
|
|
TwBar * bar;
|
|
std::string name;
|
|
protected:
|
|
std::vector<ReTwRWItem> rw_items;
|
|
std::vector<ReTwCBItem> cb_items;
|
|
public:
|
|
// Default constructor with explicit initialization
|
|
IGL_INLINE ReTwBar();
|
|
private:
|
|
// Copy constructor does shallow copy
|
|
IGL_INLINE ReTwBar(const ReTwBar & that);
|
|
// Assignment operator does shallow assignment
|
|
IGL_INLINE ReTwBar &operator=(const ReTwBar & that);
|
|
|
|
// WRAPPERS FOR ANTTWEAKBAR FUNCTIONS
|
|
public:
|
|
IGL_INLINE void TwNewBar(const char *_name);
|
|
IGL_INLINE int TwAddVarRW(
|
|
const char *name,
|
|
TwType type,
|
|
void *var,
|
|
const char *def,
|
|
const bool record=true);
|
|
IGL_INLINE int TwAddVarCB(
|
|
const char *name,
|
|
TwType type,
|
|
TwSetVarCallback setCallback,
|
|
TwGetVarCallback getCallback,
|
|
void *clientData,
|
|
const char *def,
|
|
const bool record=true);
|
|
// Wrappers for convenience (not recorded, just passed on)
|
|
IGL_INLINE int TwAddVarRO(const char *name, TwType type, void *var, const char *def);
|
|
IGL_INLINE int TwAddButton(
|
|
const char *name,
|
|
TwButtonCallback buttonCallback,
|
|
void *clientData,
|
|
const char *def);
|
|
IGL_INLINE int TwSetParam(
|
|
const char *varName,
|
|
const char *paramName,
|
|
TwParamValueType paramValueType,
|
|
unsigned int inValueCount,
|
|
const void *inValues);
|
|
IGL_INLINE int TwGetParam(
|
|
const char *varName,
|
|
const char *paramName,
|
|
TwParamValueType paramValueType,
|
|
unsigned int outValueMaxCount,
|
|
void *outValues);
|
|
IGL_INLINE int TwRefreshBar();
|
|
IGL_INLINE int TwTerminate();
|
|
|
|
|
|
// IO FUNCTIONS
|
|
public:
|
|
// Save current items to file
|
|
// Input:
|
|
// file_name name of file to save data to, can be null which means print
|
|
// to stdout
|
|
// Return:
|
|
// true only if there were no (fatal) errors
|
|
IGL_INLINE bool save(const char *file_name);
|
|
std::string get_value_as_string(
|
|
void * var,
|
|
TwType type);
|
|
// Load into current items from file
|
|
// Input:
|
|
// file_name name of input file to load
|
|
// Return:
|
|
// true only if there were no (fatal) errors
|
|
IGL_INLINE bool load(const char *file_name);
|
|
// Get TwType from string
|
|
// Input
|
|
// type_str string of type
|
|
// Output
|
|
// type TwType converted from string
|
|
// Returns
|
|
// true only if string matched a valid type
|
|
IGL_INLINE bool type_from_string(const char *type_str, TwType & type);
|
|
// I realize that I mix std::string and const char * all over the place.
|
|
// What can you do...
|
|
IGL_INLINE bool set_value_from_string(
|
|
const char * name,
|
|
TwType type,
|
|
const char * value_str);
|
|
IGL_INLINE const std::vector<ReTwRWItem> & get_rw_items();
|
|
IGL_INLINE const std::vector<ReTwCBItem> & get_cb_items();
|
|
};
|
|
}
|
|
}
|
|
|
|
// List of TwBar functions
|
|
//TW_API TwBar * TW_CALL TwNewBar(const char *barName);
|
|
//TW_API int TW_CALL TwDeleteBar(TwBar *bar);
|
|
//TW_API int TW_CALL TwDeleteAllBars();
|
|
//TW_API int TW_CALL TwSetTopBar(const TwBar *bar);
|
|
//TW_API TwBar * TW_CALL TwGetTopBar();
|
|
//TW_API int TW_CALL TwSetBottomBar(const TwBar *bar);
|
|
//TW_API TwBar * TW_CALL TwGetBottomBar();
|
|
//TW_API const char * TW_CALL TwGetBarName(TwBar *bar);
|
|
//TW_API int TW_CALL TwGetBarCount();
|
|
//TW_API TwBar * TW_CALL TwGetBarByIndex(int barIndex);
|
|
//TW_API TwBar * TW_CALL TwGetBarByName(const char *barName);
|
|
//TW_API int TW_CALL TwRefreshBar(TwBar *bar);
|
|
//TW_API int TW_CALL TwTerminate();
|
|
//
|
|
//TW_API int TW_CALL TwAddVarRW(TwBar *bar, const char *name, TwType type, void *var, const char *def);
|
|
//TW_API int TW_CALL TwAddVarRO(TwBar *bar, const char *name, TwType type, const void *var, const char *def);
|
|
//TW_API int TW_CALL TwAddVarCB(TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def);
|
|
//TW_API int TW_CALL TwAddButton(TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def);
|
|
//TW_API int TW_CALL TwAddSeparator(TwBar *bar, const char *name, const char *def);
|
|
//TW_API int TW_CALL TwRemoveVar(TwBar *bar, const char *name);
|
|
//TW_API int TW_CALL TwRemoveAllVars(TwBar *bar);
|
|
|
|
// Until AntTweakBar dependency folder exists, this is header-only
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "ReAntTweakBar.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_bbw_bbw = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BBW_BBW_H
|
|
#define IGL_BBW_BBW_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#ifndef IGL_NO_MOSEK
|
|
# include <igl/mosek/mosek_quadprog.h>
|
|
#endif
|
|
#include <igl/active_set.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace bbw
|
|
{
|
|
enum QPSolver
|
|
{
|
|
QP_SOLVER_IGL_ACTIVE_SET = 0,
|
|
QP_SOLVER_MOSEK = 1,
|
|
NUM_QP_SOLVERS = 2
|
|
};
|
|
const char * const QPSolverNames[NUM_QP_SOLVERS] =
|
|
{
|
|
"QP_SOLVER_IGL_ACTIVE_SET",
|
|
"QP_SOLVER_MOSEK"
|
|
};
|
|
// Container for BBW computation related data and flags
|
|
class BBWData
|
|
{
|
|
public:
|
|
// Enforce partition of unity during optimization (optimize all weight
|
|
// simultaneously)
|
|
bool partition_unity;
|
|
// Initial guess
|
|
Eigen::MatrixXd W0;
|
|
#ifndef IGL_NO_MOSEK
|
|
igl::mosek::MosekData mosek_data;
|
|
#endif
|
|
igl::active_set_params active_set_params;
|
|
// Which solver
|
|
QPSolver qp_solver;
|
|
// Verbosity level
|
|
// 0: quiet
|
|
// 1: loud
|
|
// 2: louder
|
|
int verbosity;
|
|
public:
|
|
BBWData();
|
|
// Print current state of object
|
|
void print();
|
|
};
|
|
|
|
// Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given
|
|
// set of boundary conditions
|
|
//
|
|
// Templates
|
|
// DerivedV derived type of eigen matrix for V (e.g. MatrixXd)
|
|
// DerivedF derived type of eigen matrix for F (e.g. MatrixXi)
|
|
// Derivedb derived type of eigen matrix for b (e.g. VectorXi)
|
|
// Derivedbc derived type of eigen matrix for bc (e.g. MatrixXd)
|
|
// DerivedW derived type of eigen matrix for W (e.g. MatrixXd)
|
|
// Inputs:
|
|
// V #V by dim vertex positions
|
|
// Ele #Elements by simplex-size list of element indices
|
|
// b #b boundary indices into V
|
|
// bc #b by #W list of boundary values
|
|
// data object containing options, intial guess --> solution and results
|
|
// Outputs:
|
|
// W #V by #W list of *unnormalized* weights to normalize use
|
|
// igl::normalize_row_sums(W,W);
|
|
// Returns true on success, false on failure
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedEle,
|
|
typename Derivedb,
|
|
typename Derivedbc,
|
|
typename DerivedW>
|
|
IGL_INLINE bool bbw(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedEle> & Ele,
|
|
const Eigen::PlainObjectBase<Derivedb> & b,
|
|
const Eigen::PlainObjectBase<Derivedbc> & bc,
|
|
BBWData & data,
|
|
Eigen::PlainObjectBase<DerivedW> & W);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "bbw.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boolean_from_cork_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOOLEAN_FROM_CORK_MESH_H
|
|
#define IGL_BOOLEAN_FROM_CORK_MESH_H
|
|
#ifndef IGL_NO_CORK
|
|
#include <igl/igl_inline.h>
|
|
#include <cork.h>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace boolean
|
|
{
|
|
// Convert cork's triangle mesh representation to a (V,F) mesh.
|
|
//
|
|
// Inputs:
|
|
// mesh cork representation of mesh
|
|
// Outputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF>
|
|
IGL_INLINE void from_cork_mesh(
|
|
const CorkTriMesh & mesh,
|
|
Eigen::PlainObjectBase<DerivedV > & V,
|
|
Eigen::PlainObjectBase<DerivedF > & F);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "from_cork_mesh.cpp"
|
|
#endif
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boolean_mesh_boolean = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOOLEAN_MESH_BOOLEAN_H
|
|
#define IGL_BOOLEAN_MESH_BOOLEAN_H
|
|
|
|
#include <igl/igl_inline.h>
|
|
#include "MeshBooleanType.h"
|
|
#include <Eigen/Core>
|
|
#include <functional>
|
|
|
|
namespace igl
|
|
{
|
|
namespace boolean
|
|
{
|
|
// MESH_BOOLEAN Compute boolean csg operations on "solid", consistently
|
|
// oriented meshes.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions of first mesh
|
|
// F #F by 3 list of triangle indices into V
|
|
// U #U by 3 list of vertex positions of second mesh
|
|
// G #G by 3 list of triangle indices into U
|
|
// type type of boolean operation
|
|
// Outputs:
|
|
// W #W by 3 list of vertex positions of boolean result mesh
|
|
// H #H by 3 list of triangle indices into W
|
|
// J #H list of indices into [FA;FB] revealing "birth" facet
|
|
//
|
|
// See also: self_intersect
|
|
//
|
|
template <
|
|
typename DerivedVA,
|
|
typename DerivedFA,
|
|
typename DerivedVB,
|
|
typename DerivedFB,
|
|
typename DerivedVC,
|
|
typename DerivedFC,
|
|
typename DerivedJ>
|
|
IGL_INLINE void mesh_boolean(
|
|
const Eigen::PlainObjectBase<DerivedVA > & VA,
|
|
const Eigen::PlainObjectBase<DerivedFA > & FA,
|
|
const Eigen::PlainObjectBase<DerivedVB > & VB,
|
|
const Eigen::PlainObjectBase<DerivedFB > & FB,
|
|
const MeshBooleanType & type,
|
|
Eigen::PlainObjectBase<DerivedVC > & VC,
|
|
Eigen::PlainObjectBase<DerivedFC > & FC,
|
|
Eigen::PlainObjectBase<DerivedJ > & J);
|
|
template <
|
|
typename DerivedVA,
|
|
typename DerivedFA,
|
|
typename DerivedVB,
|
|
typename DerivedFB,
|
|
typename DerivedVC,
|
|
typename DerivedFC>
|
|
IGL_INLINE void mesh_boolean(
|
|
const Eigen::PlainObjectBase<DerivedVA > & VA,
|
|
const Eigen::PlainObjectBase<DerivedFA > & FA,
|
|
const Eigen::PlainObjectBase<DerivedVB > & VB,
|
|
const Eigen::PlainObjectBase<DerivedFB > & FB,
|
|
const MeshBooleanType & type,
|
|
Eigen::PlainObjectBase<DerivedVC > & VC,
|
|
Eigen::PlainObjectBase<DerivedFC > & FC);
|
|
// Inputs:
|
|
// resolve_fun function handle for computing resolve of a
|
|
// self-intersections of a mesh and outputting the new mesh.
|
|
template <
|
|
typename DerivedVA,
|
|
typename DerivedFA,
|
|
typename DerivedVB,
|
|
typename DerivedFB,
|
|
typename DerivedVC,
|
|
typename DerivedFC,
|
|
typename DerivedJ>
|
|
IGL_INLINE void mesh_boolean(
|
|
const Eigen::PlainObjectBase<DerivedVA > & VA,
|
|
const Eigen::PlainObjectBase<DerivedFA > & FA,
|
|
const Eigen::PlainObjectBase<DerivedVB > & VB,
|
|
const Eigen::PlainObjectBase<DerivedFB > & FB,
|
|
const MeshBooleanType & type,
|
|
const std::function<void(
|
|
const Eigen::Matrix<
|
|
typename DerivedVC::Scalar,Eigen::Dynamic,3> &,
|
|
const Eigen::Matrix<
|
|
typename DerivedFC::Scalar,Eigen::Dynamic,3> &,
|
|
Eigen::Matrix<
|
|
typename DerivedVC::Scalar,Eigen::Dynamic,3> &,
|
|
Eigen::Matrix<
|
|
typename DerivedFC::Scalar,Eigen::Dynamic,3> &,
|
|
Eigen::Matrix<
|
|
typename DerivedJ::Scalar,Eigen::Dynamic,1>&)>
|
|
& resolve_fun,
|
|
Eigen::PlainObjectBase<DerivedVC > & VC,
|
|
Eigen::PlainObjectBase<DerivedFC > & FC,
|
|
Eigen::PlainObjectBase<DerivedJ > & J);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mesh_boolean.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boolean_mesh_boolean_cork = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOOLEAN_MESH_BOOLEAN_CORK_H
|
|
#define IGL_BOOLEAN_MESH_BOOLEAN_CORK_H
|
|
#ifndef IGL_NO_CORK
|
|
#include "MeshBooleanType.h"
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include <cork.h> // for consistent uint
|
|
|
|
namespace igl
|
|
{
|
|
namespace boolean
|
|
{
|
|
// Compute a boolean operation on two input meshes using the cork library.
|
|
//
|
|
// Inputs:
|
|
// VA #VA by 3 list of vertex positions of first mesh
|
|
// FA #FA by 3 list of triangle indices into VA
|
|
// VB #VB by 3 list of vertex positions of second mesh
|
|
// FB #FB by 3 list of triangle indices into VB
|
|
// type of boolean operation see MeshBooleanType.h
|
|
// Outputs:
|
|
// VC #VC by 3 list of vertex positions of output mesh
|
|
// FC #FC by 3 list of triangle indices into VC
|
|
template <
|
|
typename DerivedVA,
|
|
typename DerivedFA,
|
|
typename DerivedVB,
|
|
typename DerivedFB,
|
|
typename DerivedVC,
|
|
typename DerivedFC>
|
|
IGL_INLINE void mesh_boolean_cork(
|
|
const Eigen::PlainObjectBase<DerivedVA > & VA,
|
|
const Eigen::PlainObjectBase<DerivedFA > & FA,
|
|
const Eigen::PlainObjectBase<DerivedVB > & VB,
|
|
const Eigen::PlainObjectBase<DerivedFB > & FB,
|
|
const MeshBooleanType & type,
|
|
Eigen::PlainObjectBase<DerivedVC > & VC,
|
|
Eigen::PlainObjectBase<DerivedFC > & FC);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mesh_boolean_cork.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boolean_MeshBooleanType = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOOLEAN_MESH_BOOLEAN_TYPE_H
|
|
#define IGL_BOOLEAN_MESH_BOOLEAN_TYPE_H
|
|
namespace igl
|
|
{
|
|
namespace boolean
|
|
{
|
|
enum MeshBooleanType
|
|
{
|
|
MESH_BOOLEAN_TYPE_UNION = 0,
|
|
MESH_BOOLEAN_TYPE_INTERSECT = 1,
|
|
MESH_BOOLEAN_TYPE_MINUS = 2,
|
|
MESH_BOOLEAN_TYPE_XOR = 3,
|
|
MESH_BOOLEAN_TYPE_RESOLVE = 4,
|
|
NUM_MESH_BOOLEAN_TYPES = 5
|
|
};
|
|
}
|
|
};
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_boolean_to_cork_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_BOOLEAN_TO_CORK_MESH_H
|
|
#define IGL_BOOLEAN_TO_CORK_MESH_H
|
|
#ifndef IGL_NO_CORK
|
|
#include <igl/igl_inline.h>
|
|
#include <cork.h>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace boolean
|
|
{
|
|
// Convert a (V,F) mesh to a cork's triangle mesh representation.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// Outputs:
|
|
// mesh cork representation of mesh
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF>
|
|
IGL_INLINE void to_cork_mesh(
|
|
const Eigen::PlainObjectBase<DerivedV > & V,
|
|
const Eigen::PlainObjectBase<DerivedF > & F,
|
|
CorkTriMesh & mesh);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "to_cork_mesh.cpp"
|
|
#endif
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_complex_to_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_COMPLEX_TO_MESH_H
|
|
#define IGL_CGAL_COMPLEX_TO_MESH_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <CGAL/Complex_2_in_triangulation_3.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Templates:
|
|
// Tr CGAL triangulation type, e.g.
|
|
// CGAL::Surface_mesh_default_triangulation_3
|
|
// Inputs
|
|
// c2t3 2-complex (surface) living in a 3d triangulation (e.g. result of
|
|
// CGAL::make_surface_mesh)
|
|
// Outputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// Returns true iff conversion was successful, failure can ok if CGAL code
|
|
// can't figure out ordering.
|
|
//
|
|
template <typename Tr, typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool complex_to_mesh(
|
|
const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,
|
|
Eigen::PlainObjectBase<DerivedV> & V,
|
|
Eigen::PlainObjectBase<DerivedF> & F);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "complex_to_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_intersect_other = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_INTERSECT_OTHER_H
|
|
#define IGL_CGAL_INTERSECT_OTHER_H
|
|
#include <igl/igl_inline.h>
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
#ifdef MEX
|
|
# include <mex.h>
|
|
# include <cassert>
|
|
# undef assert
|
|
# define assert( isOK ) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(C_STR(__FILE__<<":"<<__LINE__<<": failed assertion `"<<#isOK<<"'"<<std::endl) ) )
|
|
#endif
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// INTERSECT Given a triangle mesh (V,F) and another mesh (U,G) find all pairs
|
|
// of intersecting faces. Note that self-intersections are ignored.
|
|
//
|
|
// [VV,FF,IF] = selfintersect(V,F,'ParameterName',ParameterValue, ...)
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// U #U by 3 list of vertex positions
|
|
// G #G by 3 list of triangle indices into U
|
|
// first_only whether to only detect the first intersection.
|
|
// Outputs:
|
|
// IF #intersecting face pairs by 2 list of intersecting face pairs,
|
|
// indexing F and G
|
|
//
|
|
// See also: selfintersect
|
|
IGL_INLINE void intersect_other(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & U,
|
|
const Eigen::MatrixXi & G,
|
|
const bool first_only,
|
|
Eigen::MatrixXi & IF);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "intersect_other.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_mesh_to_cgal_triangle_list = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H
|
|
#define IGL_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include "CGAL_includes.hpp"
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Convert a mesh (V,F) to a list of CGAL triangles
|
|
//
|
|
// Templates:
|
|
// Kernal CGAL computation and construction kernel (e.g.
|
|
// CGAL::Exact_predicates_exact_constructions_kernel)
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// Outputs:
|
|
// T #F list of CGAL triangles
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename Kernel>
|
|
IGL_INLINE void mesh_to_cgal_triangle_list(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
std::vector<CGAL::Triangle_3<Kernel> > & T);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mesh_to_cgal_triangle_list.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_mesh_to_polyhedron = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_MESH_TO_POLYHEDRON_H
|
|
#define IGL_CGAL_MESH_TO_POLYHEDRON_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Convert a mesh (V,F) to a CGAL Polyhedron
|
|
//
|
|
// Templates:
|
|
// Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// Outputs:
|
|
// poly cgal polyhedron
|
|
// Returns true only if (V,F) can be converted to a valid polyhedron (i.e. if
|
|
// (V,F) is vertex and edge manifold).
|
|
template <typename Polyhedron>
|
|
IGL_INLINE bool mesh_to_polyhedron(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
Polyhedron & poly);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mesh_to_polyhedron.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_order_facets_around_edges = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_ORDER_FACETS_AROUND_EDGES_H
|
|
#define IGL_CGAL_ORDER_FACETS_AROUND_EDGES_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// For each undirected edge, sort its adjacent faces.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertices.
|
|
// F #F by 3 list of faces
|
|
// N #F by 3 list of face normals.
|
|
// E #F*3 by 2 list vertex indices, represents directed edges.
|
|
// uE #uE by 2 list of vertex_indices, represents undirected edges.
|
|
// EMAP #F*3 list of indices that maps E to uE. (a many-to-one map)
|
|
// uE2E #uE list of lists that maps uE to E. (a one-to-many map)
|
|
//
|
|
// Outputs:
|
|
// uE2oE #uE list of lists that maps uE to an ordered list of E. (a
|
|
// one-to-many map)
|
|
// uE2C #uE list of lists of bools indicates whether each face in
|
|
// uE2oE[i] is consistently orientated as the ordering.
|
|
//
|
|
template<
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedE,
|
|
typename DeriveduE,
|
|
typename DerivedEMAP,
|
|
typename uE2EType,
|
|
typename uE2oEType,
|
|
typename uE2CType >
|
|
IGL_INLINE
|
|
typename std::enable_if<!std::is_same<typename DerivedV::Scalar,
|
|
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
|
order_facets_around_edges(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedN>& N,
|
|
const Eigen::PlainObjectBase<DerivedE>& E,
|
|
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
|
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
|
const std::vector<std::vector<uE2EType> >& uE2E,
|
|
std::vector<std::vector<uE2oEType> >& uE2oE,
|
|
std::vector<std::vector<uE2CType > >& uE2C );
|
|
|
|
template<
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedE,
|
|
typename DeriveduE,
|
|
typename DerivedEMAP,
|
|
typename uE2EType,
|
|
typename uE2oEType,
|
|
typename uE2CType >
|
|
IGL_INLINE
|
|
typename std::enable_if<std::is_same<typename DerivedV::Scalar,
|
|
typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
|
|
order_facets_around_edges(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const Eigen::PlainObjectBase<DerivedN>& N,
|
|
const Eigen::PlainObjectBase<DerivedE>& E,
|
|
const Eigen::PlainObjectBase<DeriveduE>& uE,
|
|
const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
|
|
const std::vector<std::vector<uE2EType> >& uE2E,
|
|
std::vector<std::vector<uE2oEType> >& uE2oE,
|
|
std::vector<std::vector<uE2CType > >& uE2C );
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "order_facets_around_edges.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_outer_hull = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_OUTER_HULL_H
|
|
#define IGL_CGAL_OUTER_HULL_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Compute the "outer hull" of a potentially non-manifold mesh (V,F) whose
|
|
// intersections have been "resolved" (e.g. using `cork` or
|
|
// `igl::cgal::selfintersect`). The outer hull is defined to be all facets
|
|
// (regardless of orientation) for which there exists some path from infinity
|
|
// to the face without intersecting any other facets. For solids, this is the
|
|
// surface of the solid. In general this includes any thin "wings" or
|
|
// "flaps". This implementation largely follows Section 3.6 of "Direct
|
|
// repair of self-intersecting meshes" [Attene 2014].
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// N #F by 3 list of per-face normals
|
|
// Outputs:
|
|
// G #G by 3 list of output triangle indices into V
|
|
// J #G list of indices into F
|
|
// flip #F list of whether facet was added to G **and** flipped orientation
|
|
// (false for faces not added to G)
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename DerivedG,
|
|
typename DerivedJ,
|
|
typename Derivedflip>
|
|
IGL_INLINE void outer_hull(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedN> & N,
|
|
Eigen::PlainObjectBase<DerivedG> & G,
|
|
Eigen::PlainObjectBase<DerivedJ> & J,
|
|
Eigen::PlainObjectBase<Derivedflip> & flip);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedG,
|
|
typename DerivedJ,
|
|
typename Derivedflip>
|
|
IGL_INLINE void outer_hull(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedG> & G,
|
|
Eigen::PlainObjectBase<DerivedJ> & J,
|
|
Eigen::PlainObjectBase<Derivedflip> & flip);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "outer_hull.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_peel_outer_hull_layers = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_PEEL_OUTER_HULL_LAYERS_H
|
|
#define IGL_CGAL_PEEL_OUTER_HULL_LAYERS_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Computes necessary generic information for boolean operations by
|
|
// successively "peeling" off the "outer hull" of a mesh (V,F) resulting from
|
|
// "resolving" all (self-)intersections.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// N #F by 3 list of per-face normals
|
|
// Outputs:
|
|
// odd #F list of whether facet belongs to an odd iteration peel (otherwise
|
|
// an even iteration peel)
|
|
// flip #F list of whether a facet's orientation was flipped when facet
|
|
// "peeled" into its associated outer hull layer.
|
|
// Returns number of peels
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedN,
|
|
typename Derivedodd,
|
|
typename Derivedflip>
|
|
IGL_INLINE size_t peel_outer_hull_layers(
|
|
const Eigen::PlainObjectBase<DerivedV > & V,
|
|
const Eigen::PlainObjectBase<DerivedF > & F,
|
|
const Eigen::PlainObjectBase<DerivedN > & N,
|
|
Eigen::PlainObjectBase<Derivedodd > & odd,
|
|
Eigen::PlainObjectBase<Derivedflip > & flip);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename Derivedodd,
|
|
typename Derivedflip>
|
|
IGL_INLINE size_t peel_outer_hull_layers(
|
|
const Eigen::PlainObjectBase<DerivedV > & V,
|
|
const Eigen::PlainObjectBase<DerivedF > & F,
|
|
Eigen::PlainObjectBase<Derivedodd > & odd,
|
|
Eigen::PlainObjectBase<Derivedflip > & flip);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "peel_outer_hull_layers.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_point_mesh_squared_distance = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_POINT_MESH_SQUARED_DISTANCE_H
|
|
#define IGL_CGAL_POINT_MESH_SQUARED_DISTANCE_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
#include "CGAL_includes.hpp"
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Compute distances from a set of points P to a triangle mesh (V,F)
|
|
//
|
|
// Templates:
|
|
// Kernal CGAL computation and construction kernel (e.g.
|
|
// CGAL::Simple_cartesian<double>)
|
|
// Inputs:
|
|
// P #P by 3 list of query point positions
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// Outputs:
|
|
// sqrD #P list of smallest squared distances
|
|
// I #P list of facet indices corresponding to smallest distances
|
|
// C #P by 3 list of closest points
|
|
//
|
|
// Known bugs: This only computes distances to triangles. So unreferenced
|
|
// vertices and degenerate triangles (segments) are ignored.
|
|
template <typename Kernel>
|
|
IGL_INLINE void point_mesh_squared_distance(
|
|
const Eigen::MatrixXd & P,
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
Eigen::VectorXd & sqrD,
|
|
Eigen::VectorXi & I,
|
|
Eigen::MatrixXd & C);
|
|
// Probably can do this in a way that we don't pass around `tree` and `T`
|
|
//
|
|
// Outputs:
|
|
// tree CGAL's AABB tree
|
|
// T list of CGAL triangles in order of F (for determining which was found
|
|
// in computation)
|
|
template <typename Kernel>
|
|
IGL_INLINE void point_mesh_squared_distance_precompute(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
CGAL::AABB_tree<
|
|
CGAL::AABB_traits<Kernel,
|
|
CGAL::AABB_triangle_primitive<Kernel,
|
|
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
|
>
|
|
>
|
|
> & tree,
|
|
std::vector<CGAL::Triangle_3<Kernel> > & T);
|
|
// Inputs:
|
|
// see above
|
|
// Outputs:
|
|
// see above
|
|
template <typename Kernel>
|
|
IGL_INLINE void point_mesh_squared_distance(
|
|
const Eigen::MatrixXd & P,
|
|
const CGAL::AABB_tree<
|
|
CGAL::AABB_traits<Kernel,
|
|
CGAL::AABB_triangle_primitive<Kernel,
|
|
typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
|
|
>
|
|
>
|
|
> & tree,
|
|
const std::vector<CGAL::Triangle_3<Kernel> > & T,
|
|
Eigen::VectorXd & sqrD,
|
|
Eigen::VectorXi & I,
|
|
Eigen::MatrixXd & C);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "point_mesh_squared_distance.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_polyhedron_to_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_POLYHEDRON_TO_MESH_H
|
|
#define IGL_CGAL_POLYHEDRON_TO_MESH_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Convert a CGAL Polyhedron to a mesh (V,F)
|
|
//
|
|
// Templates:
|
|
// Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
|
|
// Inputs:
|
|
// poly cgal polyhedron
|
|
// Outputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
template <typename Polyhedron>
|
|
IGL_INLINE void polyhedron_to_mesh(
|
|
const Polyhedron & poly,
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXi & F);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "polyhedron_to_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_remesh_self_intersections = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_REMESH_SELF_INTERSECTIONS_H
|
|
#define IGL_CGAL_REMESH_SELF_INTERSECTIONS_H
|
|
#include <igl/igl_inline.h>
|
|
#include "RemeshSelfIntersectionsParam.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
#ifdef MEX
|
|
# include <mex.h>
|
|
# include <cassert>
|
|
# undef assert
|
|
# define assert( isOK ) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(C_STR(__FILE__<<":"<<__LINE__<<": failed assertion `"<<#isOK<<"'"<<std::endl) ) )
|
|
#endif
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Given a triangle mesh (V,F) compute a new mesh (VV,FF) which is the same
|
|
// as (V,F) except that any self-intersecting triangles in (V,F) have been
|
|
// subdivided (new vertices and face created) so that the self-intersection
|
|
// contour lies exactly on edges in (VV,FF). New vertices will appear in
|
|
// original faces or on original edges. New vertices on edges are "merged"
|
|
// only across original faces sharing that edge. This means that if the input
|
|
// triangle mesh is a closed manifold the output will be too.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices into V
|
|
// params struct of optional parameters
|
|
// Outputs:
|
|
// VV #VV by 3 list of vertex positions
|
|
// FF #FF by 3 list of triangle indices into V
|
|
// IF #intersecting face pairs by 2 list of intersecting face pairs,
|
|
// indexing F
|
|
// J #FF list of indices into F denoting birth triangle
|
|
// IM #VV list of indices into VV of unique vertices.
|
|
//
|
|
// Known bugs: If an existing edge in (V,F) lies exactly on another face then
|
|
// any resulting additional vertices along that edge may not get properly
|
|
// connected so that the output mesh has the same global topology. This is
|
|
// because
|
|
//
|
|
// Example:
|
|
// // resolve intersections
|
|
// igl::cgal::remesh_self_intersections(V,F,params,VV,FF,IF,J,IM);
|
|
// // _apply_ duplicate vertex mapping IM to FF
|
|
// for_each(FF.data(),FF.data()+FF.size(),[&IM](int & a){a=IM(a);});
|
|
// // remove any vertices now unreferenced after duplicate mapping.
|
|
// igl::remove_unreferenced(VV,FF,SV,SF,UIM);
|
|
// // Now (SV,SF) is ready to extract outer hull
|
|
// igl::cgal::outer_hull(SV,SF,G,J,flip);
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
IGL_INLINE void remesh_self_intersections(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const RemeshSelfIntersectionsParam & params,
|
|
Eigen::PlainObjectBase<DerivedVV> & VV,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedIF> & IF,
|
|
Eigen::PlainObjectBase<DerivedJ> & J,
|
|
Eigen::PlainObjectBase<DerivedIM> & IM);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "remesh_self_intersections.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_RemeshSelfIntersectionsParam = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
|
|
#define IGL_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Optional Parameters
|
|
// DetectOnly Only compute IF, leave VV and FF alone
|
|
struct RemeshSelfIntersectionsParam
|
|
{
|
|
bool detect_only;
|
|
bool first_only;
|
|
RemeshSelfIntersectionsParam():detect_only(false),first_only(false){};
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_SelfIntersectMesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_SELFINTERSECTMESH_H
|
|
#define IGL_CGAL_SELFINTERSECTMESH_H
|
|
|
|
#include "CGAL_includes.hpp"
|
|
#include "RemeshSelfIntersectionsParam.h"
|
|
|
|
#include <Eigen/Dense>
|
|
#include <list>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
//#define IGL_SELFINTERSECTMESH_DEBUG
|
|
#ifndef IGL_FIRST_HIT_EXCEPTION
|
|
#define IGL_FIRST_HIT_EXCEPTION 10
|
|
#endif
|
|
|
|
// The easiest way to keep track of everything is to use a class
|
|
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// Kernel is a CGAL kernel like:
|
|
// CGAL::Exact_predicates_inexact_constructions_kernel
|
|
// or
|
|
// CGAL::Exact_predicates_exact_constructions_kernel
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
class SelfIntersectMesh
|
|
{
|
|
typedef
|
|
SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM> Self;
|
|
public:
|
|
// 3D Primitives
|
|
typedef CGAL::Point_3<Kernel> Point_3;
|
|
typedef CGAL::Segment_3<Kernel> Segment_3;
|
|
typedef CGAL::Triangle_3<Kernel> Triangle_3;
|
|
typedef CGAL::Plane_3<Kernel> Plane_3;
|
|
typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
|
|
//typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3;
|
|
//typedef CGAL::Nef_polyhedron_3<Kernel> Nef_polyhedron_3;
|
|
// 2D Primitives
|
|
typedef CGAL::Point_2<Kernel> Point_2;
|
|
typedef CGAL::Segment_2<Kernel> Segment_2;
|
|
typedef CGAL::Triangle_2<Kernel> Triangle_2;
|
|
// 2D Constrained Delaunay Triangulation types
|
|
typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
|
|
typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
|
|
typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
|
|
typedef CGAL::Exact_intersections_tag Itag;
|
|
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag>
|
|
CDT_2;
|
|
typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
|
|
// Axis-align boxes for all-pairs self-intersection detection
|
|
typedef std::vector<Triangle_3> Triangles;
|
|
typedef typename Triangles::iterator TrianglesIterator;
|
|
typedef typename Triangles::const_iterator TrianglesConstIterator;
|
|
typedef
|
|
CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator>
|
|
Box;
|
|
|
|
// Input mesh
|
|
const Eigen::PlainObjectBase<DerivedV> & V;
|
|
const Eigen::PlainObjectBase<DerivedF> & F;
|
|
// Number of self-intersecting triangle pairs
|
|
typedef typename DerivedF::Index Index;
|
|
Index count;
|
|
typedef std::vector<CGAL::Object> ObjectList;
|
|
std::vector<ObjectList > F_objects;
|
|
Triangles T;
|
|
typedef std::vector<Index> IndexList;
|
|
IndexList lIF;
|
|
std::vector<bool> offensive;
|
|
std::vector<Index> offending_index;
|
|
std::vector<Index> offending;
|
|
// Make a short name for the edge map's key
|
|
typedef std::pair<Index,Index> EMK;
|
|
// Make a short name for the type stored at each edge, the edge map's
|
|
// value
|
|
typedef std::vector<Index> EMV;
|
|
// Make a short name for the edge map
|
|
typedef std::map<EMK,EMV> EdgeMap;
|
|
EdgeMap edge2faces;
|
|
public:
|
|
RemeshSelfIntersectionsParam params;
|
|
public:
|
|
// Constructs (VV,FF) a new mesh with self-intersections of (V,F)
|
|
// subdivided
|
|
//
|
|
// See also: remesh_self_intersections.h
|
|
inline SelfIntersectMesh(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const RemeshSelfIntersectionsParam & params,
|
|
Eigen::PlainObjectBase<DerivedVV> & VV,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedIF> & IF,
|
|
Eigen::PlainObjectBase<DerivedJ> & J,
|
|
Eigen::PlainObjectBase<DerivedIM> & IM);
|
|
private:
|
|
// Helper function to mark a face as offensive
|
|
//
|
|
// Inputs:
|
|
// f index of face in F
|
|
inline void mark_offensive(const Index f);
|
|
// Helper function to count intersections between faces
|
|
//
|
|
// Input:
|
|
// fa index of face A in F
|
|
// fb index of face B in F
|
|
inline void count_intersection( const Index fa, const Index fb);
|
|
// Helper function for box_intersect. Intersect two triangles A and B,
|
|
// append the intersection object (point,segment,triangle) to a running
|
|
// list for A and B
|
|
//
|
|
// Inputs:
|
|
// A triangle in 3D
|
|
// B triangle in 3D
|
|
// fa index of A in F (and F_objects)
|
|
// fb index of A in F (and F_objects)
|
|
// Returns true only if A intersects B
|
|
//
|
|
inline bool intersect(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb);
|
|
// Helper function for box_intersect. In the case where A and B have
|
|
// already been identified to share a vertex, then we only want to add
|
|
// possible segment intersections. Assumes truly duplicate triangles are
|
|
// not given as input
|
|
//
|
|
// Inputs:
|
|
// A triangle in 3D
|
|
// B triangle in 3D
|
|
// fa index of A in F (and F_objects)
|
|
// fb index of B in F (and F_objects)
|
|
// va index of shared vertex in A (and F_objects)
|
|
// vb index of shared vertex in B (and F_objects)
|
|
//// Returns object of intersection (should be Segment or point)
|
|
// Returns true if intersection (besides shared point)
|
|
//
|
|
inline bool single_shared_vertex(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb,
|
|
const Index va,
|
|
const Index vb);
|
|
// Helper handling one direction
|
|
inline bool single_shared_vertex(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb,
|
|
const Index va);
|
|
// Helper function for box_intersect. In the case where A and B have
|
|
// already been identified to share two vertices, then we only want to add
|
|
// a possible coplanar (Triangle) intersection. Assumes truly degenerate
|
|
// facets are not givin as input.
|
|
inline bool double_shared_vertex(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb);
|
|
|
|
public:
|
|
// Callback function called during box self intersections test. Means
|
|
// boxes a and b intersect. This method then checks if the triangles in
|
|
// each box intersect and if so, then processes the intersections
|
|
//
|
|
// Inputs:
|
|
// a box containing a triangle
|
|
// b box containing a triangle
|
|
inline void box_intersect(const Box& a, const Box& b);
|
|
private:
|
|
// Compute 2D delaunay triangulation of a given 3d triangle and a list of
|
|
// intersection objects (points,segments,triangles). CGAL uses an affine
|
|
// projection rather than an isometric projection, so we're not
|
|
// guaranteed that the 2D delaunay triangulation here will be a delaunay
|
|
// triangulation in 3D.
|
|
//
|
|
// Inputs:
|
|
// A triangle in 3D
|
|
// A_objects_3 updated list of intersection objects for A
|
|
// Outputs:
|
|
// cdt Contrained delaunay triangulation in projected 2D plane
|
|
inline void projected_delaunay(
|
|
const Triangle_3 & A,
|
|
const ObjectList & A_objects_3,
|
|
CDT_plus_2 & cdt);
|
|
// Getters:
|
|
public:
|
|
//const IndexList& get_lIF() const{ return lIF;}
|
|
static inline void box_intersect_static(
|
|
SelfIntersectMesh * SIM,
|
|
const Box &a,
|
|
const Box &b);
|
|
// Annoying wrappers to conver from cgal to double or cgal
|
|
static inline void to_output_type(const typename Kernel::FT & cgal,double & d);
|
|
static inline void to_output_type(
|
|
const typename CGAL::Epeck::FT & cgal,
|
|
CGAL::Epeck::FT & d);
|
|
};
|
|
}
|
|
}
|
|
|
|
// Implementation
|
|
|
|
#include "mesh_to_cgal_triangle_list.h"
|
|
|
|
#include <igl/REDRUM.h>
|
|
#include <igl/get_seconds.h>
|
|
#include <igl/C_STR.h>
|
|
|
|
|
|
#include <functional>
|
|
#include <algorithm>
|
|
#include <exception>
|
|
#include <cassert>
|
|
#include <iostream>
|
|
|
|
// References:
|
|
// http://minregret.googlecode.com/svn/trunk/skyline/src/extern/CGAL-3.3.1/examples/Polyhedron/polyhedron_self_intersection.cpp
|
|
// http://www.cgal.org/Manual/3.9/examples/Boolean_set_operations_2/do_intersect.cpp
|
|
|
|
// Q: Should we be using CGAL::Polyhedron_3?
|
|
// A: No! Input is just a list of unoriented triangles. Polyhedron_3 requires
|
|
// a 2-manifold.
|
|
// A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy
|
|
// to take advantage of functions like insert_in_facet because we want to
|
|
// constrain segments. Hmmm. Actualy Triangulation_3 doesn't look right...
|
|
|
|
//static void box_intersect(SelfIntersectMesh * SIM,const Box & A, const Box & B)
|
|
//{
|
|
// return SIM->box_intersect(A,B);
|
|
//}
|
|
|
|
|
|
// CGAL's box_self_intersection_d uses C-style function callbacks without
|
|
// userdata. This is a leapfrog method for calling a member function. It should
|
|
// be bound as if the prototype was:
|
|
// static void box_intersect(const Box &a, const Box &b)
|
|
// using boost:
|
|
// boost::function<void(const Box &a,const Box &b)> cb
|
|
// = boost::bind(&::box_intersect, this, _1,_2);
|
|
//
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline void igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::box_intersect_static(
|
|
Self * SIM,
|
|
const typename Self::Box &a,
|
|
const typename Self::Box &b)
|
|
{
|
|
SIM->box_intersect(a,b);
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::SelfIntersectMesh(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const RemeshSelfIntersectionsParam & params,
|
|
Eigen::PlainObjectBase<DerivedVV> & VV,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedIF> & IF,
|
|
Eigen::PlainObjectBase<DerivedJ> & J,
|
|
Eigen::PlainObjectBase<DerivedIM> & IM):
|
|
V(V),
|
|
F(F),
|
|
count(0),
|
|
F_objects(F.rows()),
|
|
T(),
|
|
lIF(),
|
|
offensive(F.rows(),false),
|
|
offending_index(F.rows(),-1),
|
|
offending(),
|
|
edge2faces(),
|
|
params(params)
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
const auto & tictoc = []()
|
|
{
|
|
static double t_start = igl::get_seconds();
|
|
double diff = igl::get_seconds()-t_start;
|
|
t_start += diff;
|
|
return diff;
|
|
};
|
|
tictoc();
|
|
#endif
|
|
|
|
// Compute and process self intersections
|
|
mesh_to_cgal_triangle_list(V,F,T);
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
cout<<"mesh_to_cgal_triangle_list: "<<tictoc()<<endl;
|
|
#endif
|
|
// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5
|
|
// Create the corresponding vector of bounding boxes
|
|
std::vector<Box> boxes;
|
|
boxes.reserve(T.size());
|
|
for (
|
|
TrianglesIterator tit = T.begin();
|
|
tit != T.end();
|
|
++tit)
|
|
{
|
|
boxes.push_back(Box(tit->bbox(), tit));
|
|
}
|
|
// Leapfrog callback
|
|
std::function<void(const Box &a,const Box &b)> cb =
|
|
std::bind(&box_intersect_static, this,
|
|
// Explicitly use std namespace to avoid confusion with boost (who puts
|
|
// _1 etc. in global namespace)
|
|
std::placeholders::_1,
|
|
std::placeholders::_2);
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
cout<<"boxes and bind: "<<tictoc()<<endl;
|
|
#endif
|
|
// Run the self intersection algorithm with all defaults
|
|
try{
|
|
CGAL::box_self_intersection_d(boxes.begin(), boxes.end(),cb);
|
|
}catch(int e)
|
|
{
|
|
// Rethrow if not IGL_FIRST_HIT_EXCEPTION
|
|
if(e != IGL_FIRST_HIT_EXCEPTION)
|
|
{
|
|
throw e;
|
|
}
|
|
// Otherwise just fall through
|
|
}
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
cout<<"box_self_intersection_d: "<<tictoc()<<endl;
|
|
#endif
|
|
|
|
// Convert lIF to Eigen matrix
|
|
assert(lIF.size()%2 == 0);
|
|
IF.resize(lIF.size()/2,2);
|
|
{
|
|
Index i=0;
|
|
for(
|
|
typename IndexList::const_iterator ifit = lIF.begin();
|
|
ifit!=lIF.end();
|
|
)
|
|
{
|
|
IF(i,0) = (*ifit);
|
|
ifit++;
|
|
IF(i,1) = (*ifit);
|
|
ifit++;
|
|
i++;
|
|
}
|
|
}
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
cout<<"IF: "<<tictoc()<<endl;
|
|
#endif
|
|
|
|
if(params.detect_only)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int NF_count = 0;
|
|
// list of new faces, we'll fix F later
|
|
vector<
|
|
typename Eigen::Matrix<typename DerivedFF::Scalar,Dynamic,Dynamic>
|
|
> NF(offending.size());
|
|
// list of new vertices
|
|
typedef vector<Point_3> Point_3List;
|
|
Point_3List NV;
|
|
Index NV_count = 0;
|
|
vector<CDT_plus_2> cdt(offending.size());
|
|
vector<Plane_3> P(offending.size());
|
|
// Use map for *all* faces
|
|
map<typename CDT_plus_2::Vertex_handle,Index> v2i;
|
|
// Loop over offending triangles
|
|
const size_t noff = offending.size();
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
double t_proj_del = 0;
|
|
#endif
|
|
// Unfortunately it looks like CGAL has trouble allocating memory when
|
|
// multiple openmp threads are running. Crashes durring CDT...
|
|
//# pragma omp parallel for if (noff>1000)
|
|
for(Index o = 0;o<(Index)noff;o++)
|
|
{
|
|
// index in F
|
|
const Index f = offending[o];
|
|
{
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
const double t_before = get_seconds();
|
|
#endif
|
|
projected_delaunay(T[f],F_objects[f],cdt[o]);
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
t_proj_del += (get_seconds()-t_before);
|
|
#endif
|
|
}
|
|
// Q: Is this also delaunay in 3D?
|
|
// A: No, because the projection is affine and delaunay is not affine
|
|
// invariant.
|
|
// Q: Then, can't we first get the 2D delaunay triangulation, then lift it
|
|
// to 3D and flip any offending edges?
|
|
// Plane of projection (also used by projected_delaunay)
|
|
P[o] = Plane_3(T[f].vertex(0),T[f].vertex(1),T[f].vertex(2));
|
|
// Build index map
|
|
{
|
|
Index i=0;
|
|
for(
|
|
typename CDT_plus_2::Finite_vertices_iterator vit = cdt[o].finite_vertices_begin();
|
|
vit != cdt[o].finite_vertices_end();
|
|
++vit)
|
|
{
|
|
if(i<3)
|
|
{
|
|
//cout<<T[f].vertex(i)<<
|
|
// (T[f].vertex(i) == P[o].to_3d(vit->point())?" == ":" != ")<<
|
|
// P[o].to_3d(vit->point())<<endl;
|
|
#ifndef NDEBUG
|
|
// I want to be sure that the original corners really show up as the
|
|
// original corners of the CDT. I.e. I don't trust CGAL to maintain
|
|
// the order
|
|
assert(T[f].vertex(i) == P[o].to_3d(vit->point()));
|
|
#endif
|
|
// For first three, use original index in F
|
|
//# pragma omp critical
|
|
v2i[vit] = F(f,i);
|
|
}else
|
|
{
|
|
const Point_3 vit_point_3 = P[o].to_3d(vit->point());
|
|
// First look up each edge's neighbors to see if exact point has
|
|
// already been added (This makes everything a bit quadratic)
|
|
bool found = false;
|
|
for(int e = 0; e<3 && !found;e++)
|
|
{
|
|
// Index of F's eth edge in V
|
|
Index i = F(f,(e+1)%3);
|
|
Index j = F(f,(e+2)%3);
|
|
// Be sure that i<j
|
|
if(i>j)
|
|
{
|
|
swap(i,j);
|
|
}
|
|
assert(edge2faces.count(EMK(i,j))==1);
|
|
// loop over neighbors
|
|
for(
|
|
typename IndexList::const_iterator nit = edge2faces[EMK(i,j)].begin();
|
|
nit != edge2faces[EMK(i,j)].end() && !found;
|
|
nit++)
|
|
{
|
|
// don't consider self
|
|
if(*nit == f)
|
|
{
|
|
continue;
|
|
}
|
|
// index of neighbor in offending (to find its cdt)
|
|
Index no = offending_index[*nit];
|
|
// Loop over vertices of that neighbor's cdt (might not have been
|
|
// processed yet, but then it's OK because it'll just be empty)
|
|
for(
|
|
typename CDT_plus_2::Finite_vertices_iterator uit = cdt[no].finite_vertices_begin();
|
|
uit != cdt[no].finite_vertices_end() && !found;
|
|
++uit)
|
|
{
|
|
if(vit_point_3 == P[no].to_3d(uit->point()))
|
|
{
|
|
assert(v2i.count(uit) == 1);
|
|
//# pragma omp critical
|
|
v2i[vit] = v2i[uit];
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!found)
|
|
{
|
|
//# pragma omp critical
|
|
{
|
|
v2i[vit] = V.rows()+NV_count;
|
|
NV.push_back(vit_point_3);
|
|
NV_count++;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
{
|
|
Index i = 0;
|
|
// Resize to fit new number of triangles
|
|
NF[o].resize(cdt[o].number_of_faces(),3);
|
|
//# pragma omp atomic
|
|
NF_count+=NF[o].rows();
|
|
// Append new faces to NF
|
|
for(
|
|
typename CDT_plus_2::Finite_faces_iterator fit = cdt[o].finite_faces_begin();
|
|
fit != cdt[o].finite_faces_end();
|
|
++fit)
|
|
{
|
|
NF[o](i,0) = v2i[fit->vertex(0)];
|
|
NF[o](i,1) = v2i[fit->vertex(1)];
|
|
NF[o](i,2) = v2i[fit->vertex(2)];
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
cout<<"CDT: "<<tictoc()<<" "<<t_proj_del<<endl;
|
|
#endif
|
|
|
|
assert(NV_count == (Index)NV.size());
|
|
// Build output
|
|
#ifndef NDEBUG
|
|
{
|
|
Index off_count = 0;
|
|
for(Index f = 0;f<F.rows();f++)
|
|
{
|
|
off_count+= (offensive[f]?1:0);
|
|
}
|
|
assert(off_count==(Index)offending.size());
|
|
}
|
|
#endif
|
|
// Append faces
|
|
FF.resize(F.rows()-offending.size()+NF_count,3);
|
|
J.resize(FF.rows());
|
|
// First append non-offending original faces
|
|
// There's an Eigen way to do this in one line but I forget
|
|
Index off = 0;
|
|
for(Index f = 0;f<F.rows();f++)
|
|
{
|
|
if(!offensive[f])
|
|
{
|
|
FF.row(off) = F.row(f);
|
|
J(off) = f;
|
|
off++;
|
|
}
|
|
}
|
|
assert(off == (Index)(F.rows()-offending.size()));
|
|
// Now append replacement faces for offending faces
|
|
for(Index o = 0;o<(Index)offending.size();o++)
|
|
{
|
|
FF.block(off,0,NF[o].rows(),3) = NF[o];
|
|
J.block(off,0,NF[o].rows(),1).setConstant(offending[o]);
|
|
off += NF[o].rows();
|
|
}
|
|
// Append vertices
|
|
VV.resize(V.rows()+NV_count,3);
|
|
VV.block(0,0,V.rows(),3) = V.template cast<typename DerivedVV::Scalar>();
|
|
{
|
|
Index i = 0;
|
|
for(
|
|
typename Point_3List::const_iterator nvit = NV.begin();
|
|
nvit != NV.end();
|
|
nvit++)
|
|
{
|
|
for(Index d = 0;d<3;d++)
|
|
{
|
|
const Point_3 & p = *nvit;
|
|
// Don't convert via double if output type is same as Kernel
|
|
to_output_type(p[d], VV(V.rows()+i,d));
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
IM.resize(VV.rows(),1);
|
|
map<Point_3,Index> vv2i;
|
|
// Safe to check for duplicates using double for original vertices: if
|
|
// incoming reps are different then the points are unique.
|
|
for(Index v = 0;v<V.rows();v++)
|
|
{
|
|
const Point_3 p(V(v,0),V(v,1),V(v,2));
|
|
if(vv2i.count(p)==0)
|
|
{
|
|
vv2i[p] = v;
|
|
}
|
|
assert(vv2i.count(p) == 1);
|
|
IM(v) = vv2i[p];
|
|
}
|
|
// Must check for duplicates of new vertices using exact.
|
|
{
|
|
Index v = V.rows();
|
|
for(
|
|
typename Point_3List::const_iterator nvit = NV.begin();
|
|
nvit != NV.end();
|
|
nvit++)
|
|
{
|
|
const Point_3 & p = *nvit;
|
|
if(vv2i.count(p)==0)
|
|
{
|
|
vv2i[p] = v;
|
|
}
|
|
assert(vv2i.count(p) == 1);
|
|
IM(v) = vv2i[p];
|
|
v++;
|
|
}
|
|
}
|
|
#ifdef IGL_SELFINTERSECTMESH_DEBUG
|
|
cout<<"Output + dupes: "<<tictoc()<<endl;
|
|
#endif
|
|
|
|
// Q: Does this give the same result as TETGEN?
|
|
// A: For the cow and beast, yes.
|
|
|
|
// Q: Is tetgen faster than this CGAL implementation?
|
|
// A: Well, yes. But Tetgen is only solving the detection (predicates)
|
|
// problem. This is also appending the intersection objects (construction).
|
|
// But maybe tetgen is still faster for the detection part. For example, this
|
|
// CGAL implementation on the beast takes 98 seconds but tetgen detection
|
|
// takes 14 seconds
|
|
|
|
}
|
|
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline void igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::mark_offensive(const Index f)
|
|
{
|
|
using namespace std;
|
|
lIF.push_back(f);
|
|
if(!offensive[f])
|
|
{
|
|
offensive[f]=true;
|
|
offending_index[f]=offending.size();
|
|
offending.push_back(f);
|
|
// Add to edge map
|
|
for(Index e = 0; e<3;e++)
|
|
{
|
|
// Index of F's eth edge in V
|
|
Index i = F(f,(e+1)%3);
|
|
Index j = F(f,(e+2)%3);
|
|
// Be sure that i<j
|
|
if(i>j)
|
|
{
|
|
swap(i,j);
|
|
}
|
|
// Create new list if there is no entry
|
|
if(edge2faces.count(EMK(i,j))==0)
|
|
{
|
|
edge2faces[EMK(i,j)] = EMV();
|
|
}
|
|
// append to list
|
|
edge2faces[EMK(i,j)].push_back(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline void igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::count_intersection(
|
|
const Index fa,
|
|
const Index fb)
|
|
{
|
|
mark_offensive(fa);
|
|
mark_offensive(fb);
|
|
this->count++;
|
|
// We found the first intersection
|
|
if(params.first_only && this->count >= 1)
|
|
{
|
|
throw IGL_FIRST_HIT_EXCEPTION;
|
|
}
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline bool igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::intersect(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb)
|
|
{
|
|
// Determine whether there is an intersection
|
|
if(!CGAL::do_intersect(A,B))
|
|
{
|
|
return false;
|
|
}
|
|
if(!params.detect_only)
|
|
{
|
|
// Construct intersection
|
|
CGAL::Object result = CGAL::intersection(A,B);
|
|
F_objects[fa].push_back(result);
|
|
F_objects[fb].push_back(result);
|
|
}
|
|
count_intersection(fa,fb);
|
|
return true;
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline bool igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::single_shared_vertex(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb,
|
|
const Index va,
|
|
const Index vb)
|
|
{
|
|
////using namespace std;
|
|
//CGAL::Object result = CGAL::intersection(A,B);
|
|
//if(CGAL::object_cast<Segment_3 >(&result))
|
|
//{
|
|
// // Append to each triangle's running list
|
|
// F_objects[fa].push_back(result);
|
|
// F_objects[fb].push_back(result);
|
|
// count_intersection(fa,fb);
|
|
//}else
|
|
//{
|
|
// // Then intersection must be at point
|
|
// // And point must be at shared vertex
|
|
// assert(CGAL::object_cast<Point_3>(&result));
|
|
//}
|
|
if(single_shared_vertex(A,B,fa,fb,va))
|
|
{
|
|
return true;
|
|
}
|
|
return single_shared_vertex(B,A,fb,fa,vb);
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline bool igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::single_shared_vertex(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb,
|
|
const Index va)
|
|
{
|
|
// This was not a good idea. It will not handle coplanar triangles well.
|
|
using namespace std;
|
|
Segment_3 sa(
|
|
A.vertex((va+1)%3),
|
|
A.vertex((va+2)%3));
|
|
|
|
if(CGAL::do_intersect(sa,B))
|
|
{
|
|
CGAL::Object result = CGAL::intersection(sa,B);
|
|
if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
|
|
{
|
|
if(!params.detect_only)
|
|
{
|
|
// Single intersection --> segment from shared point to intersection
|
|
CGAL::Object seg = CGAL::make_object(Segment_3(
|
|
A.vertex(va),
|
|
*p));
|
|
F_objects[fa].push_back(seg);
|
|
F_objects[fb].push_back(seg);
|
|
}
|
|
count_intersection(fa,fb);
|
|
return true;
|
|
}else if(CGAL::object_cast<Segment_3 >(&result))
|
|
{
|
|
//cerr<<REDRUM("Coplanar at: "<<fa<<" & "<<fb<<" (single shared).")<<endl;
|
|
// Must be coplanar
|
|
if(params.detect_only)
|
|
{
|
|
count_intersection(fa,fb);
|
|
}else
|
|
{
|
|
// WRONG:
|
|
//// Segment intersection --> triangle from shared point to intersection
|
|
//CGAL::Object tri = CGAL::make_object(Triangle_3(
|
|
// A.vertex(va),
|
|
// s->vertex(0),
|
|
// s->vertex(1)));
|
|
//F_objects[fa].push_back(tri);
|
|
//F_objects[fb].push_back(tri);
|
|
//count_intersection(fa,fb);
|
|
// Need to do full test. Intersection could be a general poly.
|
|
bool test = intersect(A,B,fa,fb);
|
|
((void)test);
|
|
assert(test);
|
|
}
|
|
return true;
|
|
}else
|
|
{
|
|
cerr<<REDRUM("Segment ∩ triangle neither point nor segment?")<<endl;
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline bool igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::double_shared_vertex(
|
|
const Triangle_3 & A,
|
|
const Triangle_3 & B,
|
|
const Index fa,
|
|
const Index fb)
|
|
{
|
|
using namespace std;
|
|
// Cheaper way to do this than calling do_intersect?
|
|
if(
|
|
// Can only have an intersection if co-planar
|
|
(A.supporting_plane() == B.supporting_plane() ||
|
|
A.supporting_plane() == B.supporting_plane().opposite()) &&
|
|
CGAL::do_intersect(A,B))
|
|
{
|
|
// Construct intersection
|
|
try
|
|
{
|
|
// This can fail for Epick but not Epeck
|
|
CGAL::Object result = CGAL::intersection(A,B);
|
|
if(!result.empty())
|
|
{
|
|
if(CGAL::object_cast<Segment_3 >(&result))
|
|
{
|
|
// not coplanar
|
|
return false;
|
|
} else if(CGAL::object_cast<Point_3 >(&result))
|
|
{
|
|
// this "shouldn't" happen but does for inexact
|
|
return false;
|
|
} else
|
|
{
|
|
if(!params.detect_only)
|
|
{
|
|
// Triangle object
|
|
F_objects[fa].push_back(result);
|
|
F_objects[fb].push_back(result);
|
|
}
|
|
count_intersection(fa,fb);
|
|
//cerr<<REDRUM("Coplanar at: "<<fa<<" & "<<fb<<" (double shared).")<<endl;
|
|
return true;
|
|
}
|
|
}else
|
|
{
|
|
// CGAL::intersection is disagreeing with do_intersect
|
|
return false;
|
|
}
|
|
}catch(...)
|
|
{
|
|
// This catches some cgal assertion:
|
|
// CGAL error: assertion violation!
|
|
// Expression : is_finite(d)
|
|
// File : /opt/local/include/CGAL/GMP/Gmpq_type.h
|
|
// Line : 132
|
|
// Explanation:
|
|
// But only if NDEBUG is not defined, otherwise there's an uncaught
|
|
// "Floating point exception: 8" SIGFPE
|
|
return false;
|
|
}
|
|
}
|
|
// No intersection.
|
|
return false;
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline void igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::box_intersect(
|
|
const Box& a,
|
|
const Box& b)
|
|
{
|
|
using namespace std;
|
|
// Could we write this as a static function of:
|
|
//
|
|
// F.row(fa)
|
|
// F.row(fb)
|
|
// A
|
|
// B
|
|
|
|
// index in F and T
|
|
Index fa = a.handle()-T.begin();
|
|
Index fb = b.handle()-T.begin();
|
|
const Triangle_3 & A = *a.handle();
|
|
const Triangle_3 & B = *b.handle();
|
|
// I'm not going to deal with degenerate triangles, though at some point we
|
|
// should
|
|
assert(!a.handle()->is_degenerate());
|
|
assert(!b.handle()->is_degenerate());
|
|
// Number of combinatorially shared vertices
|
|
Index comb_shared_vertices = 0;
|
|
// Number of geometrically shared vertices (*not* including combinatorially
|
|
// shared)
|
|
Index geo_shared_vertices = 0;
|
|
// Keep track of shared vertex indices (we only handles single shared
|
|
// vertices as a special case, so just need last/first/only ones)
|
|
Index va=-1,vb=-1;
|
|
Index ea,eb;
|
|
for(ea=0;ea<3;ea++)
|
|
{
|
|
for(eb=0;eb<3;eb++)
|
|
{
|
|
if(F(fa,ea) == F(fb,eb))
|
|
{
|
|
comb_shared_vertices++;
|
|
va = ea;
|
|
vb = eb;
|
|
}else if(A.vertex(ea) == B.vertex(eb))
|
|
{
|
|
geo_shared_vertices++;
|
|
va = ea;
|
|
vb = eb;
|
|
}
|
|
}
|
|
}
|
|
const Index total_shared_vertices = comb_shared_vertices + geo_shared_vertices;
|
|
if(comb_shared_vertices== 3)
|
|
{
|
|
//// Combinatorially duplicate face, these should be removed by preprocessing
|
|
//cerr<<REDRUM("Facets "<<fa<<" and "<<fb<<" are combinatorial duplicates")<<endl;
|
|
goto done;
|
|
}
|
|
if(total_shared_vertices== 3)
|
|
{
|
|
//// Geometrically duplicate face, these should be removed by preprocessing
|
|
//cerr<<REDRUM("Facets "<<fa<<" and "<<fb<<" are geometrical duplicates")<<endl;
|
|
goto done;
|
|
}
|
|
//// SPECIAL CASES ARE BROKEN FOR COPLANAR TRIANGLES
|
|
//if(total_shared_vertices > 0)
|
|
//{
|
|
// bool coplanar =
|
|
// CGAL::coplanar(A.vertex(0),A.vertex(1),A.vertex(2),B.vertex(0)) &&
|
|
// CGAL::coplanar(A.vertex(0),A.vertex(1),A.vertex(2),B.vertex(1)) &&
|
|
// CGAL::coplanar(A.vertex(0),A.vertex(1),A.vertex(2),B.vertex(2));
|
|
// if(coplanar)
|
|
// {
|
|
// cerr<<MAGENTAGIN("Facets "<<fa<<" and "<<fb<<
|
|
// " are coplanar and share vertices")<<endl;
|
|
// goto full;
|
|
// }
|
|
//}
|
|
|
|
if(total_shared_vertices == 2)
|
|
{
|
|
// Q: What about coplanar?
|
|
//
|
|
// o o
|
|
// |\ /|
|
|
// | \/ |
|
|
// | /\ |
|
|
// |/ \|
|
|
// o----o
|
|
double_shared_vertex(A,B,fa,fb);
|
|
|
|
goto done;
|
|
}
|
|
assert(total_shared_vertices<=1);
|
|
if(total_shared_vertices==1)
|
|
{
|
|
assert(va>=0 && va<3);
|
|
assert(vb>=0 && vb<3);
|
|
//#ifndef NDEBUG
|
|
// CGAL::Object result =
|
|
//#endif
|
|
single_shared_vertex(A,B,fa,fb,va,vb);
|
|
//#ifndef NDEBUG
|
|
// if(!CGAL::object_cast<Segment_3 >(&result))
|
|
// {
|
|
// const Point_3 * p = CGAL::object_cast<Point_3 >(&result);
|
|
// assert(p);
|
|
// for(int ea=0;ea<3;ea++)
|
|
// {
|
|
// for(int eb=0;eb<3;eb++)
|
|
// {
|
|
// if(F(fa,ea) == F(fb,eb))
|
|
// {
|
|
// assert(*p==A.vertex(ea));
|
|
// assert(*p==B.vertex(eb));
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//#endif
|
|
}else
|
|
{
|
|
//full:
|
|
// No geometrically shared vertices, do general intersect
|
|
intersect(*a.handle(),*b.handle(),fa,fb);
|
|
}
|
|
done:
|
|
return;
|
|
}
|
|
|
|
// Compute 2D delaunay triangulation of a given 3d triangle and a list of
|
|
// intersection objects (points,segments,triangles). CGAL uses an affine
|
|
// projection rather than an isometric projection, so we're not guaranteed
|
|
// that the 2D delaunay triangulation here will be a delaunay triangulation
|
|
// in 3D.
|
|
//
|
|
// Inputs:
|
|
// A triangle in 3D
|
|
// A_objects_3 updated list of intersection objects for A
|
|
// Outputs:
|
|
// cdt Contrained delaunay triangulation in projected 2D plane
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline void igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::projected_delaunay(
|
|
const Triangle_3 & A,
|
|
const ObjectList & A_objects_3,
|
|
CDT_plus_2 & cdt)
|
|
{
|
|
using namespace std;
|
|
// http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
|
|
// Plane of triangle A
|
|
Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
|
|
// Insert triangle into vertices
|
|
typename CDT_plus_2::Vertex_handle corners[3];
|
|
for(Index i = 0;i<3;i++)
|
|
{
|
|
corners[i] = cdt.insert(P.to_2d(A.vertex(i)));
|
|
}
|
|
// Insert triangle edges as constraints
|
|
for(Index i = 0;i<3;i++)
|
|
{
|
|
cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
|
|
}
|
|
// Insert constraints for intersection objects
|
|
for( const auto & obj : A_objects_3)
|
|
{
|
|
if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
|
|
{
|
|
// Add segment constraint
|
|
cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
|
|
}else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
|
|
{
|
|
// Add point
|
|
cdt.insert(P.to_2d(*ipoint));
|
|
} else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
|
|
{
|
|
// Add 3 segment constraints
|
|
cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
|
|
cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
|
|
cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
|
|
} else if(const std::vector<Point_3 > *polyp =
|
|
CGAL::object_cast< std::vector<Point_3 > >(&obj))
|
|
{
|
|
//cerr<<REDRUM("Poly...")<<endl;
|
|
const std::vector<Point_3 > & poly = *polyp;
|
|
const Index m = poly.size();
|
|
assert(m>=2);
|
|
for(Index p = 0;p<m;p++)
|
|
{
|
|
const Index np = (p+1)%m;
|
|
cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
|
|
}
|
|
}else
|
|
{
|
|
cerr<<REDRUM("What is this object?!")<<endl;
|
|
assert(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline
|
|
void
|
|
igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::to_output_type(
|
|
const typename Kernel::FT & cgal,
|
|
double & d)
|
|
{
|
|
d = CGAL::to_double(cgal);
|
|
}
|
|
|
|
template <
|
|
typename Kernel,
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedVV,
|
|
typename DerivedFF,
|
|
typename DerivedIF,
|
|
typename DerivedJ,
|
|
typename DerivedIM>
|
|
inline
|
|
void
|
|
igl::cgal::SelfIntersectMesh<
|
|
Kernel,
|
|
DerivedV,
|
|
DerivedF,
|
|
DerivedVV,
|
|
DerivedFF,
|
|
DerivedIF,
|
|
DerivedJ,
|
|
DerivedIM>::to_output_type(
|
|
const typename CGAL::Epeck::FT & cgal,
|
|
CGAL::Epeck::FT & d)
|
|
{
|
|
d = cgal;
|
|
}
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_cgal_signed_distance_isosurface = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_CGAL_SIGNED_DISTANCE_ISOSURFACE_H
|
|
#define IGL_CGAL_SIGNED_DISTANCE_ISOSURFACE_H
|
|
#include "../igl_inline.h"
|
|
#include "../signed_distance.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace cgal
|
|
{
|
|
// SIGNED_DISTANCE_ISOSURFACE Compute the contour of an iso-level of the
|
|
// signed distance field to a given mesh.
|
|
//
|
|
// Inputs:
|
|
// IV #IV by 3 list of input mesh vertex positions
|
|
// IF #IF by 3 list of input triangle indices
|
|
// level iso-level to contour in world coords, negative is inside.
|
|
// angle_bound lower bound on triangle angles (mesh quality) (e.g. 28)
|
|
// radius_bound upper bound on triangle size (mesh density?) (e.g. 0.02)
|
|
// distance_bound cgal mysterious parameter (mesh density?) (e.g. 0.01)
|
|
// sign_type method for computing distance _sign_ (see
|
|
// ../signed_distance.h)
|
|
// Outputs:
|
|
// V #V by 3 list of input mesh vertex positions
|
|
// F #F by 3 list of input triangle indices
|
|
//
|
|
IGL_INLINE bool signed_distance_isosurface(
|
|
const Eigen::MatrixXd & IV,
|
|
const Eigen::MatrixXi & IF,
|
|
const double level,
|
|
const double angle_bound,
|
|
const double radius_bound,
|
|
const double distance_bound,
|
|
const SignedDistanceType sign_type,
|
|
Eigen::MatrixXd & V,
|
|
Eigen::MatrixXi & F);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "signed_distance_isosurface.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_comiso_frame_field = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COMISO_FRAMEFIELD_H
|
|
#define IGL_COMISO_FRAMEFIELD_H
|
|
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Dense>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
namespace comiso
|
|
{
|
|
// Generate a piecewise-constant frame-field field from a sparse set of constraints on faces
|
|
// using the algorithm proposed in:
|
|
// Frame Fields: Anisotropic and Non-Orthogonal Cross Fields
|
|
// Daniele Panozzo, Enrico Puppo, Marco Tarini, Olga Sorkine-Hornung,
|
|
// ACM Transactions on Graphics (SIGGRAPH, 2014)
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex coordinates
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// b #B by 1 list of constrained face indices
|
|
// bc1 #B by 3 list of the constrained first representative vector of the frame field (up to permutation and sign)
|
|
// bc2 #B by 3 list of the constrained second representative vector of the frame field (up to permutation and sign)
|
|
//
|
|
// Outputs:
|
|
// FF1 #F by 3 the first representative vector of the frame field (up to permutation and sign)
|
|
// FF2 #F by 3 the second representative vector of the frame field (up to permutation and sign)
|
|
//
|
|
// TODO: it now supports only soft constraints, should be extended to support both hard and soft constraints
|
|
IGL_INLINE void frame_field(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::MatrixXd& bc1,
|
|
const Eigen::MatrixXd& bc2,
|
|
Eigen::MatrixXd& FF1,
|
|
Eigen::MatrixXd& FF2
|
|
);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "frame_field.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_comiso_miq = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COMISO_MIQ_H
|
|
#define IGL_COMISO_MIQ_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
namespace comiso
|
|
{
|
|
// Global seamless parametrization aligned with a given per-face jacobian (PD1,PD2).
|
|
// The algorithm is based on
|
|
// "Mixed-Integer Quadrangulation" by D. Bommes, H. Zimmer, L. Kobbelt
|
|
// ACM SIGGRAPH 2009, Article No. 77 (http://dl.acm.org/citation.cfm?id=1531383)
|
|
// We thank Nico Pietroni for providing a reference implementation of MIQ
|
|
// on which our code is based.
|
|
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex 3D positions
|
|
// F #F by 3 list of faces indices in V
|
|
// PD1 #V by 3 first line of the Jacobian per triangle
|
|
// PD2 #V by 3 second line of the Jacobian per triangle
|
|
// (optional, if empty it will be a vector in the tangent plane orthogonal to PD1)
|
|
// scale global scaling for the gradient (controls the quads resolution)
|
|
// stiffness weight for the stiffness iterations
|
|
// direct_round greedily round all integer variables at once (greatly improves optimization speed but lowers quality)
|
|
// iter stiffness iterations (0 = no stiffness)
|
|
// local_iter number of local iterations for the integer rounding
|
|
// do_round enables the integer rounding (disabling it could be useful for debugging)
|
|
// round_vertices id of additional vertices that should be snapped to integer coordinates
|
|
// hard_features #H by 2 list of pairs of vertices that belongs to edges that should be snapped to integer coordinates
|
|
//
|
|
// Output:
|
|
// UV #UV by 2 list of vertices in 2D
|
|
// FUV #FUV by 3 list of face indices in UV
|
|
//
|
|
// TODO: rename the parameters name in the cpp consistenly
|
|
// improve the handling of hard_features, right now it might fail in difficult cases
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedU>
|
|
IGL_INLINE void miq(
|
|
const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD1,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD2,
|
|
Eigen::PlainObjectBase<DerivedU> &UV,
|
|
Eigen::PlainObjectBase<DerivedF> &FUV,
|
|
double scale = 30.0,
|
|
double stiffness = 5.0,
|
|
bool direct_round = false,
|
|
int iter = 5,
|
|
int local_iter = 5,
|
|
bool DoRound = true,bool SingularityRound=true,
|
|
std::vector<int> round_vertices = std::vector<int>(),
|
|
std::vector<std::vector<int> > hard_features = std::vector<std::vector<int> >());
|
|
|
|
// Helper function that allows to directly provided pre-combed bisectors for an already cut mesh
|
|
// Additional input:
|
|
// PD1_combed, PD2_combed : #F by 3 combed jacobian
|
|
// BIS1_combed, BIS2_combed: #F by 3 pre combed bi-sectors
|
|
// MMatch: #F by 3 list of per-corner integer PI/2 rotations
|
|
// Singular: #V list of flag that denotes if a vertex is singular or not
|
|
// SingularDegree: #V list of flag that denotes the degree of the singularity
|
|
// Seams: #F by 3 list of per-corner flag that denotes seams
|
|
|
|
template <typename DerivedV, typename DerivedF, typename DerivedU>
|
|
IGL_INLINE void miq(const Eigen::PlainObjectBase<DerivedV> &V,
|
|
const Eigen::PlainObjectBase<DerivedF> &F,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD1_combed,
|
|
const Eigen::PlainObjectBase<DerivedV> &PD2_combed,
|
|
// const Eigen::PlainObjectBase<DerivedV> &BIS1_combed,
|
|
// const Eigen::PlainObjectBase<DerivedV> &BIS2_combed,
|
|
const Eigen::Matrix<int, Eigen::Dynamic, 3> &MMatch,
|
|
const Eigen::Matrix<int, Eigen::Dynamic, 1> &Singular,
|
|
// const Eigen::Matrix<int, Eigen::Dynamic, 1> &SingularDegree,
|
|
const Eigen::Matrix<int, Eigen::Dynamic, 3> &Seams,
|
|
Eigen::PlainObjectBase<DerivedU> &UV,
|
|
Eigen::PlainObjectBase<DerivedF> &FUV,
|
|
double GradientSize = 30.0,
|
|
double Stiffness = 5.0,
|
|
bool DirectRound = false,
|
|
int iter = 5,
|
|
int localIter = 5, bool DoRound = true,bool SingularityRound=true,
|
|
std::vector<int> roundVertices = std::vector<int>(),
|
|
std::vector<std::vector<int> > hardFeatures = std::vector<std::vector<int> >());
|
|
};
|
|
};
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "miq.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_comiso_nrosy = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_COMISO_NROSY_H
|
|
#define IGL_COMISO_NROSY_H
|
|
|
|
#include <iostream>
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
#include <vector>
|
|
#include <igl/igl_inline.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace comiso
|
|
{
|
|
// Generate a N-RoSy field from a sparse set of constraints
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex coordinates
|
|
// F #F by 3 list of mesh faces (must be triangles)
|
|
// b #B by 1 list of constrained face indices
|
|
// bc #B by 3 list of representative vectors for the constrained
|
|
// faces
|
|
// b_soft #S by 1 b for soft constraints
|
|
// w_soft #S by 1 weight for the soft constraints (0-1)
|
|
// bc_soft #S by 3 bc for soft constraints
|
|
// N the degree of the N-RoSy vector field
|
|
// soft the strenght of the soft contraints w.r.t. smoothness
|
|
// (0 -> smoothness only, 1->constraints only)
|
|
// Outputs:
|
|
// R #F by 3 the representative vectors of the interpolated field
|
|
// S #V by 1 the singularity index for each vertex (0 = regular)
|
|
IGL_INLINE void nrosy(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::MatrixXd& bc,
|
|
const Eigen::VectorXi& b_soft,
|
|
const Eigen::VectorXd& w_soft,
|
|
const Eigen::MatrixXd& bc_soft,
|
|
const int N,
|
|
const double soft,
|
|
Eigen::MatrixXd& R,
|
|
Eigen::VectorXd& S
|
|
);
|
|
//wrapper for the case without soft constraints
|
|
IGL_INLINE void nrosy(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::VectorXi& b,
|
|
const Eigen::MatrixXd& bc,
|
|
const int N,
|
|
Eigen::MatrixXd& R,
|
|
Eigen::VectorXd& S
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "nrosy.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_ambient_occlusion = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_AMBIENT_OCCLUSION_H
|
|
#define IGL_EMBREE_AMBIENT_OCCLUSION_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// Forward define
|
|
class EmbreeIntersector;
|
|
// Compute ambient occlusion per given point
|
|
//
|
|
// Inputs:
|
|
// ei EmbreeIntersector containing (V,F)
|
|
// P #P by 3 list of origin points
|
|
// N #P by 3 list of origin normals
|
|
// Outputs:
|
|
// S #P list of ambient occlusion values between 1 (fully occluded) and
|
|
// 0 (not occluded)
|
|
//
|
|
template <
|
|
typename DerivedP,
|
|
typename DerivedN,
|
|
typename DerivedS >
|
|
IGL_INLINE void ambient_occlusion(
|
|
const EmbreeIntersector & ei,
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
const Eigen::PlainObjectBase<DerivedN> & N,
|
|
const int num_samples,
|
|
Eigen::PlainObjectBase<DerivedS> & S);
|
|
// Wrapper which builds new EmbreeIntersector for (V,F). That's expensive so
|
|
// avoid this if repeatedly calling.
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedP,
|
|
typename DerivedN,
|
|
typename DerivedS >
|
|
IGL_INLINE void ambient_occlusion(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
const Eigen::PlainObjectBase<DerivedN> & N,
|
|
const int num_samples,
|
|
Eigen::PlainObjectBase<DerivedS> & S);
|
|
}
|
|
};
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "ambient_occlusion.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_bone_heat = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_BONE_HEAT_H
|
|
#define IGL_EMBREE_BONE_HEAT_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// BONE_HEAT Compute skinning weights W given a surface mesh (V,F) and an
|
|
// internal skeleton (C,BE) according to "Automatic Rigging" [Baran and
|
|
// Popovic 2007].
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex positions
|
|
// F #F by 3 list of mesh corner indices into V
|
|
// C #C by 3 list of joint locations
|
|
// P #P list of point handle indices into C
|
|
// BE #BE by 2 list of bone edge indices into C
|
|
// CE #CE by 2 list of cage edge indices into **P**
|
|
// Outputs:
|
|
// W #V by #P+#BE matrix of weights.
|
|
// Returns true only on success.
|
|
//
|
|
IGL_INLINE bool bone_heat(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::VectorXi & P,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::MatrixXi & CE,
|
|
Eigen::MatrixXd & W);
|
|
}
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "bone_heat.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_bone_visible = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_BONE_VISIBLE_H
|
|
#define IGL_EMBREE_BONE_VISIBLE_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include "EmbreeIntersector.h"
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
//
|
|
// BONE_VISIBLE test whether vertices of mesh are "visible" to a given bone,
|
|
// where "visible" is defined as in [Baran & Popovic 07]. Instead of checking
|
|
// whether each point can see *any* of the bone, we just check if each point
|
|
// can see its own projection onto the bone segment. In other words, we project
|
|
// each vertex v onto the bone, projv. Then we check if there are any
|
|
// intersections between the line segment (projv-->v) and the mesh.
|
|
//
|
|
// [flag] = bone_visible(V,F,s,d);
|
|
//
|
|
// Input:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// s row vector of position of start end point of bone
|
|
// d row vector of position of dest end point of bone
|
|
// Output:
|
|
// flag #V by 1 list of bools (true) visible, (false) obstructed
|
|
//
|
|
// Note: This checks for hits along the segment which are facing in *any*
|
|
// direction from the ray.
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedSD,
|
|
typename Derivedflag>
|
|
IGL_INLINE void bone_visible(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const Eigen::PlainObjectBase<DerivedSD> & s,
|
|
const Eigen::PlainObjectBase<DerivedSD> & d,
|
|
Eigen::PlainObjectBase<Derivedflag> & flag);
|
|
// Inputs:
|
|
// ei EmbreeIntersector for mesh (V,F) should be double sided
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedSD,
|
|
typename Derivedflag>
|
|
IGL_INLINE void bone_visible(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
const EmbreeIntersector & ei,
|
|
const Eigen::PlainObjectBase<DerivedSD> & s,
|
|
const Eigen::PlainObjectBase<DerivedSD> & d,
|
|
Eigen::PlainObjectBase<Derivedflag> & flag);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "bone_visible.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_Embree_convenience = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_EMBREE_CONVENIENCE_H
|
|
#define IGL_EMBREE_EMBREE_CONVENIENCE_H
|
|
|
|
#undef interface
|
|
#undef near
|
|
#undef far
|
|
// Why are these in quotes? isn't that a bad idea?
|
|
#ifdef __GNUC__
|
|
// This is how it should be done
|
|
# if __GNUC__ >= 4
|
|
# if __GNUC_MINOR__ >= 6
|
|
# pragma GCC diagnostic push
|
|
# pragma GCC diagnostic ignored "-Weffc++"
|
|
# endif
|
|
# endif
|
|
// This is a hack
|
|
# pragma GCC system_header
|
|
#endif
|
|
#include <embree/include/embree.h>
|
|
#include <embree/include/intersector1.h>
|
|
#include <embree/common/ray.h>
|
|
#ifdef __GNUC__
|
|
# if __GNUC__ >= 4
|
|
# if __GNUC_MINOR__ >= 6
|
|
# pragma GCC diagnostic pop
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_EmbreeIntersector = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
// 2014 Christian Schüller <schuellchr@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
// igl function interface for Embree2.2
|
|
//
|
|
// Necessary changes to switch from previous Embree versions:
|
|
// * Use igl:Hit instead of embree:Hit (where id0 -> id)
|
|
// * For Embree2.2
|
|
// * Uncomment #define __USE_RAY_MASK__ in platform.h to enable masking
|
|
|
|
#ifndef IGL_EMBREE_EMBREE_INTERSECTOR_H
|
|
#define IGL_EMBREE_EMBREE_INTERSECTOR_H
|
|
|
|
#include "Hit.h"
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
|
|
#include <embree2/rtcore.h>
|
|
#include <embree2/rtcore_ray.h>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
class EmbreeIntersector
|
|
{
|
|
public:
|
|
// Initialize embree engine. This will be called on instance `init()`
|
|
// calls. If already inited then this function does nothing: it is harmless
|
|
// to call more than once.
|
|
static inline void global_init();
|
|
private:
|
|
// Deinitialize the embree engine.
|
|
static inline void global_deinit();
|
|
public:
|
|
typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
|
|
typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
|
|
public:
|
|
inline EmbreeIntersector();
|
|
private:
|
|
// Copying and assignment are not allowed.
|
|
inline EmbreeIntersector(const EmbreeIntersector & that);
|
|
inline EmbreeIntersector & operator=(const EmbreeIntersector &);
|
|
public:
|
|
virtual inline ~EmbreeIntersector();
|
|
|
|
// Initialize with a given mesh.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of Oriented triangles
|
|
// Side effects:
|
|
// The first time this is ever called the embree engine is initialized.
|
|
inline void init(
|
|
const PointMatrixType& V,
|
|
const FaceMatrixType& F);
|
|
|
|
// Initialize with a given mesh.
|
|
//
|
|
// Inputs:
|
|
// V vector of #V by 3 list of vertex positions for each geometry
|
|
// F vector of #F by 3 list of Oriented triangles for each geometry
|
|
// masks a 32 bit mask to identify active geometries.
|
|
// Side effects:
|
|
// The first time this is ever called the embree engine is initialized.
|
|
inline void init(
|
|
const std::vector<const PointMatrixType*>& V,
|
|
const std::vector<const FaceMatrixType*>& F,
|
|
const std::vector<int>& masks);
|
|
|
|
// Deinitialize embree datasctructures for current mesh. Also called on
|
|
// destruction: no need to call if you just want to init() once and
|
|
// destroy.
|
|
inline void deinit();
|
|
|
|
// Given a ray find the first hit
|
|
//
|
|
// Inputs:
|
|
// origin 3d origin point of ray
|
|
// direction 3d (not necessarily normalized) direction vector of ray
|
|
// tnear start of ray segment
|
|
// tfar end of ray segment
|
|
// masks a 32 bit mask to identify active geometries.
|
|
// Output:
|
|
// hit information about hit
|
|
// Returns true if and only if there was a hit
|
|
inline bool intersectRay(
|
|
const Eigen::RowVector3f& origin,
|
|
const Eigen::RowVector3f& direction,
|
|
Hit& hit,
|
|
float tnear = 0,
|
|
float tfar = std::numeric_limits<float>::infinity(),
|
|
int mask = 0xFFFFFFFF) const;
|
|
|
|
// Given a ray find the first hit
|
|
// This is a conservative hit test where multiple rays within a small radius
|
|
// will be tested and only the closesest hit is returned.
|
|
//
|
|
// Inputs:
|
|
// origin 3d origin point of ray
|
|
// direction 3d (not necessarily normalized) direction vector of ray
|
|
// tnear start of ray segment
|
|
// tfar end of ray segment
|
|
// masks a 32 bit mask to identify active geometries.
|
|
// geoId id of geometry mask (default std::numeric_limits<float>::infinity() if no: no masking)
|
|
// closestHit true for gets closest hit, false for furthest hit
|
|
// Output:
|
|
// hit information about hit
|
|
// Returns true if and only if there was a hit
|
|
inline bool intersectBeam(
|
|
const Eigen::RowVector3f& origin,
|
|
const Eigen::RowVector3f& direction,
|
|
Hit& hit,
|
|
float tnear = 0,
|
|
float tfar = std::numeric_limits<float>::infinity(),
|
|
int mask = 0xFFFFFFFF,
|
|
int geoId = -1,
|
|
bool closestHit = true,
|
|
unsigned int samples = 4) const;
|
|
|
|
// Given a ray find all hits in order
|
|
//
|
|
// Inputs:
|
|
// origin 3d origin point of ray
|
|
// direction 3d (not necessarily normalized) direction vector of ray
|
|
// tnear start of ray segment
|
|
// tfar end of ray segment
|
|
// masks a 32 bit mask to identify active geometries.
|
|
// Output:
|
|
// hit information about hit
|
|
// num_rays number of rays shot (at least one)
|
|
// Returns true if and only if there was a hit
|
|
inline bool intersectRay(
|
|
const Eigen::RowVector3f& origin,
|
|
const Eigen::RowVector3f& direction,
|
|
std::vector<Hit > &hits,
|
|
int& num_rays,
|
|
float tnear = 0,
|
|
float tfar = std::numeric_limits<float>::infinity(),
|
|
int mask = 0xFFFFFFFF) const;
|
|
|
|
// Given a ray find the first hit
|
|
//
|
|
// Inputs:
|
|
// a 3d first end point of segment
|
|
// ab 3d vector from a to other endpoint b
|
|
// Output:
|
|
// hit information about hit
|
|
// Returns true if and only if there was a hit
|
|
inline bool intersectSegment(
|
|
const Eigen::RowVector3f& a,
|
|
const Eigen::RowVector3f& ab,
|
|
Hit &hit,
|
|
int mask = 0xFFFFFFFF) const;
|
|
|
|
private:
|
|
|
|
struct Vertex {float x,y,z,a;};
|
|
struct Triangle {int v0, v1, v2;};
|
|
|
|
RTCScene scene;
|
|
unsigned geomID;
|
|
Vertex* vertices;
|
|
Triangle* triangles;
|
|
bool initialized;
|
|
|
|
inline void createRay(
|
|
RTCRay& ray,
|
|
const Eigen::RowVector3f& origin,
|
|
const Eigen::RowVector3f& direction,
|
|
float tnear,
|
|
float tfar,
|
|
int mask) const;
|
|
};
|
|
}
|
|
}
|
|
|
|
// Implementation
|
|
#include <igl/EPS.h>
|
|
// This unfortunately cannot be a static field of EmbreeIntersector because it
|
|
// would depend on the template and then we might end up with initializing
|
|
// embree twice. If only there was a way to ask embree if it's already
|
|
// initialized...
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// Keeps track of whether the **Global** Embree intersector has been
|
|
// initialized. This should never been done at the global scope.
|
|
static bool EmbreeIntersector_inited = false;
|
|
}
|
|
}
|
|
|
|
inline void igl::embree::EmbreeIntersector::global_init()
|
|
{
|
|
if(!EmbreeIntersector_inited)
|
|
{
|
|
rtcInit();
|
|
if(rtcGetError() != RTC_NO_ERROR)
|
|
std::cerr << "Embree: An error occured while initialiting embree core!" << std::endl;
|
|
#ifdef IGL_VERBOSE
|
|
else
|
|
std::cerr << "Embree: core initialized." << std::endl;
|
|
#endif
|
|
EmbreeIntersector_inited = true;
|
|
}
|
|
}
|
|
|
|
inline void igl::embree::EmbreeIntersector::global_deinit()
|
|
{
|
|
EmbreeIntersector_inited = false;
|
|
rtcExit();
|
|
}
|
|
|
|
inline igl::embree::EmbreeIntersector::EmbreeIntersector()
|
|
:
|
|
//scene(NULL),
|
|
geomID(0),
|
|
triangles(NULL),
|
|
vertices(NULL),
|
|
initialized(false)
|
|
{
|
|
}
|
|
|
|
inline igl::embree::EmbreeIntersector::EmbreeIntersector(
|
|
const EmbreeIntersector &)
|
|
:// To make -Weffc++ happy
|
|
//scene(NULL),
|
|
geomID(0),
|
|
triangles(NULL),
|
|
vertices(NULL),
|
|
initialized(false)
|
|
{
|
|
assert(false && "Embree: Copying EmbreeIntersector is not allowed");
|
|
}
|
|
|
|
inline igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
|
|
const EmbreeIntersector &)
|
|
{
|
|
assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
|
|
return *this;
|
|
}
|
|
|
|
|
|
inline void igl::embree::EmbreeIntersector::init(
|
|
const PointMatrixType& V,
|
|
const FaceMatrixType& F)
|
|
{
|
|
std::vector<const PointMatrixType*> Vtemp;
|
|
std::vector<const FaceMatrixType*> Ftemp;
|
|
std::vector<int> masks;
|
|
Vtemp.push_back(&V);
|
|
Ftemp.push_back(&F);
|
|
masks.push_back(0xFFFFFFFF);
|
|
init(Vtemp,Ftemp,masks);
|
|
}
|
|
|
|
inline void igl::embree::EmbreeIntersector::init(
|
|
const std::vector<const PointMatrixType*>& V,
|
|
const std::vector<const FaceMatrixType*>& F,
|
|
const std::vector<int>& masks)
|
|
{
|
|
|
|
if(initialized)
|
|
deinit();
|
|
|
|
using namespace std;
|
|
global_init();
|
|
|
|
if(V.size() == 0 || F.size() == 0)
|
|
{
|
|
std::cerr << "Embree: No geometry specified!";
|
|
return;
|
|
}
|
|
|
|
// create a scene
|
|
scene = rtcNewScene(RTC_SCENE_ROBUST | RTC_SCENE_HIGH_QUALITY,RTC_INTERSECT1);
|
|
|
|
for(int g=0;g<(int)V.size();g++)
|
|
{
|
|
// create triangle mesh geometry in that scene
|
|
geomID = rtcNewTriangleMesh(scene,RTC_GEOMETRY_STATIC,F[g]->rows(),V[g]->rows(),1);
|
|
|
|
// fill vertex buffer
|
|
vertices = (Vertex*)rtcMapBuffer(scene,geomID,RTC_VERTEX_BUFFER);
|
|
for(int i=0;i<(int)V[g]->rows();i++)
|
|
{
|
|
vertices[i].x = (float)V[g]->coeff(i,0);
|
|
vertices[i].y = (float)V[g]->coeff(i,1);
|
|
vertices[i].z = (float)V[g]->coeff(i,2);
|
|
}
|
|
rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER);
|
|
|
|
// fill triangle buffer
|
|
triangles = (Triangle*) rtcMapBuffer(scene,geomID,RTC_INDEX_BUFFER);
|
|
for(int i=0;i<(int)F[g]->rows();i++)
|
|
{
|
|
triangles[i].v0 = (int)F[g]->coeff(i,0);
|
|
triangles[i].v1 = (int)F[g]->coeff(i,1);
|
|
triangles[i].v2 = (int)F[g]->coeff(i,2);
|
|
}
|
|
rtcUnmapBuffer(scene,geomID,RTC_INDEX_BUFFER);
|
|
|
|
rtcSetMask(scene,geomID,masks[g]);
|
|
}
|
|
|
|
rtcCommit(scene);
|
|
|
|
if(rtcGetError() != RTC_NO_ERROR)
|
|
std::cerr << "Embree: An error occured while initializing the provided geometry!" << endl;
|
|
#ifdef IGL_VERBOSE
|
|
else
|
|
std::cerr << "Embree: geometry added." << endl;
|
|
#endif
|
|
|
|
initialized = true;
|
|
}
|
|
|
|
igl::embree::EmbreeIntersector
|
|
::~EmbreeIntersector()
|
|
{
|
|
if(initialized)
|
|
deinit();
|
|
}
|
|
|
|
void igl::embree::EmbreeIntersector::deinit()
|
|
{
|
|
if(scene)
|
|
{
|
|
rtcDeleteScene(scene);
|
|
|
|
if(rtcGetError() != RTC_NO_ERROR)
|
|
{
|
|
std::cerr << "Embree: An error occured while resetting!" << std::endl;
|
|
}
|
|
#ifdef IGL_VERBOSE
|
|
else
|
|
{
|
|
std::cerr << "Embree: geometry removed." << std::endl;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
inline bool igl::embree::EmbreeIntersector::intersectRay(
|
|
const Eigen::RowVector3f& origin,
|
|
const Eigen::RowVector3f& direction,
|
|
Hit& hit,
|
|
float tnear,
|
|
float tfar,
|
|
int mask) const
|
|
{
|
|
RTCRay ray;
|
|
createRay(ray, origin,direction,tnear,tfar,mask);
|
|
|
|
// shot ray
|
|
rtcIntersect(scene,ray);
|
|
#ifdef IGL_VERBOSE
|
|
if(rtcGetError() != RTC_NO_ERROR)
|
|
std::cerr << "Embree: An error occured while resetting!" << std::endl;
|
|
#endif
|
|
|
|
if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
|
|
{
|
|
hit.id = ray.primID;
|
|
hit.gid = ray.geomID;
|
|
hit.u = ray.u;
|
|
hit.v = ray.v;
|
|
hit.t = ray.tfar;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
inline bool igl::embree::EmbreeIntersector::intersectBeam(
|
|
const Eigen::RowVector3f& origin,
|
|
const Eigen::RowVector3f& direction,
|
|
Hit& hit,
|
|
float tnear,
|
|
float tfar,
|
|
int mask,
|
|
int geoId,
|
|
bool closestHit,
|
|
unsigned int samples) const
|
|
{
|
|
bool hasHit = false;
|
|
Hit bestHit;
|
|
|
|
if(closestHit)
|
|
bestHit.t = std::numeric_limits<float>::max();
|
|
else
|
|
bestHit.t = 0;
|
|
|
|
if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
|
|
{
|
|
bestHit = hit;
|
|
}
|
|
|
|
// sample points around actual ray (conservative hitcheck)
|
|
const float eps= 1e-5;
|
|
|
|
Eigen::RowVector3f up(0,1,0);
|
|
Eigen::RowVector3f offset = direction.cross(up).normalized();
|
|
|
|
Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
|
|
|
|
for(int r=0;r<samples;r++)
|
|
{
|
|
if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
|
|
((closestHit && (hit.t < bestHit.t)) ||
|
|
(!closestHit && (hit.t > bestHit.t))) &&
|
|
(hit.gid == geoId || geoId == -1))
|
|
{
|
|
bestHit = hit;
|
|
hasHit = true;
|
|
}
|
|
offset = rot*offset.transpose();
|
|
}
|
|
|
|
hit = bestHit;
|
|
return hasHit;
|
|
}
|
|
|
|
inline bool
|
|
igl::embree::EmbreeIntersector
|
|
::intersectRay(
|
|
const Eigen::RowVector3f& origin,
|
|
const Eigen::RowVector3f& direction,
|
|
std::vector<Hit > &hits,
|
|
int& num_rays,
|
|
float tnear,
|
|
float tfar,
|
|
int mask) const
|
|
{
|
|
using namespace std;
|
|
num_rays = 0;
|
|
hits.clear();
|
|
int last_id0 = -1;
|
|
double self_hits = 0;
|
|
// This epsilon is directly correleated to the number of missed hits, smaller
|
|
// means more accurate and slower
|
|
//const double eps = DOUBLE_EPS;
|
|
const double eps = FLOAT_EPS;
|
|
double min_t = tnear;
|
|
bool large_hits_warned = false;
|
|
RTCRay ray;
|
|
createRay(ray,origin,direction,tnear,tfar,mask);
|
|
|
|
while(true)
|
|
{
|
|
ray.tnear = min_t;
|
|
ray.tfar = tfar;
|
|
ray.geomID = RTC_INVALID_GEOMETRY_ID;
|
|
ray.primID = RTC_INVALID_GEOMETRY_ID;
|
|
ray.instID = RTC_INVALID_GEOMETRY_ID;
|
|
num_rays++;
|
|
rtcIntersect(scene,ray);
|
|
if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
|
|
{
|
|
// Hit self again, progressively advance
|
|
if(ray.primID == last_id0 || ray.tfar <= min_t)
|
|
{
|
|
// push min_t a bit more
|
|
//double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
|
|
double t_push = pow(2.0,self_hits)*eps;
|
|
#ifdef IGL_VERBOSE
|
|
std::cerr<<" t_push: "<<t_push<<endl;
|
|
#endif
|
|
//o = o+t_push*d;
|
|
min_t += t_push;
|
|
self_hits++;
|
|
}
|
|
else
|
|
{
|
|
Hit hit;
|
|
hit.id = ray.primID;
|
|
hit.gid = ray.geomID;
|
|
hit.u = ray.u;
|
|
hit.v = ray.v;
|
|
hit.t = ray.tfar;
|
|
hits.push_back(hit);
|
|
#ifdef IGL_VERBOSE
|
|
std::cerr<<" t: "<<hit.t<<endl;
|
|
#endif
|
|
// Instead of moving origin, just change min_t. That way calculations
|
|
// all use exactly same origin values
|
|
min_t = ray.tfar;
|
|
|
|
// reset t_scale
|
|
self_hits = 0;
|
|
}
|
|
last_id0 = ray.primID;
|
|
}
|
|
else
|
|
break; // no more hits
|
|
|
|
if(hits.size()>1000 && !large_hits_warned)
|
|
{
|
|
std::cout<<"Warning: Large number of hits..."<<endl;
|
|
std::cout<<"[ ";
|
|
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
|
|
{
|
|
std::cout<<(hit->id+1)<<" ";
|
|
}
|
|
|
|
std::cout.precision(std::numeric_limits< double >::digits10);
|
|
std::cout<<"[ ";
|
|
|
|
for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
|
|
{
|
|
std::cout<<(hit->t)<<endl;;
|
|
}
|
|
|
|
std::cout<<"]"<<endl;
|
|
large_hits_warned = true;
|
|
|
|
return hits.empty();
|
|
}
|
|
}
|
|
|
|
return hits.empty();
|
|
}
|
|
|
|
inline bool
|
|
igl::embree::EmbreeIntersector
|
|
::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
|
|
{
|
|
RTCRay ray;
|
|
createRay(ray,a,ab,0,1.0,mask);
|
|
|
|
rtcIntersect(scene,ray);
|
|
|
|
if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
|
|
{
|
|
hit.id = ray.primID;
|
|
hit.gid = ray.geomID;
|
|
hit.u = ray.u;
|
|
hit.v = ray.v;
|
|
hit.t = ray.tfar;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
inline void
|
|
igl::embree::EmbreeIntersector
|
|
::createRay(RTCRay& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
|
|
{
|
|
ray.org[0] = origin[0];
|
|
ray.org[1] = origin[1];
|
|
ray.org[2] = origin[2];
|
|
ray.dir[0] = direction[0];
|
|
ray.dir[1] = direction[1];
|
|
ray.dir[2] = direction[2];
|
|
ray.tnear = tnear;
|
|
ray.tfar = tfar;
|
|
ray.geomID = RTC_INVALID_GEOMETRY_ID;
|
|
ray.primID = RTC_INVALID_GEOMETRY_ID;
|
|
ray.instID = RTC_INVALID_GEOMETRY_ID;
|
|
ray.mask = mask;
|
|
ray.time = 0.0f;
|
|
}
|
|
|
|
#endif //EMBREE_INTERSECTOR_H
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_Hit = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
// 2014 Christian Schüller <schuellchr@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_HIT_H
|
|
#define IGL_EMBREE_HIT_H
|
|
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// Reimplementation of the embree::Hit struct from embree1.0
|
|
struct Hit
|
|
{
|
|
int id; // primitive id
|
|
int gid; // geometry id
|
|
float u,v; // barycentric coordinates
|
|
float t; // distance = direction*t to intersection
|
|
};
|
|
}
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_line_mesh_intersection = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_LINE_MESH_INTERSECTION_H
|
|
#define IGL_EMBREE_LINE_MESH_INTERSECTION_H
|
|
#include <igl/igl_inline.h>
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// Project the point cloud V_source onto the triangle mesh
|
|
// V_target,F_target.
|
|
// A ray is casted for every vertex in the direction specified by
|
|
// N_source and its opposite.
|
|
//
|
|
// Input:
|
|
// V_source: #Vx3 Vertices of the source mesh
|
|
// N_source: #Vx3 Normals of the point cloud
|
|
// V_target: #V2x3 Vertices of the target mesh
|
|
// F_target: #F2x3 Faces of the target mesh
|
|
//
|
|
// Output:
|
|
// #Vx3 matrix of baricentric coordinate. Each row corresponds to
|
|
// a vertex of the projected mesh and it has the following format:
|
|
// id b1 b2. id is the id of a face of the source mesh. b1 and b2 are
|
|
// the barycentric coordinates wrt the first two edges of the triangle
|
|
// To convert to standard global coordinates, see barycentric_to_global.h
|
|
template <typename ScalarMatrix, typename IndexMatrix>
|
|
IGL_INLINE ScalarMatrix line_mesh_intersection
|
|
(
|
|
const ScalarMatrix & V_source,
|
|
const ScalarMatrix & N_source,
|
|
const ScalarMatrix & V_target,
|
|
const IndexMatrix & F_target
|
|
);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "line_mesh_intersection.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_reorient_facets_raycast = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_REORIENT_FACETS_RAYCAST_H
|
|
#define IGL_EMBREE_REORIENT_FACETS_RAYCAST_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// Orient each component (identified by C) of a mesh (V,F) using ambient
|
|
// occlusion such that the front side is less occluded than back side
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// rays_total Total number of rays that will be shot
|
|
// rays_minimum Minimum number of rays that each patch should receive
|
|
// facet_wise Decision made for each face independently, no use of patches
|
|
// (i.e., each face is treated as a patch)
|
|
// use_parity Use parity mode
|
|
// is_verbose Verbose output to cout
|
|
// Outputs:
|
|
// I #F list of whether face has been flipped
|
|
// C #F list of patch ID (output of bfs_orient > manifold patches)
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedI,
|
|
typename DerivedC>
|
|
IGL_INLINE void reorient_facets_raycast(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
int rays_total,
|
|
int rays_minimum,
|
|
bool facet_wise,
|
|
bool use_parity,
|
|
bool is_verbose,
|
|
Eigen::PlainObjectBase<DerivedI> & I,
|
|
Eigen::PlainObjectBase<DerivedC> & C);
|
|
// Outputs:
|
|
// FF #F by 3 list of reoriented faces
|
|
// Defaults:
|
|
// rays_total = F.rows()*100;
|
|
// rays_minimum = 10;
|
|
// facet_wise = false;
|
|
// use_parity = false;
|
|
// is_verbose = false;
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedFF,
|
|
typename DerivedI>
|
|
IGL_INLINE void reorient_facets_raycast(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedI> & I);
|
|
}
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "reorient_facets_raycast.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_unproject_in_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_UNPROJECT_IN_MESH
|
|
#define IGL_EMBREE_UNPROJECT_IN_MESH
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
|
|
#include <vector>
|
|
#include "Hit.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// Forward define
|
|
class EmbreeIntersector;
|
|
|
|
// Unproject a screen location (using current opengl viewport, projection, and
|
|
// model view) to a 3D position _inside_ a given mesh. If the ray through the
|
|
// given screen location (x,y) _hits_ the mesh more than twice then the 3D
|
|
// midpoint between the first two hits is return. If it hits once, then that
|
|
// point is return. If it does not hit the mesh then obj is not set.
|
|
//
|
|
//
|
|
// Inputs:
|
|
// pos screen space coordinates
|
|
// model model matrix
|
|
// proj projection matrix
|
|
// viewport vieweport vector
|
|
// ei EmbreeIntersector containing (V,F)
|
|
// Outputs:
|
|
// obj 3d unprojected mouse point in mesh
|
|
// hits vector of embree hits
|
|
// Returns number of hits
|
|
//
|
|
// Note: Previous prototype did not require model, proj, and viewport. This
|
|
// has been removed. Instead replace with:
|
|
//
|
|
// Eigen::Matrix4f model,proj;
|
|
// Eigen::Vector4f viewport;
|
|
// igl::opengl2::model_proj_viewport(model,proj,viewport);
|
|
// igl::embree::unproject_in_mesh(Vector2f(x,y),model,proj,viewport,ei,obj,hits);
|
|
//
|
|
template < typename Derivedobj>
|
|
IGL_INLINE int unproject_in_mesh(
|
|
const Eigen::Vector2f& pos,
|
|
const Eigen::Matrix4f& model,
|
|
const Eigen::Matrix4f& proj,
|
|
const Eigen::Vector4f& viewport,
|
|
const EmbreeIntersector & ei,
|
|
Eigen::PlainObjectBase<Derivedobj> & obj,
|
|
std::vector<igl::embree::Hit > & hits);
|
|
template < typename Derivedobj>
|
|
IGL_INLINE int unproject_in_mesh(
|
|
const Eigen::Vector2f& pos,
|
|
const Eigen::Matrix4f& model,
|
|
const Eigen::Matrix4f& proj,
|
|
const Eigen::Vector4f& viewport,
|
|
const EmbreeIntersector & ei,
|
|
Eigen::PlainObjectBase<Derivedobj> & obj);
|
|
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unproject_in_mesh.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_embree_unproject_onto_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_EMBREE_UNPROJECT_ONTO_MESH_H
|
|
#define IGL_EMBREE_UNPROJECT_ONTO_MESH_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
|
|
#include <vector>
|
|
#include "Hit.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace embree
|
|
{
|
|
// Forward define
|
|
class EmbreeIntersector;
|
|
// Unproject a screen location (using the given model, proj and viewport) to find
|
|
// the first hit on a mesh.
|
|
//
|
|
// Inputs:
|
|
// pos screen space coordinates
|
|
// F #F by 3 face matrix
|
|
// model model matrix
|
|
// proj projection matrix
|
|
// viewport vieweport vector
|
|
// ei EmbreeIntersector containing (V,F)
|
|
// Outputs:
|
|
// fid id of the first face hit
|
|
// bc barycentric coordinates of hit
|
|
// Returns true if there is a hit
|
|
IGL_INLINE bool unproject_onto_mesh(
|
|
const Eigen::Vector2f& pos,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::Matrix4f& model,
|
|
const Eigen::Matrix4f& proj,
|
|
const Eigen::Vector4f& viewport,
|
|
const EmbreeIntersector & ei,
|
|
int& fid,
|
|
Eigen::Vector3f& bc);
|
|
|
|
// Unproject a screen location (using the given model, proj and viewport) to find
|
|
// the first face on the mesh and the closest vertex
|
|
//
|
|
// Inputs:
|
|
// pos screen space coordinates
|
|
// F #F by 3 face matrix
|
|
// model model matrix
|
|
// proj projection matrix
|
|
// viewport vieweport vector
|
|
// ei EmbreeIntersector containing (V,F)
|
|
// Outputs:
|
|
// fid id of the first face hit
|
|
// vid vertex id of the closest vertex hit
|
|
// Returns true if there is a hit
|
|
IGL_INLINE bool unproject_onto_mesh(
|
|
const Eigen::Vector2f& pos,
|
|
const Eigen::MatrixXi& F,
|
|
const Eigen::Matrix4f& model,
|
|
const Eigen::Matrix4f& proj,
|
|
const Eigen::Vector4f& viewport,
|
|
const EmbreeIntersector & ei,
|
|
int& fid,
|
|
int& vid);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unproject_onto_mesh.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_lim_lim = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_LIM_LIM_H
|
|
#define IGL_LIM_LIM_H
|
|
#include <igl/igl_inline.h>
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
namespace lim
|
|
{
|
|
// Known issues: energy type should be a readable enum rather than magic
|
|
// ints.
|
|
//
|
|
// Computes a locally injective mapping of a triangle or tet-mesh based on
|
|
// a deformation energy subject to some provided linear positional
|
|
// constraints Cv-d.
|
|
//
|
|
// Inputs:
|
|
// vertices vx3 matrix containing vertex position of the mesh
|
|
// initialVertices vx3 matrix containing vertex position of initial
|
|
// rest pose mesh
|
|
// elements exd matrix containing vertex indices of all elements
|
|
// borderVertices (only needed for 2D LSCM) vector containing indices
|
|
// of border vertices
|
|
// gradients (only needed for 2D Poisson) vector containing
|
|
// partial derivatives of target element gradients
|
|
// (structure is: [xx_0, xy_0, xx_1, xy_1, ..., xx_v,
|
|
// xy_v, yx_0, yy_0, yx_1, yy_1, ..., yx_v, yy_v]')
|
|
// constraintMatrix C: (c)x(v*(d-1)) sparse linear positional constraint
|
|
// matrix. X an Y-coordinates are alternatingly stacked
|
|
// per row (structure for triangles: [x_1, y_1, x_2,
|
|
// y_2, ..., x_v,y_v])
|
|
// constraintTargets d: c vector target positions
|
|
// energyType type of used energy:
|
|
// 0=Dirichlet,1=Laplacian,2=Green,3=ARAP,4=LSCM
|
|
// tolerance max squared positional constraints error
|
|
// maxIteration max number of iterations
|
|
// findLocalMinima iterating until a local minima is found. If not
|
|
// enabled only tolerance must be fulfilled.
|
|
// enableOutput (optional) enables the output (#iteration / hessian correction / step size / positional constraints / barrier constraints / deformation energy) (default : true)
|
|
// enableBarriers (optional) enables the non-flip constraints (default = true)
|
|
// enableAlphaUpdate (optional) enables dynamic alpha weight adjustment (default = true)
|
|
// beta (optional) steepness factor of barrier slopes (default: ARAP/LSCM = 0.01, Green = 1)
|
|
// eps (optional) smallest valid triangle area (default: 1e-5 * smallest triangle)
|
|
//
|
|
// where:
|
|
// v : # vertices
|
|
// c : # linear constraints
|
|
// e : # elements of mesh
|
|
// d : # vertices per element (triangle = 3, tet = 4)
|
|
//--------------------------------------------------------------------------
|
|
// Output:
|
|
// vertices vx3 matrix containing resulting vertex position of the
|
|
// mesh
|
|
//--------------------------------------------------------------------------
|
|
// Return values:
|
|
// 1 : Successful optimization with fulfilled tolerance
|
|
// -1 : Max iteration reached before tolerance was fulfilled
|
|
// -2 : not feasible -> has inverted elements (may want to decrease eps?)
|
|
|
|
int lim(
|
|
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
|
|
const Eigen::SparseMatrix<double>& constraintMatrix,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
|
|
int energyType,
|
|
double tolerance,
|
|
int maxIteration,
|
|
bool findLocalMinima);
|
|
|
|
int lim(
|
|
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
|
|
const Eigen::SparseMatrix<double>& constraintMatrix,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
|
|
int energyType,
|
|
double tolerance,
|
|
int maxIteration,
|
|
bool findLocalMinima,
|
|
bool enableOuput,
|
|
bool enableBarriers,
|
|
bool enableAlphaUpdate,
|
|
double beta,
|
|
double eps);
|
|
|
|
int lim(
|
|
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
|
|
const std::vector<int>& borderVertices,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
|
|
const Eigen::SparseMatrix<double>& constraintMatrix,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
|
|
int energyType,
|
|
double tolerance,
|
|
int maxIteration,
|
|
bool findLocalMinima);
|
|
|
|
int lim(
|
|
Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
|
|
const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
|
|
const std::vector<int>& borderVertices,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
|
|
const Eigen::SparseMatrix<double>& constraintMatrix,
|
|
const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
|
|
int energyType,
|
|
double tolerance,
|
|
int maxIteration,
|
|
bool findLocalMinima,
|
|
bool enableOuput,
|
|
bool enableBarriers,
|
|
bool enableAlphaUpdate,
|
|
double beta,
|
|
double eps);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "lim.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matlab_matlabinterface = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATLAB_MATLAB_INTERFACE_H
|
|
#define IGL_MATLAB_MATLAB_INTERFACE_H
|
|
#include "../igl_inline.h"
|
|
// WARNING: These functions require matlab installed
|
|
// Additional header folder required:
|
|
// /Applications/MATLAB_R2011a.app/extern/include
|
|
// Additional binary lib to be linked with:
|
|
// /Applications/MATLAB_R2011a.app/bin/maci64/libeng.dylib
|
|
// /Applications/MATLAB_R2011a.app/bin/maci64/libmx.dylib
|
|
|
|
// MAC ONLY:
|
|
// Add to the environment variables:
|
|
// DYLD_LIBRARY_PATH = /Applications/MATLAB_R2011a.app/bin/maci64/
|
|
// PATH = /opt/local/bin:/opt/local/sbin:/Applications/MATLAB_R2011a.app/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
#include <string>
|
|
|
|
#include <complex>
|
|
#include <cassert>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <engine.h> // Matlab engine header
|
|
|
|
namespace igl
|
|
{
|
|
namespace matlab
|
|
{
|
|
// Init the MATLAB engine
|
|
// (no need to call it directly since it is automatically invoked by any other command)
|
|
IGL_INLINE void mlinit(Engine** engine);
|
|
|
|
// Closes the MATLAB engine
|
|
IGL_INLINE void mlclose(Engine** engine);
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXd& M);
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXf& M);
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXi& M);
|
|
|
|
// Send a matrix to MATLAB
|
|
IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M);
|
|
|
|
// Receive a matrix from MATLAB
|
|
IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXd& M);
|
|
|
|
// Receive a matrix from MATLAB
|
|
IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXf& M);
|
|
|
|
// Receive a matrix from MATLAB
|
|
IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXi& M);
|
|
|
|
// Receive a matrix from MATLAB
|
|
IGL_INLINE void mlgetmatrix(Engine** mlengine, std::string name, Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M);
|
|
|
|
// Send a single scalar to MATLAB
|
|
IGL_INLINE void mlsetscalar(Engine** engine, std::string name, double s);
|
|
|
|
// Receive a single scalar from MATLAB
|
|
IGL_INLINE double mlgetscalar(Engine** engine, std::string name);
|
|
|
|
// Execute arbitrary MATLAB code and return the MATLAB output
|
|
IGL_INLINE std::string mleval(Engine** engine, std::string code);
|
|
|
|
// Send a sparse matrix to MATLAB
|
|
IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::SparseMatrix<double>& M);
|
|
|
|
}
|
|
}
|
|
|
|
// Be sure that this is not compiled into libigl.a
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "matlabinterface.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matlab_MatlabWorkspace = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATLAB_MATLAB_WORKSPACE_H
|
|
#define IGL_MATLAB_MATLAB_WORKSPACE_H
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
#include <mat.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
namespace matlab
|
|
{
|
|
// It would be really great to replicate this for a simple XML-based
|
|
// workspace.
|
|
//
|
|
// Class which contains data of a matlab workspace which can be written to a
|
|
// .mat file and loaded from matlab
|
|
//
|
|
// This depends on matlab at compile time (though it shouldn't necessarily
|
|
// have to) but it does not depend on running the matlab engine at run-time.
|
|
//
|
|
// Known bugs: Treats all matrices as doubles (this may actually be desired
|
|
// for some "index" matrices since matlab's sparse command takes doubles
|
|
// rather than int class matrices). It is of course not desired when dealing
|
|
// with logicals or uint's for images.
|
|
class MatlabWorkspace
|
|
{
|
|
private:
|
|
// KNOWN BUG: Why not use a map? Any reason to allow duplicate names?
|
|
//
|
|
// List of names
|
|
std::vector<std::string> names;
|
|
// List of data pointers
|
|
std::vector<mxArray*> data;
|
|
public:
|
|
MatlabWorkspace();
|
|
~MatlabWorkspace();
|
|
// Clear names and data of variables in workspace
|
|
inline void clear();
|
|
// Save current list of variables
|
|
//
|
|
// Inputs:
|
|
// path path to .mat file
|
|
// Returns true on success, false on failure
|
|
inline bool write(const std::string & path) const;
|
|
// Load list of variables from .mat file
|
|
//
|
|
// Inputs:
|
|
// path path to .mat file
|
|
// Returns true on success, false on failure
|
|
inline bool read(const std::string & path);
|
|
// Assign data to a variable name in the workspace
|
|
//
|
|
// Template:
|
|
// DerivedM eigen matrix (e.g. MatrixXd)
|
|
// Inputs:
|
|
// M data (usually a matrix)
|
|
// name variable name to save into work space
|
|
// Returns true on success, false on failure
|
|
//
|
|
// Known Bugs: Assumes Eigen is using column major ordering
|
|
template <typename DerivedM>
|
|
inline MatlabWorkspace& save(
|
|
const Eigen::PlainObjectBase<DerivedM>& M,
|
|
const std::string & name);
|
|
// Template:
|
|
// MT sparse matrix type (e.g. double)
|
|
template <typename MT>
|
|
inline MatlabWorkspace& save(
|
|
const Eigen::SparseMatrix<MT>& M,
|
|
const std::string & name);
|
|
// Templates:
|
|
// ScalarM scalar type, e.g. double
|
|
template <typename ScalarM>
|
|
inline MatlabWorkspace& save(
|
|
const std::vector<std::vector<ScalarM> > & vM,
|
|
const std::string & name);
|
|
// Templates:
|
|
// ScalarV scalar type, e.g. double
|
|
template <typename ScalarV>
|
|
inline MatlabWorkspace& save(
|
|
const std::vector<ScalarV> & vV,
|
|
const std::string & name);
|
|
// NOTE: Eigen stores quaternions coefficients as (i,j,k,1), but most of
|
|
// our matlab code stores them as (1,i,j,k) This takes a quaternion and
|
|
// saves it as a (1,i,j,k) row vector
|
|
//
|
|
// Templates:
|
|
// Q quaternion type
|
|
template <typename Q>
|
|
inline MatlabWorkspace& save(
|
|
const Eigen::Quaternion<Q> & q,
|
|
const std::string & name);
|
|
inline MatlabWorkspace& save(
|
|
const double d,
|
|
const std::string & name);
|
|
// Same as save() but adds 1 to each element, useful for saving "index"
|
|
// matrices like lists of faces or elements
|
|
template <typename DerivedM>
|
|
inline MatlabWorkspace& save_index(
|
|
const Eigen::PlainObjectBase<DerivedM>& M,
|
|
const std::string & name);
|
|
template <typename ScalarM>
|
|
inline MatlabWorkspace& save_index(
|
|
const std::vector<std::vector<ScalarM> > & vM,
|
|
const std::string & name);
|
|
template <typename ScalarV>
|
|
inline MatlabWorkspace& save_index(
|
|
const std::vector<ScalarV> & vV,
|
|
const std::string & name);
|
|
// Find a certain matrix by name.
|
|
//
|
|
// KNOWN BUG: Outputs the first found (not necessarily unique lists).
|
|
//
|
|
// Template:
|
|
// DerivedM eigen matrix (e.g. MatrixXd)
|
|
// Inputs:
|
|
// name exact name of matrix as string
|
|
// Outputs:
|
|
// M matrix
|
|
// Returns true only if found.
|
|
template <typename DerivedM>
|
|
inline bool find(
|
|
const std::string & name,
|
|
Eigen::PlainObjectBase<DerivedM>& M);
|
|
template <typename MT>
|
|
inline bool find(
|
|
const std::string & name,
|
|
Eigen::SparseMatrix<MT>& M);
|
|
inline bool find(
|
|
const std::string & name,
|
|
double & d);
|
|
inline bool find(
|
|
const std::string & name,
|
|
int & v);
|
|
// Subtracts 1 from all entries
|
|
template <typename DerivedM>
|
|
inline bool find_index(
|
|
const std::string & name,
|
|
Eigen::PlainObjectBase<DerivedM>& M);
|
|
};
|
|
}
|
|
}
|
|
|
|
// Implementation
|
|
|
|
// Be sure that this is not compiled into libigl.a
|
|
// http://stackoverflow.com/a/3318993/148668
|
|
|
|
// IGL
|
|
#include "igl/list_to_matrix.h"
|
|
|
|
// MATLAB
|
|
#include "mat.h"
|
|
|
|
// STL
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
inline igl::matlab::MatlabWorkspace::MatlabWorkspace():
|
|
names(),
|
|
data()
|
|
{
|
|
}
|
|
|
|
inline igl::matlab::MatlabWorkspace::~MatlabWorkspace()
|
|
{
|
|
// clean up data
|
|
clear();
|
|
}
|
|
|
|
inline void igl::matlab::MatlabWorkspace::clear()
|
|
{
|
|
for_each(data.begin(),data.end(),&mxDestroyArray);
|
|
data.clear();
|
|
names.clear();
|
|
}
|
|
|
|
inline bool igl::matlab::MatlabWorkspace::write(const std::string & path) const
|
|
{
|
|
using namespace std;
|
|
MATFile * mat_file = matOpen(path.c_str(), "w");
|
|
if(mat_file == NULL)
|
|
{
|
|
fprintf(stderr,"Error opening file %s\n",path.c_str());
|
|
return false;
|
|
}
|
|
assert(names.size() == data.size());
|
|
// loop over names and data
|
|
for(int i = 0;i < (int)names.size(); i++)
|
|
{
|
|
// Put variable as LOCAL variable
|
|
int status = matPutVariable(mat_file,names[i].c_str(), data[i]);
|
|
if(status != 0)
|
|
{
|
|
cerr<<"^MatlabWorkspace::save Error: matPutVariable ("<<names[i]<<
|
|
") failed"<<endl;
|
|
return false;
|
|
}
|
|
}
|
|
if(matClose(mat_file) != 0)
|
|
{
|
|
fprintf(stderr,"Error closing file %s\n",path.c_str());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
inline bool igl::matlab::MatlabWorkspace::read(const std::string & path)
|
|
{
|
|
using namespace std;
|
|
|
|
MATFile * mat_file;
|
|
|
|
mat_file = matOpen(path.c_str(), "r");
|
|
if (mat_file == NULL)
|
|
{
|
|
cerr<<"Error: failed to open "<<path<<endl;
|
|
return false;
|
|
}
|
|
|
|
int ndir;
|
|
const char ** dir = (const char **)matGetDir(mat_file, &ndir);
|
|
if (dir == NULL) {
|
|
cerr<<"Error reading directory of file "<< path<<endl;
|
|
return false;
|
|
}
|
|
mxFree(dir);
|
|
|
|
// Must close and reopen
|
|
if(matClose(mat_file) != 0)
|
|
{
|
|
cerr<<"Error: failed to close file "<<path<<endl;
|
|
return false;
|
|
}
|
|
mat_file = matOpen(path.c_str(), "r");
|
|
if (mat_file == NULL)
|
|
{
|
|
cerr<<"Error: failed to open "<<path<<endl;
|
|
return false;
|
|
}
|
|
|
|
|
|
/* Read in each array. */
|
|
for (int i=0; i<ndir; i++)
|
|
{
|
|
const char * name;
|
|
mxArray * mx_data = matGetNextVariable(mat_file, &name);
|
|
if (mx_data == NULL)
|
|
{
|
|
cerr<<"Error: matGetNextVariable failed in "<<path<<endl;
|
|
return false;
|
|
}
|
|
const int dims = mxGetNumberOfDimensions(mx_data);
|
|
assert(dims == 2);
|
|
if(dims != 2)
|
|
{
|
|
fprintf(stderr,"Variable '%s' has %d ≠ 2 dimensions. Skipping\n",
|
|
name,dims);
|
|
mxDestroyArray(mx_data);
|
|
continue;
|
|
}
|
|
// don't destroy
|
|
names.push_back(name);
|
|
data.push_back(mx_data);
|
|
}
|
|
|
|
if(matClose(mat_file) != 0)
|
|
{
|
|
cerr<<"Error: failed to close file "<<path<<endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Treat everything as a double
|
|
template <typename DerivedM>
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
|
const Eigen::PlainObjectBase<DerivedM>& M,
|
|
const std::string & name)
|
|
{
|
|
using namespace std;
|
|
const int m = M.rows();
|
|
const int n = M.cols();
|
|
mxArray * mx_data = mxCreateDoubleMatrix(m,n,mxREAL);
|
|
data.push_back(mx_data);
|
|
names.push_back(name);
|
|
// Copy data immediately
|
|
// Q: Won't this be incorrect for integers?
|
|
copy(M.data(),M.data()+M.size(),mxGetPr(mx_data));
|
|
return *this;
|
|
}
|
|
|
|
// Treat everything as a double
|
|
template <typename MT>
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
|
const Eigen::SparseMatrix<MT>& M,
|
|
const std::string & name)
|
|
{
|
|
using namespace std;
|
|
const int m = M.rows();
|
|
const int n = M.cols();
|
|
// THIS WILL NOT WORK FOR ROW-MAJOR
|
|
assert(n==M.outerSize());
|
|
const int nzmax = M.nonZeros();
|
|
mxArray * mx_data = mxCreateSparse(m, n, nzmax, mxREAL);
|
|
data.push_back(mx_data);
|
|
names.push_back(name);
|
|
// Copy data immediately
|
|
double * pr = mxGetPr(mx_data);
|
|
mwIndex * ir = mxGetIr(mx_data);
|
|
mwIndex * jc = mxGetJc(mx_data);
|
|
|
|
// Iterate over outside
|
|
int k = 0;
|
|
for(int j=0; j<M.outerSize();j++)
|
|
{
|
|
jc[j] = k;
|
|
// Iterate over inside
|
|
for(typename Eigen::SparseMatrix<MT>::InnerIterator it (M,j); it; ++it)
|
|
{
|
|
pr[k] = it.value();
|
|
ir[k] = it.row();
|
|
k++;
|
|
}
|
|
}
|
|
jc[M.outerSize()] = k;
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <typename ScalarM>
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
|
const std::vector<std::vector<ScalarM> > & vM,
|
|
const std::string & name)
|
|
{
|
|
Eigen::MatrixXd M;
|
|
list_to_matrix(vM,M);
|
|
return this->save(M,name);
|
|
}
|
|
|
|
template <typename ScalarV>
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
|
const std::vector<ScalarV> & vV,
|
|
const std::string & name)
|
|
{
|
|
Eigen::MatrixXd V;
|
|
list_to_matrix(vV,V);
|
|
return this->save(V,name);
|
|
}
|
|
|
|
template <typename Q>
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
|
const Eigen::Quaternion<Q> & q,
|
|
const std::string & name)
|
|
{
|
|
Eigen::Matrix<Q,1,4> qm;
|
|
qm(0,0) = q.w();
|
|
qm(0,1) = q.x();
|
|
qm(0,2) = q.y();
|
|
qm(0,3) = q.z();
|
|
return save(qm,name);
|
|
}
|
|
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
|
|
const double d,
|
|
const std::string & name)
|
|
{
|
|
Eigen::VectorXd v(1);
|
|
v(0) = d;
|
|
return save(v,name);
|
|
}
|
|
|
|
template <typename DerivedM>
|
|
inline igl::matlab::MatlabWorkspace&
|
|
igl::matlab::MatlabWorkspace::save_index(
|
|
const Eigen::PlainObjectBase<DerivedM>& M,
|
|
const std::string & name)
|
|
{
|
|
DerivedM Mp1 = M;
|
|
Mp1.array() += 1;
|
|
return this->save(Mp1,name);
|
|
}
|
|
|
|
template <typename ScalarM>
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save_index(
|
|
const std::vector<std::vector<ScalarM> > & vM,
|
|
const std::string & name)
|
|
{
|
|
Eigen::MatrixXd M;
|
|
list_to_matrix(vM,M);
|
|
return this->save_index(M,name);
|
|
}
|
|
|
|
template <typename ScalarV>
|
|
inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save_index(
|
|
const std::vector<ScalarV> & vV,
|
|
const std::string & name)
|
|
{
|
|
Eigen::MatrixXd V;
|
|
list_to_matrix(vV,V);
|
|
return this->save_index(V,name);
|
|
}
|
|
|
|
template <typename DerivedM>
|
|
inline bool igl::matlab::MatlabWorkspace::find(
|
|
const std::string & name,
|
|
Eigen::PlainObjectBase<DerivedM>& M)
|
|
{
|
|
using namespace std;
|
|
const int i = std::find(names.begin(), names.end(), name)-names.begin();
|
|
if(i>=(int)names.size())
|
|
{
|
|
return false;
|
|
}
|
|
assert(i<=(int)data.size());
|
|
mxArray * mx_data = data[i];
|
|
assert(!mxIsSparse(mx_data));
|
|
assert(mxGetNumberOfDimensions(mx_data) == 2);
|
|
//cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
|
|
const int m = mxGetM(mx_data);
|
|
const int n = mxGetN(mx_data);
|
|
// Handle vectors
|
|
if(DerivedM::IsVectorAtCompileTime)
|
|
{
|
|
assert(m==1 || n==1 || (m==0 && n==0));
|
|
M.resize(m*n,1);
|
|
}else
|
|
{
|
|
M.resize(m,n);
|
|
}
|
|
copy(
|
|
mxGetPr(mx_data),
|
|
mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
|
|
M.data());
|
|
return true;
|
|
}
|
|
|
|
template <typename MT>
|
|
inline bool igl::matlab::MatlabWorkspace::find(
|
|
const std::string & name,
|
|
Eigen::SparseMatrix<MT>& M)
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
const int i = std::find(names.begin(), names.end(), name)-names.begin();
|
|
if(i>=(int)names.size())
|
|
{
|
|
return false;
|
|
}
|
|
assert(i<=(int)data.size());
|
|
mxArray * mx_data = data[i];
|
|
// Handle boring case where matrix is actually an empty dense matrix
|
|
if(mxGetNumberOfElements(mx_data) == 0)
|
|
{
|
|
M.resize(0,0);
|
|
return true;
|
|
}
|
|
assert(mxIsSparse(mx_data));
|
|
assert(mxGetNumberOfDimensions(mx_data) == 2);
|
|
//cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
|
|
const int m = mxGetM(mx_data);
|
|
const int n = mxGetN(mx_data);
|
|
|
|
// Copy data immediately
|
|
double * pr = mxGetPr(mx_data);
|
|
mwIndex * ir = mxGetIr(mx_data);
|
|
mwIndex * jc = mxGetJc(mx_data);
|
|
|
|
vector<Triplet<MT> > MIJV;
|
|
MIJV.reserve(mxGetNumberOfElements(mx_data));
|
|
|
|
// Iterate over outside
|
|
int k = 0;
|
|
for(int j=0; j<n;j++)
|
|
{
|
|
// Iterate over inside
|
|
while(k<(int)jc[j+1])
|
|
{
|
|
//cout<<ir[k]<<" "<<j<<" "<<pr[k]<<endl;
|
|
assert((int)ir[k]<m);
|
|
assert((int)j<n);
|
|
MIJV.push_back(Triplet<MT >(ir[k],j,pr[k]));
|
|
k++;
|
|
}
|
|
}
|
|
M.resize(m,n);
|
|
M.setFromTriplets(MIJV.begin(),MIJV.end());
|
|
return true;
|
|
|
|
}
|
|
|
|
inline bool igl::matlab::MatlabWorkspace::find(
|
|
const std::string & name,
|
|
int & v)
|
|
{
|
|
using namespace std;
|
|
const int i = std::find(names.begin(), names.end(), name)-names.begin();
|
|
if(i>=(int)names.size())
|
|
{
|
|
return false;
|
|
}
|
|
assert(i<=(int)data.size());
|
|
mxArray * mx_data = data[i];
|
|
assert(!mxIsSparse(mx_data));
|
|
assert(mxGetNumberOfDimensions(mx_data) == 2);
|
|
//cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
|
|
assert(mxGetNumberOfElements(mx_data) == 1);
|
|
copy(
|
|
mxGetPr(mx_data),
|
|
mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
|
|
&v);
|
|
return true;
|
|
}
|
|
|
|
inline bool igl::matlab::MatlabWorkspace::find(
|
|
const std::string & name,
|
|
double & d)
|
|
{
|
|
using namespace std;
|
|
const int i = std::find(names.begin(), names.end(), name)-names.begin();
|
|
if(i>=(int)names.size())
|
|
{
|
|
return false;
|
|
}
|
|
assert(i<=(int)data.size());
|
|
mxArray * mx_data = data[i];
|
|
assert(!mxIsSparse(mx_data));
|
|
assert(mxGetNumberOfDimensions(mx_data) == 2);
|
|
//cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
|
|
assert(mxGetNumberOfElements(mx_data) == 1);
|
|
copy(
|
|
mxGetPr(mx_data),
|
|
mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
|
|
&d);
|
|
return true;
|
|
}
|
|
|
|
template <typename DerivedM>
|
|
inline bool igl::matlab::MatlabWorkspace::find_index(
|
|
const std::string & name,
|
|
Eigen::PlainObjectBase<DerivedM>& M)
|
|
{
|
|
if(!find(name,M))
|
|
{
|
|
return false;
|
|
}
|
|
M.array() -= 1;
|
|
return true;
|
|
}
|
|
|
|
|
|
//template <typename Data>
|
|
//bool igl::matlab::MatlabWorkspace::save(const Data & M, const std::string & name)
|
|
//{
|
|
// using namespace std;
|
|
// // If I don't know the type then I can't save it
|
|
// cerr<<"^MatlabWorkspace::save Error: Unknown data type. "<<
|
|
// name<<" not saved."<<endl;
|
|
// return false;
|
|
//}
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matlab_mexErrMsgTxt = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATLAB_MEXERRMSGTXT_H
|
|
#define IGL_MATLAB_MEXERRMSGTXT_H
|
|
#include "../igl_inline.h"
|
|
namespace igl
|
|
{
|
|
namespace matlab
|
|
{
|
|
// Wrapper for mexErrMsgTxt that only calls error if test fails
|
|
IGL_INLINE void mexErrMsgTxt(bool test, const char * message);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mexErrMsgTxt.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matlab_MexStream = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATLAB_MEX_STREAM_H
|
|
#define IGL_MATLAB_MEX_STREAM_H
|
|
#include <iostream>
|
|
namespace igl
|
|
{
|
|
namespace matlab
|
|
{
|
|
// http://stackoverflow.com/a/249008/148668
|
|
|
|
// Class to implement "cout" for mex files to print to the matlab terminal
|
|
// window.
|
|
//
|
|
// Insert at the beginning of mexFunction():
|
|
// MexStream mout;
|
|
// std::streambuf *outbuf = std::cout.rdbuf(&mout);
|
|
// ...
|
|
// ALWAYS restore original buffer to avoid memory leak problems in matlab
|
|
// std::cout.rdbuf(outbuf);
|
|
//
|
|
class MexStream : public std::streambuf
|
|
{
|
|
public:
|
|
protected:
|
|
inline virtual std::streamsize xsputn(const char *s, std::streamsize n);
|
|
inline virtual int overflow(int c = EOF);
|
|
};
|
|
}
|
|
}
|
|
|
|
// Implementation
|
|
#include <mex.h>
|
|
inline std::streamsize igl::matlab::MexStream::xsputn(
|
|
const char *s,
|
|
std::streamsize n)
|
|
{
|
|
mexPrintf("%.*s",n,s);
|
|
mexEvalString("drawnow;"); // to dump string.
|
|
return n;
|
|
}
|
|
|
|
inline int igl::matlab::MexStream::overflow(int c)
|
|
{
|
|
if (c != EOF) {
|
|
mexPrintf("%.1s",&c);
|
|
mexEvalString("drawnow;"); // to dump string.
|
|
}
|
|
return 1;
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matlab_parse_rhs = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATLAB_PARSE_RHS_H
|
|
#define IGL_MATLAB_PARSE_RHS_H
|
|
#include <igl/igl_inline.h>
|
|
#include <mex.h>
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
namespace matlab
|
|
{
|
|
// Reads in a matrix as a double
|
|
//
|
|
// Inputs:
|
|
// prhs points to rhs argument
|
|
// Outputs:
|
|
// V M by N matrix
|
|
template <typename DerivedV>
|
|
IGL_INLINE void parse_rhs_double(
|
|
const mxArray *prhs[],
|
|
Eigen::PlainObjectBase<DerivedV> & V);
|
|
// Reads in a matrix and subtracts 1
|
|
template <typename DerivedV>
|
|
IGL_INLINE void parse_rhs_index(
|
|
const mxArray *prhs[],
|
|
Eigen::PlainObjectBase<DerivedV> & V);
|
|
}
|
|
};
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "parse_rhs.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_matlab_prepare_lhs = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MATLAB_PREPARE_LHS_H
|
|
#define IGL_MATLAB_PREPARE_LHS_H
|
|
#include <igl/igl_inline.h>
|
|
#include <mex.h>
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
namespace matlab
|
|
{
|
|
// Writes out a matrix as a double
|
|
//
|
|
// Inputs:
|
|
// prhs points to rhs argument
|
|
// Outputs:
|
|
// V M by N matrix
|
|
template <typename DerivedV>
|
|
IGL_INLINE void prepare_lhs_double(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
mxArray *plhs[]);
|
|
// Casts to logical
|
|
template <typename DerivedV>
|
|
IGL_INLINE void prepare_lhs_logical(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
mxArray *plhs[]);
|
|
// Writes out a matrix and adds 1
|
|
template <typename DerivedV>
|
|
IGL_INLINE void prepare_lhs_index(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
mxArray *plhs[]);
|
|
};
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "prepare_lhs.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mosek_mosek_guarded = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MOSEK_MOSEK_GUARDED_H
|
|
#define IGL_MOSEK_MOSEK_GUARDED_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "mosek.h"
|
|
namespace igl
|
|
{
|
|
namespace mosek
|
|
{
|
|
// Little function to wrap around mosek call to handle errors
|
|
//
|
|
// Inputs:
|
|
// r mosek error code returned from mosek call
|
|
// Returns r untouched
|
|
IGL_INLINE MSKrescodee mosek_guarded(const MSKrescodee r);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mosek_guarded.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mosek_mosek_linprog = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MOSEK_MOSEK_LINPROG_H
|
|
#define IGL_MOSEK_MOSEK_LINPROG_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Sparse>
|
|
#include <mosek.h>
|
|
namespace igl
|
|
{
|
|
namespace mosek
|
|
{
|
|
// Solve a linear program using mosek:
|
|
//
|
|
// min c'x
|
|
// s.t. lc <= A x <= uc
|
|
// lx <= x <= ux
|
|
//
|
|
// Inputs:
|
|
// c #x list of linear objective coefficients
|
|
// A #A by #x matrix of linear inequality constraint coefficients
|
|
// lc #A list of lower constraint bounds
|
|
// uc #A list of upper constraint bounds
|
|
// lx #x list of lower variable bounds
|
|
// ux #x list of upper variable bounds
|
|
// Outputs:
|
|
// x #x list of solution values
|
|
// Returns true iff success.
|
|
IGL_INLINE bool mosek_linprog(
|
|
const Eigen::VectorXd & c,
|
|
const Eigen::SparseMatrix<double> & A,
|
|
const Eigen::VectorXd & lc,
|
|
const Eigen::VectorXd & uc,
|
|
const Eigen::VectorXd & lx,
|
|
const Eigen::VectorXd & ux,
|
|
Eigen::VectorXd & x);
|
|
// Wrapper that keeps mosek environment alive (if licence checking is
|
|
// becoming a bottleneck)
|
|
IGL_INLINE bool mosek_linprog(
|
|
const Eigen::VectorXd & c,
|
|
const Eigen::SparseMatrix<double> & A,
|
|
const Eigen::VectorXd & lc,
|
|
const Eigen::VectorXd & uc,
|
|
const Eigen::VectorXd & lx,
|
|
const Eigen::VectorXd & ux,
|
|
const MSKenv_t & env,
|
|
Eigen::VectorXd & x);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mosek_linprog.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_mosek_mosek_quadprog = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_MOSEK_MOSEK_QUADPROG_H
|
|
#define IGL_MOSEK_MOSEK_QUADPROG_H
|
|
#include "../igl_inline.h"
|
|
#include <vector>
|
|
#include <map>
|
|
#include "mosek.h"
|
|
|
|
|
|
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
namespace igl
|
|
{
|
|
namespace mosek
|
|
{
|
|
struct MosekData
|
|
{
|
|
// Integer parameters
|
|
std::map<MSKiparame,int> intparam;
|
|
// Double parameters
|
|
std::map<MSKdparame,double> douparam;
|
|
// Default values
|
|
MosekData();
|
|
};
|
|
// Solve a convex quadratic optimization problem with linear and constant
|
|
// bounds, that is:
|
|
//
|
|
// Minimize: ½ * xT * Q⁰ * x + cT * x + cf
|
|
//
|
|
// Subject to: lc ≤ Ax ≤ uc
|
|
// lx ≤ x ≤ ux
|
|
//
|
|
// where we are trying to find the optimal vector of values x.
|
|
//
|
|
// Note: Q⁰ must be symmetric and the ½ is a convention of MOSEK
|
|
//
|
|
// Note: Because of how MOSEK accepts different parts of the system, Q should
|
|
// be stored in IJV (aka Coordinate) format and should only include entries in
|
|
// the lower triangle. A should be stored in Column compressed (aka Harwell
|
|
// Boeing) format. As described:
|
|
// http://netlib.org/linalg/html_templates/node92.html
|
|
// or
|
|
// http://en.wikipedia.org/wiki/Sparse_matrix
|
|
// #Compressed_sparse_column_.28CSC_or_CCS.29
|
|
//
|
|
//
|
|
// Templates:
|
|
// Index type for index variables
|
|
// Scalar type for floating point variables (gets cast to double?)
|
|
// Input:
|
|
// n number of variables, i.e. size of x
|
|
// Qi vector of qnnz row indices of non-zeros in LOWER TRIANGLE ONLY of Q⁰
|
|
// Qj vector of qnnz column indices of non-zeros in LOWER TRIANGLE ONLY of
|
|
// Q⁰
|
|
// Qv vector of qnnz values of non-zeros in LOWER TRIANGLE ONLY of Q⁰,
|
|
// such that:
|
|
// Q⁰(Qi[k],Qj[k]) = Qv[k] for k ∈ [0,Qnnz-1], where Qnnz is the number of
|
|
// non-zeros in Q⁰
|
|
// c (optional) vector of n values of c, transpose of coefficient row vector
|
|
// of linear terms, EMPTY means c == 0
|
|
// cf (optional) value of constant term in objective, 0 means cf == 0, so
|
|
// optional only in the sense that it is mandatory
|
|
// m number of constraints, therefore also number of rows in linear
|
|
// constraint coefficient matrix A, and in linear constraint bound vectors
|
|
// lc and uc
|
|
// Av vector of non-zero values of A, in column compressed order
|
|
// Ari vector of row indices corresponding to non-zero values of A,
|
|
// Acp vector of indices into Ari and Av of the first entry for each column
|
|
// of A, size(Acp) = (# columns of A) + 1 = n + 1
|
|
// lc vector of m linear constraint lower bounds
|
|
// uc vector of m linear constraint upper bounds
|
|
// lx vector of n constant lower bounds
|
|
// ux vector of n constant upper bounds
|
|
// Output:
|
|
// x vector of size n to hold output of optimization
|
|
// Return:
|
|
// true only if optimization was successful with no errors
|
|
//
|
|
// Note: All indices are 0-based
|
|
//
|
|
template <typename Index, typename Scalar>
|
|
IGL_INLINE bool mosek_quadprog(
|
|
const Index n,
|
|
/* mosek won't allow this to be const*/ std::vector<Index> & Qi,
|
|
/* mosek won't allow this to be const*/ std::vector<Index> & Qj,
|
|
/* mosek won't allow this to be const*/ std::vector<Scalar> & Qv,
|
|
const std::vector<Scalar> & c,
|
|
const Scalar cf,
|
|
const Index m,
|
|
/* mosek won't allow this to be const*/ std::vector<Scalar> & Av,
|
|
/* mosek won't allow this to be const*/ std::vector<Index> & Ari,
|
|
const std::vector<Index> & Acp,
|
|
const std::vector<Scalar> & lc,
|
|
const std::vector<Scalar> & uc,
|
|
const std::vector<Scalar> & lx,
|
|
const std::vector<Scalar> & ux,
|
|
MosekData & mosek_data,
|
|
std::vector<Scalar> & x);
|
|
|
|
// Wrapper with Eigen elements
|
|
//// Templates:
|
|
//// Scalar Scalar type for sparse matrix (e.g. double)
|
|
//// Derived dervied type from matrix/vector (e.g. VectorXd)
|
|
IGL_INLINE bool mosek_quadprog(
|
|
const Eigen::SparseMatrix<double> & Q,
|
|
const Eigen::VectorXd & c,
|
|
const double cf,
|
|
const Eigen::SparseMatrix<double> & A,
|
|
const Eigen::VectorXd & lc,
|
|
const Eigen::VectorXd & uc,
|
|
const Eigen::VectorXd & lx,
|
|
const Eigen::VectorXd & ux,
|
|
MosekData & mosek_data,
|
|
Eigen::VectorXd & x);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mosek_quadprog.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_compile_and_link_program = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_COMPILE_AND_LINK_PROGRAM_H
|
|
#define IGL_OPENGL_COMPILE_AND_LINK_PROGRAM_H
|
|
#include "../igl_inline.h"
|
|
#include "OpenGL_convenience.h"
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Compile and link very simple vertex/fragment shaders
|
|
//
|
|
// Inputs:
|
|
// v_str string of vertex shader contents
|
|
// f_str string of fragment shader contents
|
|
// Returns id of program
|
|
//
|
|
// Known bugs: this seems to duplicate `create_shader_program` with less
|
|
// functionality.
|
|
IGL_INLINE GLuint compile_and_link_program(
|
|
const char * v_str, const char * f_str);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "compile_and_link_program.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_compile_shader = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_COMPILE_SHADER_H
|
|
#define IGL_OPENGL_COMPILE_SHADER_H
|
|
#include "OpenGL_convenience.h"
|
|
#include "../igl_inline.h"
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Compile a shader given type and string of shader code
|
|
//
|
|
// Inputs:
|
|
// type either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
|
|
// str contents of shader code
|
|
// Returns result of glCreateShader (id of shader)
|
|
//
|
|
// Example:
|
|
// GLuint vid = compile_shader(GL_VERTEX_SHADER,vertex_shader.c_str());
|
|
// GLuint fid = compile_shader(GL_FRAGMENT_SHADER,fragment_shader.c_str());
|
|
// GLuint prog_id = glCreateProgram();
|
|
// glAttachShader(prog_id,vid);
|
|
// glAttachShader(prog_id,fid);
|
|
// glLinkProgram(prog_id);
|
|
//
|
|
// Known bugs: seems to be duplicate of `load_shader`
|
|
IGL_INLINE GLuint compile_shader(const GLint type, const char * str);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "compile_shader.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_create_index_vbo = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_CREATE_INDEX_VBO_H
|
|
#define IGL_OPENGL_CREATE_INDEX_VBO_H
|
|
#include "../igl_inline.h"
|
|
// NOTE: It wouldn't be so hard to template this using Eigen's templates
|
|
|
|
#include <Eigen/Core>
|
|
#include "OpenGL_convenience.h"
|
|
|
|
// Create a VBO (Vertex Buffer Object) for a list of indices:
|
|
// GL_ELEMENT_ARRAY_BUFFER_ARB for the triangle indices (F)
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Inputs:
|
|
// F #F by 3 eigen Matrix of face (triangle) indices
|
|
// Outputs:
|
|
// F_vbo_id buffer id for face indices
|
|
//
|
|
IGL_INLINE void create_index_vbo(
|
|
const Eigen::MatrixXi & F,
|
|
GLuint & F_vbo_id);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "create_index_vbo.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_create_mesh_vbo = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_CREATE_MESH_VBO_H
|
|
#define IGL_OPENGL_CREATE_MESH_VBO_H
|
|
#include "../igl_inline.h"
|
|
// NOTE: It wouldn't be so hard to template this using Eigen's templates
|
|
|
|
#include <Eigen/Core>
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
// Create a VBO (Vertex Buffer Object) for a mesh. Actually two VBOs: one
|
|
// GL_ARRAY_BUFFER for the vertex positions (V) and one
|
|
// GL_ELEMENT_ARRAY_BUFFER for the triangle indices (F)
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigne Matrix of face (triangle) indices
|
|
// Outputs:
|
|
// V_vbo_id buffer id for vertex positions
|
|
// F_vbo_id buffer id for face indices
|
|
//
|
|
// NOTE: when using glDrawElements VBOs for V and F using MatrixXd and
|
|
// MatrixXi will have types GL_DOUBLE and GL_UNSIGNED_INT respectively
|
|
//
|
|
IGL_INLINE void create_mesh_vbo(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
GLuint & V_vbo_id,
|
|
GLuint & F_vbo_id);
|
|
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3 eigne Matrix of face (triangle) indices
|
|
// N #V by 3 eigen Matrix of mesh vertex 3D normals
|
|
// Outputs:
|
|
// V_vbo_id buffer id for vertex positions
|
|
// F_vbo_id buffer id for face indices
|
|
// N_vbo_id buffer id for vertex positions
|
|
IGL_INLINE void create_mesh_vbo(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & N,
|
|
GLuint & V_vbo_id,
|
|
GLuint & F_vbo_id,
|
|
GLuint & N_vbo_id);
|
|
}
|
|
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "create_mesh_vbo.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_create_shader_program = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_CREATE_SHADER_PROGRAM_H
|
|
#define IGL_OPENGL_CREATE_SHADER_PROGRAM_H
|
|
|
|
#include "../igl_inline.h"
|
|
#include <string>
|
|
#include <map>
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Create a shader program with a vertex and fragments shader loading from
|
|
// source strings and vertex attributes assigned from a map before linking the
|
|
// shaders to the program, making it ready to use with glUseProgram(id)
|
|
// Inputs:
|
|
// geom_source string containing source code of geometry shader (can be
|
|
// "" to mean use default pass-through)
|
|
// vert_source string containing source code of vertex shader
|
|
// frag_source string containing source code of fragment shader
|
|
// attrib map containing table of vertex attribute strings add their
|
|
// correspondingly ids (generated previously using glBindAttribLocation)
|
|
// Outputs:
|
|
// id index id of created shader, set to 0 on error
|
|
// Returns true on success, false on error
|
|
//
|
|
// Note: Caller is responsible for making sure that current value of id is not
|
|
// leaking a shader (since it will be overwritten)
|
|
//
|
|
// See also: destroy_shader_program
|
|
IGL_INLINE bool create_shader_program(
|
|
const std::string &geom_source,
|
|
const std::string &vert_source,
|
|
const std::string &frag_source,
|
|
const std::map<std::string,GLuint> &attrib,
|
|
GLuint & id);
|
|
IGL_INLINE bool create_shader_program(
|
|
const std::string &vert_source,
|
|
const std::string &frag_source,
|
|
const std::map<std::string,GLuint> &attrib,
|
|
GLuint & id);
|
|
IGL_INLINE GLuint create_shader_program(
|
|
const std::string & geom_source,
|
|
const std::string & vert_source,
|
|
const std::string & frag_source,
|
|
const std::map<std::string,GLuint> &attrib);
|
|
IGL_INLINE GLuint create_shader_program(
|
|
const std::string & vert_source,
|
|
const std::string & frag_source,
|
|
const std::map<std::string,GLuint> &attrib);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "create_shader_program.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_create_vector_vbo = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_CREATE_VECTOR_VBO_H
|
|
#define IGL_OPENGL_CREATE_VECTOR_VBO_H
|
|
#include "../igl_inline.h"
|
|
// NOTE: It wouldn't be so hard to template this using Eigen's templates
|
|
|
|
#include <Eigen/Core>
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
// Create a VBO (Vertex Buffer Object) for a list of vectors:
|
|
// GL_ARRAY_BUFFER for the vectors (V)
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Templates:
|
|
// T should be a eigen matrix primitive type like int or double
|
|
// Inputs:
|
|
// V m by n eigen Matrix of type T values
|
|
// Outputs:
|
|
// V_vbo_id buffer id for vectors
|
|
//
|
|
template <typename T>
|
|
IGL_INLINE void create_vector_vbo(
|
|
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & V,
|
|
GLuint & V_vbo_id);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "create_vector_vbo.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_destroy_shader_program = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_DESTROY_SHADER_PROGRAM_H
|
|
#define IGL_OPENGL_DESTROY_SHADER_PROGRAM_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Properly destroy a shader program. Detach and delete each of its shaders
|
|
// and delete it
|
|
// Inputs:
|
|
// id index id of created shader, set to 0 on error
|
|
// Returns true on success, false on error
|
|
//
|
|
// Note: caller is responsible for making sure he doesn't foolishly continue
|
|
// to use id as if it still contains a program
|
|
//
|
|
// See also: create_shader_program
|
|
IGL_INLINE bool destroy_shader_program(const GLuint id);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "destroy_shader_program.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_gl_type_size = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_GL_TYPE_SIZE_H
|
|
#define IGL_OPENGL_GL_TYPE_SIZE_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Return the number of bytes for a given OpenGL type // Inputs:
|
|
// type enum value of opengl type
|
|
// Returns size in bytes of type
|
|
IGL_INLINE int gl_type_size(const GLenum type);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "gl_type_size.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_init_render_to_texture = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_INIT_RENDER_TO_TEXTURE_H
|
|
#define IGL_OPENGL_INIT_RENDER_TO_TEXTURE_H
|
|
#include "../igl_inline.h"
|
|
#include "OpenGL_convenience.h"
|
|
#include <cstdlib>
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Create a texture+framebuffer+depthbuffer triplet bound for rendering into
|
|
// the texture;
|
|
//
|
|
// Inputs:
|
|
// width image width
|
|
// height image height
|
|
// Outputs:
|
|
// tex_id id of the texture
|
|
// fbo_id id of the frame buffer object
|
|
// dfbo_id id of the depth frame buffer object
|
|
IGL_INLINE void init_render_to_texture(
|
|
const size_t width,
|
|
const size_t height,
|
|
GLuint & tex_id,
|
|
GLuint & fbo_id,
|
|
GLuint & dfbo_id);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "init_render_to_texture.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_load_shader = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_LOAD_SHADER_H
|
|
#define IGL_OPENGL_LOAD_SHADER_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Creates and compiles a shader from a given string
|
|
// Inputs:
|
|
// src string containing GLSL shader code
|
|
// type GLSL type of shader, one of:
|
|
// GL_VERTEX_SHADER
|
|
// GL_FRAGMENT_SHADER
|
|
// GL_GEOMETRY_SHADER
|
|
// Returns index id of the newly created shader, 0 on error
|
|
IGL_INLINE GLuint load_shader(const char *src,const GLenum type);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "load_shader.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_OpenGL_convenience = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_OPENGL_CONVENIENCE_H
|
|
#define IGL_OPENGL_OPENGL_CONVENIENCE_H
|
|
|
|
// Always use this:
|
|
// #include "OpenGL_convenience.h"
|
|
// Convenience includer for opengl.
|
|
|
|
// For now this includes glu, glew and glext (perhaps these should be
|
|
// separated)
|
|
#if __APPLE__
|
|
# include <OpenGL/gl.h>
|
|
# include <OpenGL/glu.h>
|
|
# include <OpenGL/glext.h>
|
|
#elif defined(_WIN32)
|
|
# define NOMINMAX
|
|
# include <Windows.h>
|
|
# undef NOMINMAX
|
|
# include <GL/glew.h>
|
|
# include <GL/gl.h>
|
|
#else
|
|
# define GL_GLEXT_PROTOTYPES
|
|
# include <GL/gl.h>
|
|
# include <GL/glext.h>
|
|
# include <GL/glu.h>
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_print_program_info_log = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_PRINT_PROGRAM_INFO_LOG_H
|
|
#define IGL_OPENGL_PRINT_PROGRAM_INFO_LOG_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Inputs:
|
|
// obj OpenGL index of program to print info log about
|
|
IGL_INLINE void print_program_info_log(const GLuint obj);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "print_program_info_log.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_print_shader_info_log = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_PRINT_SHADER_INFO_LOG_H
|
|
#define IGL_OPENGL_PRINT_SHADER_INFO_LOG_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Inputs:
|
|
// obj OpenGL index of shader to print info log about
|
|
IGL_INLINE void print_shader_info_log(const GLuint obj);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "print_shader_info_log.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_render_to_tga = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_RENDER_TO_TGA_H
|
|
#define IGL_OPENGL_RENDER_TO_TGA_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Render current open GL image to .tga file
|
|
// Inputs:
|
|
// tga_file path to output .tga file
|
|
// width width of scene and resulting image
|
|
// height height of scene and resulting image
|
|
/// alpha whether to include alpha channel
|
|
// Returns true only if no errors occured
|
|
//
|
|
// See also: png/render_to_png which is slower but writes .png files
|
|
IGL_INLINE bool render_to_tga(
|
|
const std::string tga_file,
|
|
const int width,
|
|
const int height,
|
|
const bool alpha);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "render_to_tga.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_report_gl_error = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_REPORT_GL_ERROR_H
|
|
#define IGL_OPENGL_REPORT_GL_ERROR_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Print last OpenGL error to stderr prefixed by specified id string
|
|
// Inputs:
|
|
// id string to appear before any error msgs
|
|
// Returns result of glGetError()
|
|
IGL_INLINE GLenum report_gl_error(const std::string id);
|
|
// No prefix
|
|
IGL_INLINE GLenum report_gl_error();
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "report_gl_error.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_texture_from_tga = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_TEXTURE_FROM_TGA_H
|
|
#define IGL_OPENGL_TEXTURE_FROM_TGA_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Read an image from a .tga file and use it as a texture
|
|
//
|
|
// Input:
|
|
// tga_file path to .tga file
|
|
// Output:
|
|
// id of generated openGL texture
|
|
// Returns true on success, false on failure
|
|
IGL_INLINE bool texture_from_tga(const std::string tga_file, GLuint & id);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "texture_from_tga.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_tga = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_TGA_H
|
|
#define IGL_OPENGL_TGA_H
|
|
#include "../igl_inline.h"
|
|
// See license in tga.cpp
|
|
|
|
/* tga.h - interface for TrueVision (TGA) image file loader */
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
|
|
typedef struct {
|
|
|
|
GLsizei width;
|
|
GLsizei height;
|
|
GLint components;
|
|
GLenum format;
|
|
|
|
GLsizei cmapEntries;
|
|
GLenum cmapFormat;
|
|
GLubyte *cmap;
|
|
|
|
GLubyte *pixels;
|
|
|
|
} gliGenericImage;
|
|
|
|
typedef struct {
|
|
unsigned char idLength;
|
|
unsigned char colorMapType;
|
|
|
|
/* The image type. */
|
|
#define TGA_TYPE_MAPPED 1
|
|
#define TGA_TYPE_COLOR 2
|
|
#define TGA_TYPE_GRAY 3
|
|
#define TGA_TYPE_MAPPED_RLE 9
|
|
#define TGA_TYPE_COLOR_RLE 10
|
|
#define TGA_TYPE_GRAY_RLE 11
|
|
unsigned char imageType;
|
|
|
|
/* Color Map Specification. */
|
|
/* We need to separately specify high and low bytes to avoid endianness
|
|
and alignment problems. */
|
|
unsigned char colorMapIndexLo, colorMapIndexHi;
|
|
unsigned char colorMapLengthLo, colorMapLengthHi;
|
|
unsigned char colorMapSize;
|
|
|
|
/* Image Specification. */
|
|
unsigned char xOriginLo, xOriginHi;
|
|
unsigned char yOriginLo, yOriginHi;
|
|
|
|
unsigned char widthLo, widthHi;
|
|
unsigned char heightLo, heightHi;
|
|
|
|
unsigned char bpp;
|
|
|
|
/* Image descriptor.
|
|
3-0: attribute bpp
|
|
4: left-to-right ordering
|
|
5: top-to-bottom ordering
|
|
7-6: zero
|
|
*/
|
|
#define TGA_DESC_ABITS 0x0f
|
|
#define TGA_DESC_HORIZONTAL 0x10
|
|
#define TGA_DESC_VERTICAL 0x20
|
|
unsigned char descriptor;
|
|
|
|
} TgaHeader;
|
|
|
|
typedef struct {
|
|
unsigned int extensionAreaOffset;
|
|
unsigned int developerDirectoryOffset;
|
|
#define TGA_SIGNATURE "TRUEVISION-XFILE"
|
|
char signature[16];
|
|
char dot;
|
|
char null;
|
|
} TgaFooter;
|
|
|
|
IGL_INLINE extern gliGenericImage *gliReadTGA(FILE *fp, char *name, int hflip, int vflip);
|
|
IGL_INLINE int gli_verbose(int new_verbose);
|
|
IGL_INLINE extern int gliVerbose(int newVerbose);
|
|
|
|
IGL_INLINE void writeTGA( gliGenericImage* image, FILE *fp);
|
|
|
|
|
|
|
|
} // end of igl namespace
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "tga.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl_uniform_type_to_string = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL_UNIFORM_TYPE_TO_STRING_H
|
|
#define IGL_OPENGL_UNIFORM_TYPE_TO_STRING_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <string>
|
|
|
|
#include "OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl
|
|
{
|
|
// Convert a GL uniform variable type (say, returned from
|
|
// glGetActiveUniform) and output a string naming that type
|
|
// Inputs:
|
|
// type enum for given type
|
|
// Returns string name of that type
|
|
IGL_INLINE std::string uniform_type_to_string(const GLenum type);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "uniform_type_to_string.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_draw_beach_ball = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_DRAW_BEACH_BALL_H
|
|
#define IGL_OPENGL2_DRAW_BEACH_BALL_H
|
|
#include "../igl_inline.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Draw a beach ball icon/glyph (from AntTweakBar) at the current origin
|
|
// according to the current orientation: ball has radius 0.75 and axis have
|
|
// length 1.15
|
|
IGL_INLINE void draw_beach_ball();
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "draw_beach_ball.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_draw_floor = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_DRAW_FLOOR_H
|
|
#define IGL_OPENGL2_DRAW_FLOOR_H
|
|
#include "../igl_inline.h"
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
|
|
// Draw a checkerboard floor aligned with current (X,Z) plane using ../opengl/OpenGL_
|
|
// calls. side=50 centered at (0,0):
|
|
// (-25,-25)-->(-25,25)-->(25,25)-->(25,-25)
|
|
//
|
|
// Use glPushMatrix(), glScaled(), glTranslated() to arrange the floor.
|
|
//
|
|
// Inputs:
|
|
// colorA float4 color
|
|
// colorB float4 color
|
|
//
|
|
// Example:
|
|
// // Draw a nice floor
|
|
// glPushMatrix();
|
|
// glCullFace(GL_BACK);
|
|
// glEnable(GL_CULL_FACE);
|
|
// glEnable(GL_LIGHTING);
|
|
// glTranslated(0,-1,0);
|
|
// if(project(Vector3d(0,0,0))(2) - project(Vector3d(0,1,0))(2) > -FLOAT_EPS)
|
|
// {
|
|
// draw_floor_outline();
|
|
// }
|
|
// draw_floor();
|
|
// glPopMatrix();
|
|
// glDisable(GL_CULL_FACE);
|
|
//
|
|
IGL_INLINE void draw_floor(
|
|
const float * colorA,
|
|
const float * colorB,
|
|
const int GridSizeX=100,
|
|
const int GridSizeY=100);
|
|
// Wrapper with default colors
|
|
IGL_INLINE void draw_floor();
|
|
IGL_INLINE void draw_floor_outline(
|
|
const float * colorA,
|
|
const float * colorB,
|
|
const int GridSizeX=100,
|
|
const int GridSizeY=100);
|
|
// Wrapper with default colors
|
|
IGL_INLINE void draw_floor_outline();
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "draw_floor.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_draw_mesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_DRAW_MESH_H
|
|
#define IGL_OPENGL2_DRAW_MESH_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
#include "../opengl/OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
|
|
// Draw ../opengl/OpenGL_ commands needed to display a mesh with normals
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3|4 eigen Matrix of face (triangle/quad) indices
|
|
// N #V|#F by 3 eigen Matrix of 3D normals
|
|
IGL_INLINE void draw_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & N);
|
|
|
|
// Draw ../opengl/OpenGL_ commands needed to display a mesh with normals and per-vertex
|
|
// colors
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3|4 eigen Matrix of face (triangle/quad) indices
|
|
// N #V|#F by 3 eigen Matrix of 3D normals
|
|
// C #V|#F|1 by 3 eigen Matrix of RGB colors
|
|
IGL_INLINE void draw_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & N,
|
|
const Eigen::MatrixXd & C);
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3|4 eigen Matrix of face (triangle/quad) indices
|
|
// N #V|#F by 3 eigen Matrix of 3D normals
|
|
// C #V|#F|1 by 3 eigen Matrix of RGB colors
|
|
// TC #V|#F|1 by 3 eigen Matrix of Texture Coordinates
|
|
IGL_INLINE void draw_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & N,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXd & TC);
|
|
|
|
// Draw ../opengl/OpenGL_ commands needed to display a mesh with normals, per-vertex
|
|
// colors and LBS weights
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3|4 eigen Matrix of face (triangle/quad) indices
|
|
// N #V by 3 eigen Matrix of mesh vertex 3D normals
|
|
// C #V by 3 eigen Matrix of mesh vertex RGB colors
|
|
// TC #V by 3 eigen Matrix of mesh vertex UC coorindates between 0 and 1
|
|
// W #V by #H eigen Matrix of per mesh vertex, per handle weights
|
|
// W_index Specifies the index of the "weight" vertex attribute: see
|
|
// glBindAttribLocation, if W_index is 0 then weights are ignored
|
|
// WI #V by #H eigen Matrix of per mesh vertex, per handle weight ids
|
|
// WI_index Specifies the index of the "weight" vertex attribute: see
|
|
// glBindAttribLocation, if WI_index is 0 then weight indices are ignored
|
|
IGL_INLINE void draw_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & N,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXd & TC,
|
|
const Eigen::MatrixXd & W,
|
|
const GLuint W_index,
|
|
const Eigen::MatrixXi & WI,
|
|
const GLuint WI_index);
|
|
|
|
// Draw ../opengl/OpenGL_ commands needed to display a mesh with normals, per-vertex
|
|
// colors and LBS weights
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
|
// F #F by 3|4 eigen Matrix of face (triangle/quad) indices
|
|
// N #V by 3 eigen Matrix of mesh vertex 3D normals
|
|
// NF #F by 3 eigen Matrix of face (triangle/quad) normal indices, <0
|
|
// means no normal
|
|
// C #V by 3 eigen Matrix of mesh vertex RGB colors
|
|
// TC #V by 3 eigen Matrix of mesh vertex UC coorindates between 0 and 1
|
|
// TF #F by 3 eigen Matrix of face (triangle/quad) texture indices, <0
|
|
// means no texture
|
|
// W #V by #H eigen Matrix of per mesh vertex, per handle weights
|
|
// W_index Specifies the index of the "weight" vertex attribute: see
|
|
// glBindAttribLocation, if W_index is 0 then weights are ignored
|
|
// WI #V by #H eigen Matrix of per mesh vertex, per handle weight ids
|
|
// WI_index Specifies the index of the "weight" vertex attribute: see
|
|
// glBindAttribLocation, if WI_index is 0 then weight indices are ignored
|
|
IGL_INLINE void draw_mesh(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & N,
|
|
const Eigen::MatrixXi & NF,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXd & TC,
|
|
const Eigen::MatrixXi & TF,
|
|
const Eigen::MatrixXd & W,
|
|
const GLuint W_index,
|
|
const Eigen::MatrixXi & WI,
|
|
const GLuint WI_index);
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "draw_mesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_draw_point = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_DRAW_POINT_H
|
|
#define IGL_OPENGL2_DRAW_POINT_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
|
|
//double POINT_COLOR[3] = {239./255.,213./255.,46./255.};
|
|
// Draw a nice looking, colored dot at a given point in 3d.
|
|
//
|
|
// Note: expects that GL_CURRENT_COLOR is set with the desired foreground color
|
|
//
|
|
// Inputs:
|
|
// x x-coordinate of point, modelview coordinates
|
|
// y y-coordinate of point, modelview coordinates
|
|
// z z-coordinate of point, modelview coordinates
|
|
// requested_r outer-most radius of dot {7}, measured in screen space pixels
|
|
// selected fills inner circle with black {false}
|
|
// Asserts that requested_r does not exceed 0.5*GL_POINT_SIZE_MAX
|
|
IGL_INLINE void draw_point(
|
|
const double x,
|
|
const double y,
|
|
const double z,
|
|
const double requested_r = 7,
|
|
const bool selected = false);
|
|
template <typename DerivedP>
|
|
IGL_INLINE void draw_point(
|
|
const Eigen::PlainObjectBase<DerivedP> & P,
|
|
const double requested_r = 7,
|
|
const bool selected = false);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "draw_point.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_draw_rectangular_marquee = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_DRAW_RECTANGULAR_MARQUEE_H
|
|
#define IGL_OPENGL2_DRAW_RECTANGULAR_MARQUEE_H
|
|
#include "../igl_inline.h"
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Draw a rectangular marquee (selection box) in screen space. This sets up
|
|
// screen space using current viewport.
|
|
//
|
|
// Inputs:
|
|
// from_x x coordinate of from point
|
|
// from_y y coordinate of from point
|
|
// to_x x coordinate of to point
|
|
// to_y y coordinate of to point
|
|
IGL_INLINE void draw_rectangular_marquee(
|
|
const int from_x,
|
|
const int from_y,
|
|
const int to_x,
|
|
const int to_y);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "draw_rectangular_marquee.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_draw_skeleton_3d = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_DRAW_SKELETON_3D_H
|
|
#define IGL_OPENGL2_DRAW_SKELETON_3D_H
|
|
#include "../igl_inline.h"
|
|
#include "../material_colors.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
|
|
// Draw a skeleton
|
|
//
|
|
// Inputs:
|
|
// C #C by dim List of joint rest positions
|
|
// BE #BE by 2 list of bone edge indices into C
|
|
// T #BE*(dim+1) by dim matrix of stacked transposed bone transformations
|
|
// color #BE|1 by 4 list of color
|
|
// half_bbd half bounding box diagonal to determine scaling {1.0}
|
|
template <
|
|
typename DerivedC,
|
|
typename DerivedBE,
|
|
typename DerivedT,
|
|
typename Derivedcolor>
|
|
IGL_INLINE void draw_skeleton_3d(
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedBE> & BE,
|
|
const Eigen::PlainObjectBase<DerivedT> & T,
|
|
const Eigen::PlainObjectBase<Derivedcolor> & color,
|
|
const double half_bbd=0.5);
|
|
// Default color
|
|
template <typename DerivedC, typename DerivedBE, typename DerivedT>
|
|
IGL_INLINE void draw_skeleton_3d(
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedBE> & BE,
|
|
const Eigen::PlainObjectBase<DerivedT> & T);
|
|
template <typename DerivedC, typename DerivedBE>
|
|
IGL_INLINE void draw_skeleton_3d(
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedBE> & BE);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "draw_skeleton_3d.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_draw_skeleton_vector_graphics = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_DRAW_SKELETON_VECTOR_GRAPHICS_H
|
|
#define IGL_OPENGL2_DRAW_SKELETON_VECTOR_GRAPHICS_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Draw a skeleton with a 2D vector graphcis style à la BBW, STBS, Monotonic,
|
|
// FAST papers.
|
|
//
|
|
// Inputs:
|
|
// C #C by dim list of joint positions
|
|
// BE #BE by 2 list of bone edge indices into C
|
|
// point_color color of points
|
|
// line_color color of lines
|
|
IGL_INLINE void draw_skeleton_vector_graphics(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const float * point_color,
|
|
const float * line_color);
|
|
// Use default colors (originally from BBW paper)
|
|
IGL_INLINE void draw_skeleton_vector_graphics(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE);
|
|
// T #BE*(dim+1) by dim matrix of stacked transposed bone transformations
|
|
template <typename DerivedC, typename DerivedBE, typename DerivedT>
|
|
IGL_INLINE void draw_skeleton_vector_graphics(
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedBE> & BE,
|
|
const Eigen::PlainObjectBase<DerivedT> & T,
|
|
const float * point_color,
|
|
const float * line_color);
|
|
template <typename DerivedC, typename DerivedBE, typename DerivedT>
|
|
IGL_INLINE void draw_skeleton_vector_graphics(
|
|
const Eigen::PlainObjectBase<DerivedC> & C,
|
|
const Eigen::PlainObjectBase<DerivedBE> & BE,
|
|
const Eigen::PlainObjectBase<DerivedT> & T);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "draw_skeleton_vector_graphics.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_flare_textures = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_FLARE_TEXTURES_H
|
|
#define IGL_OPENGL2_FLARE_TEXTURES_H
|
|
#include <stdint.h>
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
|
|
const uint8_t FLARE_TEXTURE_0[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,20,20,20,20,23,23,23,23,23,23,23,23,23,23,23,23,23,23,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,20,20,20,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,20,20,23,23,28,28,28,28,28,28,28,31,31,31,31,31,31,31,31,31,31,31,31,31,31,28,28,28,28,28,28,28,28,23,23,20,20,20,20,15,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,20,23,28,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,31,28,28,28,28,28,23,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,15,20,20,20,23,23,28,28,28,28,31,31,36,36,36,36,36,36,36,36,39,39,39,39,39,39,39,39,39,39,39,39,39,36,36,36,36,36,36,36,36,31,28,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,31,36,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,44,44,47,47,47,47,47,47,47,47,47,47,47,47,47,44,44,44,44,44,44,44,39,39,36,36,36,36,31,31,28,28,28,23,23,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,28,31,31,36,36,36,36,39,44,44,44,44,44,47,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,44,44,39,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,28,28,31,36,36,36,39,44,44,44,44,44,47,47,52,52,52,52,52,52,52,55,55,55,55,55,55,55,55,55,55,55,55,55,52,52,52,52,52,52,52,47,47,44,44,44,44,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,52,47,47,44,44,44,39,39,36,36,36,31,28,28,28,23,20,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,55,55,60,60,60,60,60,60,60,63,63,63,63,63,63,63,63,63,63,63,63,60,60,60,60,60,60,60,60,55,52,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,15,20,20,23,28,28,28,36,36,36,39,44,44,44,47,47,52,52,52,55,55,60,60,60,60,60,63,63,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,63,63,63,60,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,20,23,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,63,68,68,68,68,68,68,68,71,71,71,71,71,71,71,71,71,71,71,71,68,68,68,68,68,68,68,63,63,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,28,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,20,28,28,28,31,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,68,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,71,71,68,68,68,68,68,63,63,60,60,60,55,55,52,52,52,47,44,44,39,36,36,36,31,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,36,39,44,44,47,52,52,52,55,60,60,60,63,63,68,68,68,68,71,76,76,76,76,76,76,76,79,79,79,79,79,79,79,79,79,79,79,79,76,76,76,76,76,76,76,71,71,68,68,68,68,63,60,60,60,55,52,52,52,47,44,44,44,39,36,36,31,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,39,44,44,44,47,52,52,55,60,60,60,63,63,68,68,68,71,71,76,76,76,76,79,79,79,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,79,79,76,76,76,76,76,71,68,68,68,68,63,60,60,60,55,52,52,52,47,44,44,39,36,36,31,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,79,79,84,84,84,84,84,84,84,87,87,87,87,87,87,87,87,87,87,87,84,84,84,84,84,84,84,79,76,76,76,76,71,71,68,68,68,63,60,60,60,55,52,52,47,44,44,44,36,36,36,28,28,28,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,39,44,44,47,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,79,84,84,84,84,84,87,87,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,87,87,84,84,84,84,84,79,76,76,76,71,71,68,68,68,60,60,60,55,52,52,52,44,44,44,36,36,36,28,28,28,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,31,36,36,39,44,44,47,52,52,55,60,60,63,68,68,68,71,76,76,76,79,79,84,84,84,84,87,92,92,92,92,92,92,92,95,95,95,95,95,95,95,95,95,95,95,92,92,92,92,92,92,87,87,84,84,84,84,79,76,76,76,71,68,68,68,63,60,60,60,52,52,52,47,44,44,39,36,36,28,28,28,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,31,36,36,39,44,44,47,52,52,55,60,60,63,68,68,68,71,76,76,79,79,84,84,84,87,92,92,92,92,92,95,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,92,87,84,84,84,84,79,76,76,76,71,68,68,68,60,60,60,55,52,52,47,44,44,39,36,36,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,31,36,36,39,44,44,52,52,52,60,60,60,63,68,68,71,76,76,76,79,84,84,84,87,92,92,92,92,95,100,100,100,100,100,100,100,103,103,103,103,103,103,103,103,103,103,100,100,100,100,100,100,100,95,95,92,92,92,87,87,84,84,84,79,76,76,71,68,68,68,63,60,60,55,52,52,47,44,44,39,36,36,28,28,23,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,28,28,31,36,36,39,44,44,52,52,52,60,60,60,68,68,68,71,76,76,79,84,84,84,87,92,92,92,95,95,100,100,100,100,103,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,100,100,100,100,100,95,92,92,92,87,84,84,84,79,76,76,76,71,68,68,63,60,60,55,52,52,47,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,23,28,31,36,36,39,44,44,52,52,52,60,60,63,68,68,68,76,76,76,79,84,84,87,92,92,92,95,95,100,100,100,103,103,108,108,108,108,108,108,111,111,111,111,111,111,111,111,111,111,108,108,108,108,108,108,108,103,100,100,100,100,95,92,92,92,87,84,84,84,79,76,76,71,68,68,63,60,60,55,52,52,47,44,44,36,36,31,28,28,23,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,44,47,52,52,60,60,63,68,68,71,76,76,79,84,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,111,108,108,108,108,103,103,100,100,100,95,92,92,92,87,84,84,79,76,76,71,68,68,63,60,60,55,52,52,47,44,44,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,31,36,39,44,44,47,52,52,60,60,63,68,68,71,76,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,111,116,116,116,116,116,116,119,119,119,119,119,119,119,119,119,119,116,116,116,116,116,116,111,111,108,108,108,103,103,100,100,100,95,92,92,87,84,84,79,76,76,71,68,68,63,60,60,55,52,52,44,44,39,36,36,31,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,36,44,44,47,52,52,60,60,63,68,68,71,76,76,79,84,84,87,92,92,92,100,100,100,103,108,108,108,111,111,116,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,87,84,84,84,76,76,76,68,68,63,60,60,55,52,52,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,47,52,52,55,60,60,68,68,71,76,76,79,84,84,87,92,92,95,100,100,100,108,108,108,111,116,116,116,116,119,119,124,124,124,124,124,124,127,127,127,127,127,127,127,127,127,124,124,124,124,124,124,119,116,116,116,116,111,108,108,108,103,100,100,100,92,92,92,84,84,84,76,76,76,68,68,63,60,60,55,52,47,44,44,39,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,39,44,44,52,52,55,60,60,68,68,71,76,76,79,84,84,87,92,92,95,100,100,103,108,108,108,111,116,116,116,119,124,124,124,124,127,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,119,119,116,116,116,111,108,108,103,100,100,100,95,92,92,87,84,84,76,76,71,68,68,63,60,60,52,52,47,44,44,36,36,31,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,28,28,31,36,36,44,44,47,52,55,60,60,63,68,68,76,76,79,84,84,87,92,92,95,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,132,135,135,135,135,135,135,135,135,135,132,132,132,132,132,132,127,124,124,124,119,119,116,116,111,108,108,108,103,100,100,95,92,92,87,84,84,76,76,71,68,68,63,60,55,52,52,44,44,39,36,36,28,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,39,44,47,52,52,60,60,63,68,68,76,76,79,84,84,87,92,92,100,100,100,108,108,108,111,116,116,119,124,124,124,127,127,132,132,132,132,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,87,84,84,76,76,71,68,68,60,60,55,52,52,44,44,39,36,31,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,39,44,44,52,52,55,60,63,68,68,71,76,79,84,84,87,92,92,100,100,100,108,108,108,116,116,116,119,124,124,124,127,132,132,132,135,140,140,140,140,140,140,143,143,143,143,143,143,143,143,140,140,140,140,140,140,135,135,132,132,132,127,124,124,124,119,116,116,111,108,108,103,100,100,95,92,92,84,84,79,76,76,71,68,63,60,60,52,52,47,44,44,36,36,28,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,44,44,47,52,55,60,60,68,68,71,76,76,84,84,87,92,92,95,100,100,108,108,111,116,116,116,124,124,124,127,132,132,132,135,140,140,140,140,143,143,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,103,100,100,95,92,92,84,84,79,76,76,68,68,63,60,55,52,52,44,44,39,36,31,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,28,28,31,36,39,44,44,52,52,60,60,63,68,68,76,76,79,84,87,92,92,95,100,100,108,108,111,116,116,119,124,124,124,132,132,132,135,140,140,140,143,143,148,148,148,148,148,151,151,151,151,151,151,151,151,148,148,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,103,100,100,92,92,87,84,84,79,76,71,68,68,60,60,55,52,47,44,44,36,36,31,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,31,36,36,44,44,47,52,55,60,60,68,68,71,76,79,84,84,92,92,95,100,100,108,108,111,116,116,119,124,124,127,132,132,132,140,140,140,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,111,108,108,103,100,100,92,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,31,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,28,28,31,36,39,44,47,52,52,60,60,63,68,71,76,76,84,84,87,92,92,100,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,140,143,148,148,148,151,156,156,156,156,156,156,159,159,159,159,159,159,159,156,156,156,156,156,151,151,148,148,148,143,140,140,135,132,132,132,124,124,119,116,116,111,108,108,100,100,95,92,92,84,84,79,76,76,68,68,60,60,55,52,47,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,44,44,47,52,55,60,63,68,68,76,76,79,84,87,92,92,100,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,156,159,164,164,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,151,148,148,143,140,140,140,132,132,132,124,124,119,116,116,111,108,108,100,100,95,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,31,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,44,52,52,60,60,63,68,71,76,79,84,84,92,92,95,100,100,108,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,151,156,156,156,159,159,164,164,164,164,164,167,167,167,167,167,167,167,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,103,100,100,92,92,87,84,79,76,76,68,68,63,60,55,52,47,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,47,52,55,60,63,68,68,76,76,79,84,87,92,92,100,100,108,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,151,156,156,159,164,164,164,164,167,167,172,172,172,172,172,172,172,172,172,172,172,167,164,164,164,164,159,156,156,156,151,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,103,100,95,92,92,84,84,79,76,71,68,63,60,60,52,52,44,44,39,36,31,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,36,44,44,52,52,60,60,63,68,71,76,79,84,84,92,92,95,100,103,108,108,116,116,119,124,124,132,132,135,140,140,143,148,148,156,156,156,159,164,164,164,167,172,172,172,172,172,175,175,175,175,175,175,175,172,172,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,111,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,31,36,39,44,47,52,55,60,60,68,68,76,76,79,84,87,92,95,100,100,108,108,111,116,119,124,124,132,132,135,140,140,143,148,148,156,156,156,164,164,164,167,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,108,108,103,100,95,92,92,84,84,79,76,71,68,63,60,60,52,52,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,52,52,55,60,63,68,71,76,76,84,84,92,92,95,100,103,108,111,116,116,124,124,127,132,132,140,140,143,148,148,156,156,156,164,164,164,172,172,172,175,180,180,180,180,180,183,183,183,183,183,183,180,180,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,132,124,124,119,116,111,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,52,52,47,44,39,36,31,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,44,52,52,60,60,68,68,71,76,79,84,87,92,95,100,100,108,108,116,116,119,124,124,132,132,140,140,143,148,148,156,156,156,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,188,188,188,188,188,188,183,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,124,116,116,111,108,103,100,95,92,92,84,84,76,76,71,68,63,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,47,52,55,60,63,68,68,76,76,84,84,92,92,95,100,103,108,111,116,116,124,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,180,183,188,188,188,188,191,191,191,191,191,191,188,188,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,127,124,119,116,111,108,108,100,100,92,92,87,84,79,76,71,68,63,60,60,52,52,44,44,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,47,52,55,60,63,68,71,76,79,84,84,92,92,100,100,108,108,111,116,119,124,127,132,132,140,140,143,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,188,191,191,196,196,196,196,196,196,196,196,196,191,188,188,188,183,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,111,108,103,100,95,92,87,84,84,76,76,68,68,60,60,52,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,79,84,87,92,95,100,103,108,108,116,116,124,124,127,132,135,140,143,148,148,156,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,196,196,199,199,199,199,199,196,196,196,196,191,188,188,188,180,180,180,172,172,167,164,164,156,156,151,148,143,140,140,132,132,127,124,119,116,111,108,108,100,100,92,92,84,84,76,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,52,60,60,68,68,76,76,84,84,92,92,100,100,103,108,111,116,119,124,124,132,132,140,140,148,148,151,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,204,204,204,204,204,204,199,199,196,196,196,191,188,188,180,180,180,172,172,167,164,159,156,156,148,148,143,140,135,132,127,124,124,116,116,108,108,100,100,95,92,87,84,79,76,71,68,63,60,55,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,84,92,92,100,100,108,108,116,116,119,124,127,132,135,140,143,148,148,156,156,164,164,167,172,172,180,180,183,188,188,191,196,196,199,204,204,204,204,207,207,207,207,207,204,204,204,204,196,196,196,191,188,188,180,180,175,172,172,164,164,159,156,151,148,143,140,140,132,132,124,124,119,116,111,108,103,100,95,92,87,84,79,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,108,116,116,124,124,132,132,140,140,143,148,151,156,159,164,164,172,172,175,180,183,188,188,191,196,196,199,204,204,207,212,212,212,212,212,212,212,212,207,204,204,204,199,196,196,191,188,188,180,180,175,172,167,164,164,156,156,148,148,140,140,135,132,127,124,119,116,111,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,132,140,140,148,148,156,156,159,164,167,172,175,180,180,188,188,191,196,196,204,204,204,207,212,212,212,215,215,215,215,212,212,212,212,207,204,204,199,196,196,188,188,183,180,180,172,172,164,164,159,156,151,148,143,140,135,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,100,100,108,108,111,116,119,124,127,132,135,140,143,148,151,156,156,164,164,172,172,180,180,183,188,191,196,196,199,204,204,212,212,212,215,220,220,220,220,220,220,220,215,212,212,207,204,204,199,196,191,188,188,180,180,175,172,167,164,159,156,156,148,148,140,140,132,132,124,124,116,116,108,108,103,100,95,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,7,12,15,20,23,28,31,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,100,100,108,108,116,116,124,124,132,132,140,140,143,148,151,156,159,164,167,172,175,180,180,188,188,196,196,199,204,204,212,212,215,220,220,220,220,223,223,223,220,220,220,215,212,212,207,204,204,196,196,191,188,183,180,175,172,172,164,164,156,156,148,148,140,140,135,132,127,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,84,92,92,100,100,108,108,116,116,124,124,132,132,140,140,148,148,156,156,164,164,167,172,175,180,183,188,191,196,196,204,204,207,212,215,220,220,223,228,228,228,228,228,228,223,220,220,215,212,212,207,204,199,196,196,188,188,180,180,172,172,164,164,159,156,151,148,143,140,135,132,127,124,119,116,111,108,103,100,95,92,87,84,79,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,124,132,132,140,140,148,148,156,156,164,164,172,172,180,180,188,188,191,196,199,204,207,212,212,220,220,223,228,228,228,231,231,231,228,228,228,220,220,215,212,212,204,204,196,196,188,188,183,180,175,172,167,164,159,156,151,148,143,140,135,132,127,124,119,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,156,164,164,172,172,180,180,188,188,196,196,204,204,212,212,215,220,223,228,228,231,236,236,236,236,236,228,228,223,220,220,212,212,207,204,199,196,191,188,183,180,175,172,167,164,159,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,196,204,204,212,212,220,220,228,228,231,236,236,239,239,236,236,236,228,228,223,220,215,212,207,204,199,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,220,228,228,236,236,239,244,244,244,239,236,231,228,223,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,244,247,244,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,247,252,244,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,236,244,244,244,244,239,236,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,212,220,220,228,228,236,236,239,244,244,239,236,236,231,228,223,220,215,212,207,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,180,188,188,196,196,204,204,212,212,220,220,223,228,228,236,236,236,236,236,236,231,228,228,220,220,215,212,207,204,199,196,191,188,183,180,175,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,140,148,148,156,156,164,164,172,172,180,180,188,188,196,196,199,204,207,212,215,220,220,228,228,228,231,236,236,236,231,228,228,223,220,220,212,212,204,204,199,196,191,188,183,180,175,172,167,164,159,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,100,108,108,116,116,124,124,132,132,140,140,148,148,156,156,164,164,172,172,180,180,183,188,191,196,199,204,204,212,212,215,220,220,223,228,228,228,228,228,228,228,223,220,220,212,212,207,204,204,196,196,188,188,180,180,175,172,167,164,159,156,151,148,143,140,135,132,127,124,119,116,111,108,103,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,60,68,68,76,76,84,84,92,92,100,100,108,108,116,116,124,124,132,132,140,140,148,148,151,156,159,164,167,172,175,180,183,188,188,196,196,204,204,207,212,212,215,220,220,223,223,228,228,228,223,220,220,220,215,212,212,204,204,199,196,191,188,188,180,180,172,172,164,164,156,156,151,148,143,140,135,132,127,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,63,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,100,100,108,108,116,116,124,124,127,132,135,140,143,148,151,156,159,164,164,172,172,180,180,188,188,191,196,196,204,204,207,212,212,215,220,220,220,220,220,220,220,220,220,212,212,212,204,204,199,196,196,188,188,183,180,175,172,167,164,164,156,156,148,148,140,140,132,132,124,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,148,156,156,164,164,172,172,175,180,183,188,188,196,196,199,204,204,207,212,212,212,215,220,220,220,220,215,215,212,212,212,204,204,204,196,196,191,188,188,180,180,172,172,167,164,159,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,100,92,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,124,132,132,140,140,148,148,151,156,159,164,167,172,172,180,180,183,188,191,196,196,199,204,204,207,212,212,212,212,212,212,212,212,212,212,207,204,204,204,196,196,191,188,188,180,180,175,172,172,164,164,156,156,151,148,143,140,135,132,127,124,119,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,92,100,100,108,108,116,116,124,124,132,132,135,140,143,148,151,156,156,164,164,167,172,175,180,180,188,188,191,196,196,199,204,204,204,207,207,212,212,212,212,207,207,204,204,204,199,196,196,191,188,188,183,180,180,172,172,167,164,159,156,156,148,148,140,140,132,132,127,124,119,116,111,108,103,100,95,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,68,76,76,84,84,92,92,100,100,108,108,111,116,119,124,127,132,135,140,140,148,148,156,156,159,164,164,172,172,175,180,180,188,188,191,196,196,196,199,204,204,204,204,204,204,204,204,204,204,204,199,196,196,191,188,188,183,180,180,175,172,167,164,164,156,156,151,148,143,140,135,132,132,124,124,116,116,108,108,103,100,95,92,87,84,79,76,71,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,36,44,44,52,52,60,60,68,68,76,76,84,84,87,92,95,100,103,108,111,116,116,124,124,132,132,140,140,143,148,151,156,156,164,164,167,172,172,180,180,180,188,188,188,191,196,196,196,199,199,204,204,204,204,204,199,199,196,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,151,148,148,140,140,135,132,127,124,119,116,116,108,108,100,100,92,92,84,84,79,76,71,68,63,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,63,68,71,76,79,84,87,92,95,100,100,108,108,116,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,180,180,180,188,188,188,191,196,196,196,196,196,196,196,196,196,196,196,196,191,188,188,188,183,180,180,175,172,172,167,164,159,156,156,148,148,143,140,140,132,132,124,124,119,116,111,108,103,100,95,92,92,84,84,76,76,68,68,60,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,39,44,47,52,55,60,63,68,71,76,76,84,84,92,92,100,100,103,108,111,116,119,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,183,188,188,188,188,191,196,196,196,196,196,196,191,191,188,188,188,188,180,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,124,116,116,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,52,52,44,44,36,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,52,60,60,68,68,76,76,84,84,87,92,95,100,103,108,108,116,116,119,124,127,132,132,140,140,143,148,151,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,188,188,188,188,188,188,188,188,188,188,183,180,180,180,175,172,172,167,164,164,156,156,151,148,148,143,140,135,132,132,124,124,119,116,111,108,103,100,100,92,92,84,84,79,76,71,68,63,60,55,52,52,44,44,36,36,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,44,44,52,52,60,60,63,68,71,76,79,84,84,92,92,100,100,103,108,111,116,119,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,180,183,183,188,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,127,124,119,116,116,108,108,103,100,95,92,87,84,84,76,76,68,68,60,60,55,52,47,44,39,36,31,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,39,44,47,52,55,60,63,68,68,76,76,84,84,87,92,95,100,103,108,108,116,116,119,124,127,132,132,135,140,143,148,148,151,156,156,159,164,164,167,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,175,172,172,172,167,164,164,164,156,156,156,148,148,143,140,140,135,132,127,124,124,116,116,111,108,103,100,100,92,92,87,84,79,76,71,68,68,60,60,52,52,44,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,47,52,52,60,60,68,68,71,76,79,84,87,92,92,100,100,103,108,111,116,116,124,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,180,175,175,175,172,172,172,172,167,164,164,159,156,156,156,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,100,100,95,92,87,84,84,76,76,68,68,63,60,55,52,47,44,44,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,44,44,52,52,55,60,63,68,71,76,76,84,84,87,92,95,100,100,108,108,111,116,119,124,124,127,132,132,140,140,143,148,148,151,156,156,156,159,164,164,164,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,159,156,156,151,148,148,143,140,140,135,132,132,127,124,119,116,116,111,108,103,100,100,92,92,87,84,79,76,71,68,68,60,60,52,52,47,44,39,36,31,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,31,36,39,44,47,52,52,60,60,68,68,71,76,79,84,84,92,92,100,100,103,108,108,116,116,119,124,124,132,132,135,140,140,143,148,148,148,156,156,156,159,164,164,164,164,164,167,167,172,172,172,172,172,172,172,167,167,164,164,164,164,159,156,156,156,151,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,108,100,100,95,92,87,84,84,76,76,71,68,63,60,55,52,52,44,44,36,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,31,36,36,44,44,52,52,55,60,63,68,71,76,76,84,84,87,92,95,100,100,103,108,111,116,116,119,124,124,132,132,135,140,140,140,148,148,148,151,156,156,156,159,159,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,111,108,108,103,100,95,92,92,84,84,79,76,71,68,68,60,60,55,52,47,44,39,36,36,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,39,44,47,52,55,60,60,68,68,71,76,79,84,84,92,92,95,100,100,108,108,111,116,116,119,124,124,132,132,132,140,140,140,143,148,148,148,151,156,156,156,156,159,159,159,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,100,92,92,87,84,84,76,76,68,68,63,60,55,52,52,44,44,36,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,44,52,52,55,60,63,68,68,76,76,79,84,87,92,92,100,100,103,108,108,111,116,116,119,124,124,132,132,132,135,140,140,143,143,148,148,148,151,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,100,95,92,87,84,84,79,76,71,68,68,60,60,55,52,47,44,39,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,39,44,47,52,52,60,60,68,68,71,76,76,84,84,87,92,92,100,100,103,108,108,111,116,116,119,124,124,127,132,132,135,140,140,140,143,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,151,151,151,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,92,84,84,79,76,76,68,68,63,60,55,52,52,44,44,39,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,36,44,44,52,52,55,60,60,68,68,71,76,79,84,84,87,92,95,100,100,103,108,108,111,116,116,119,124,124,127,132,132,132,135,140,140,140,140,143,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,127,124,124,124,119,116,116,111,108,108,100,100,95,92,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,39,44,47,52,52,60,60,63,68,68,76,76,79,84,84,92,92,95,100,100,103,108,108,111,116,116,119,124,124,124,127,132,132,132,135,140,140,140,140,140,143,143,148,148,148,148,148,148,148,148,143,143,143,140,140,140,140,135,135,132,132,132,127,124,124,119,116,116,116,108,108,108,100,100,95,92,92,87,84,84,76,76,71,68,68,60,60,55,52,52,44,44,36,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,36,44,44,47,52,55,60,60,68,68,71,76,76,79,84,84,92,92,95,100,100,103,108,108,111,116,116,116,124,124,124,127,132,132,132,132,135,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,132,132,132,132,127,124,124,124,119,116,116,111,108,108,108,100,100,100,92,92,87,84,84,79,76,76,68,68,63,60,55,52,52,44,44,39,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,39,44,44,52,52,55,60,60,68,68,71,76,76,84,84,87,92,92,95,100,100,103,108,108,108,116,116,116,119,124,124,124,127,127,132,132,132,132,135,135,135,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,87,84,84,79,76,76,68,68,63,60,60,52,52,47,44,44,36,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,28,36,36,39,44,47,52,52,60,60,63,68,68,71,76,76,84,84,87,92,92,95,100,100,100,108,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,44,44,39,36,31,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,36,44,44,47,52,52,60,60,63,68,68,71,76,76,84,84,87,92,92,92,100,100,100,103,108,108,108,111,116,116,116,119,124,124,124,124,124,127,127,127,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,124,119,119,116,116,116,111,108,108,108,103,100,100,95,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,44,44,39,36,36,28,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,39,44,44,52,52,55,60,60,63,68,68,76,76,76,84,84,84,92,92,92,95,100,100,103,108,108,108,111,111,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,47,44,44,36,36,31,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,44,52,52,55,60,60,63,68,68,76,76,76,84,84,84,87,92,92,95,100,100,100,103,108,108,108,111,111,116,116,116,116,116,119,119,119,124,124,124,124,124,124,124,124,124,119,119,119,116,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,92,87,84,84,79,76,76,71,68,68,63,60,60,52,52,47,44,44,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,36,44,44,47,52,52,55,60,60,63,68,68,71,76,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,108,108,108,108,103,103,100,100,100,95,92,92,87,84,84,84,79,76,76,71,68,68,63,60,60,52,52,47,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,28,28,31,36,36,44,44,47,52,52,55,60,60,63,68,68,71,76,76,79,84,84,84,87,92,92,95,95,100,100,100,103,108,108,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,111,111,111,108,108,108,108,108,103,100,100,100,100,95,92,92,92,87,84,84,84,76,76,76,71,68,68,63,60,60,52,52,47,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,31,36,36,44,44,47,52,52,55,60,60,63,68,68,71,76,76,79,84,84,84,87,92,92,92,95,95,100,100,100,100,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,100,100,100,100,95,92,92,92,87,84,84,84,79,76,76,76,68,68,68,60,60,60,52,52,52,44,44,39,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,44,47,52,52,55,60,60,63,68,68,71,76,76,76,79,84,84,84,87,92,92,92,92,95,100,100,100,100,100,103,103,103,108,108,108,108,108,108,108,108,108,108,103,103,103,100,100,100,100,100,95,95,92,92,92,87,87,84,84,84,79,76,76,71,68,68,68,60,60,60,52,52,52,44,44,39,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,36,36,39,44,44,47,52,52,55,60,60,63,68,68,68,71,76,76,76,79,84,84,84,87,92,92,92,92,95,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,87,87,84,84,84,79,76,76,76,71,68,68,63,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,36,36,39,44,44,47,52,52,55,60,60,60,63,68,68,71,76,76,76,79,79,84,84,84,87,87,92,92,92,92,92,95,95,95,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,92,92,87,84,84,84,84,79,76,76,76,71,68,68,68,63,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,28,36,36,39,44,44,44,52,52,52,55,60,60,63,68,68,68,71,76,76,76,79,79,84,84,84,84,87,87,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,87,84,84,84,84,84,79,76,76,76,71,68,68,68,63,60,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,28,36,36,36,44,44,44,47,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,79,84,84,84,84,84,84,87,87,87,92,92,92,92,92,92,92,92,92,92,92,87,87,87,84,84,84,84,84,79,79,76,76,76,71,71,68,68,68,63,60,60,55,52,52,52,47,44,44,39,36,36,31,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,28,36,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,76,79,79,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,79,79,76,76,76,76,71,68,68,68,68,63,60,60,60,55,52,52,52,44,44,44,39,36,36,31,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,31,36,36,39,44,44,44,52,52,52,55,60,60,60,63,63,68,68,68,71,71,76,76,76,76,76,76,79,79,79,84,84,84,84,84,84,84,84,84,84,84,79,79,79,76,76,76,76,76,76,71,68,68,68,68,63,60,60,60,55,52,52,52,47,44,44,44,36,36,36,31,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,31,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,71,71,68,68,68,68,68,63,60,60,60,55,55,52,52,52,44,44,44,39,36,36,36,28,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,63,68,68,68,68,68,71,71,71,76,76,76,76,76,76,76,76,76,76,76,76,71,71,71,68,68,68,68,68,68,63,60,60,60,60,55,55,52,52,52,47,44,44,44,39,36,36,31,28,28,28,20,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,28,31,36,36,39,44,44,44,47,47,52,52,52,55,60,60,60,60,60,63,63,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,63,60,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,23,20,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,31,36,36,36,39,44,44,44,47,47,52,52,52,52,55,60,60,60,60,60,60,63,63,63,68,68,68,68,68,68,68,68,68,68,68,68,63,63,63,60,60,60,60,60,60,55,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,47,47,44,44,44,39,39,36,36,36,31,28,28,23,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,47,52,52,52,52,52,52,55,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,55,52,52,52,52,52,52,47,44,44,44,44,39,36,36,36,36,31,28,28,28,23,20,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,20,23,28,28,28,31,31,36,36,36,39,39,44,44,44,44,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,44,44,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,47,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,47,44,44,44,44,44,44,39,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,36,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,31,31,28,28,28,23,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,28,28,28,31,36,36,36,36,36,36,39,39,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,39,36,36,36,36,36,36,31,31,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,23,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,20,23,23,28,28,28,28,28,28,31,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,31,28,28,28,28,28,28,28,23,20,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,20,20,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,20,20,23,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,23,20,20,20,20,20,20,15,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,12,12,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t FLARE_TEXTURE_1[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,15,15,15,15,15,15,15,15,15,15,15,15,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,15,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,15,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,20,20,20,23,23,23,23,23,20,20,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,23,23,23,23,28,28,28,28,28,28,28,28,28,23,23,23,23,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,15,15,20,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,20,20,20,20,20,20,15,15,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,31,31,31,31,31,31,31,31,28,28,28,28,28,28,28,28,23,23,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,23,23,28,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,31,31,31,28,28,28,28,28,28,23,20,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,20,20,23,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,28,23,23,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,23,28,28,28,28,28,31,36,36,36,36,36,39,39,39,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,23,28,28,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,39,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,23,23,28,28,28,31,36,36,36,36,39,44,44,44,44,44,47,47,52,52,52,52,52,52,52,52,47,47,47,44,44,44,44,39,39,36,36,36,31,28,28,28,28,23,20,20,20,20,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,23,28,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,39,39,36,36,36,31,28,28,28,23,20,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,55,55,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,60,63,63,63,63,63,63,60,60,60,60,60,55,55,52,52,52,47,44,44,44,39,36,36,31,28,28,28,23,20,20,20,15,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,68,68,68,68,68,68,68,68,68,63,60,60,60,60,55,52,52,47,44,44,44,39,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,23,28,28,31,36,36,36,44,44,44,47,52,52,55,60,60,60,63,68,68,68,71,71,76,76,76,76,76,76,71,71,68,68,68,68,63,60,60,60,52,52,52,47,44,44,39,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,36,44,44,44,52,52,52,60,60,60,63,68,68,71,76,76,76,76,76,79,79,79,79,76,76,76,76,76,71,68,68,68,63,60,60,55,52,52,47,44,44,39,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,28,36,36,36,44,44,44,52,52,55,60,60,63,68,68,71,76,76,76,79,84,84,84,84,84,84,84,84,84,84,84,79,76,76,76,68,68,68,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,28,28,28,31,36,36,39,44,44,52,52,55,60,60,68,68,68,76,76,79,84,84,84,87,87,92,92,92,92,92,92,92,87,84,84,84,79,76,76,71,68,68,63,60,60,52,52,47,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,44,52,52,55,60,60,68,68,71,76,76,84,84,84,92,92,92,95,95,100,100,100,100,95,95,92,92,92,87,84,84,79,76,76,68,68,63,60,60,52,52,47,44,44,36,36,36,28,28,28,23,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,23,28,28,28,36,36,39,44,44,47,52,55,60,60,68,68,71,76,79,84,84,92,92,95,100,100,100,100,103,103,103,103,103,100,100,100,95,92,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,52,60,60,68,68,76,76,79,84,87,92,92,100,100,103,108,108,108,108,111,111,108,108,108,108,103,100,100,95,92,92,84,84,76,76,71,68,63,60,55,52,52,44,44,39,36,36,28,28,28,23,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,28,36,36,39,44,44,52,52,60,60,68,68,71,76,84,84,87,92,95,100,103,108,108,111,116,116,116,116,116,116,116,116,116,111,108,108,100,100,92,92,87,84,76,76,68,68,63,60,55,52,47,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,55,60,63,68,71,76,79,84,92,92,100,100,108,108,116,116,119,124,124,124,124,124,124,124,124,119,116,116,111,108,103,100,95,92,87,84,76,76,68,68,60,60,52,52,44,44,39,36,36,28,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,28,28,28,36,36,39,44,44,52,52,60,60,68,68,76,79,84,87,92,100,100,108,111,116,119,124,124,127,132,132,132,132,132,132,132,127,124,124,116,116,108,103,100,95,92,84,84,76,76,68,63,60,55,52,47,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,47,52,55,60,63,68,76,76,84,87,92,100,100,108,111,116,124,124,132,132,135,140,140,140,140,140,140,140,132,132,127,124,119,116,108,108,100,95,92,84,79,76,71,68,60,60,52,52,44,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,39,44,44,52,52,60,60,68,71,76,84,84,92,95,100,108,111,116,124,127,132,135,140,143,148,148,148,148,148,148,148,140,140,132,132,124,119,116,108,103,100,92,87,84,76,76,68,63,60,55,52,47,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,28,36,36,39,44,47,52,55,60,63,68,76,79,84,92,92,100,108,111,116,124,127,132,140,143,148,151,156,156,156,156,156,156,156,148,148,140,135,132,124,119,116,108,103,100,92,84,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,84,92,100,103,108,116,124,127,132,140,143,148,156,159,164,164,167,167,164,164,164,156,151,148,140,135,132,124,116,111,108,100,95,92,84,76,76,68,63,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,39,44,44,52,52,60,63,68,76,76,84,92,95,100,108,116,119,124,132,140,143,151,156,164,167,172,172,175,175,175,172,172,164,159,156,148,140,135,127,124,116,108,103,100,92,84,84,76,68,68,60,55,52,47,44,39,36,36,31,28,28,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,68,68,76,79,84,92,100,103,108,116,124,132,135,143,148,156,164,172,175,180,183,188,188,183,180,180,172,164,159,156,148,140,132,124,119,116,108,100,92,87,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,68,71,76,84,87,92,100,108,111,119,124,132,140,148,156,164,172,175,180,188,191,196,196,196,188,188,180,172,164,156,151,143,135,132,124,116,108,100,95,92,84,79,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,87,95,100,108,116,124,127,135,143,151,159,167,175,180,188,196,204,204,204,204,199,196,188,180,172,164,156,148,140,132,124,116,111,103,100,92,84,79,76,68,63,60,55,52,47,44,39,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,52,60,63,68,76,76,84,92,95,100,108,116,124,132,140,148,156,164,172,180,188,196,204,212,215,220,212,207,199,191,183,175,167,156,148,140,132,127,119,111,108,100,92,87,84,76,68,68,60,55,52,47,44,39,36,36,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,108,116,124,132,140,148,156,164,172,183,191,204,212,220,228,228,223,215,204,196,188,180,172,164,151,143,135,127,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,111,116,124,132,140,148,156,167,175,188,196,204,215,228,236,236,231,220,212,199,188,180,172,164,156,148,140,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,111,116,124,132,140,148,156,167,175,188,196,204,220,228,236,244,236,220,212,204,191,180,172,164,156,148,140,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,108,116,124,132,140,148,156,164,175,183,196,204,212,223,231,236,228,220,212,199,188,180,172,164,156,148,135,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,76,84,92,95,103,108,116,124,132,140,148,156,164,172,180,188,199,207,215,220,220,220,212,204,196,188,180,167,159,151,143,135,127,119,116,108,100,92,87,84,76,68,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,92,95,100,108,116,124,132,140,148,156,164,172,180,188,196,199,204,212,212,212,204,196,188,180,172,164,156,148,140,132,124,116,111,108,100,92,84,79,76,68,68,60,55,52,47,44,39,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,28,36,36,44,44,47,52,60,60,68,71,76,84,87,92,100,108,116,119,127,132,140,148,156,164,172,180,188,191,196,199,204,199,196,188,183,175,167,164,156,148,140,132,124,116,108,103,100,92,84,79,76,68,63,60,55,52,44,44,39,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,68,68,76,84,84,92,100,103,111,116,124,132,140,148,151,159,164,172,180,183,188,188,191,188,188,180,175,172,164,156,148,140,132,127,124,116,108,100,95,92,84,76,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,20,20,20,23,28,28,31,36,39,44,47,52,55,60,63,68,76,79,84,92,95,100,108,116,124,127,132,140,148,156,159,164,172,175,180,180,180,180,180,172,167,164,156,148,143,140,132,124,116,111,108,100,92,87,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,87,92,100,108,111,116,124,132,135,140,148,156,156,164,167,172,172,172,172,167,164,164,156,148,148,140,132,124,119,116,108,100,95,92,84,79,76,68,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,47,52,55,60,68,68,76,79,84,92,95,100,108,116,119,124,132,135,140,148,151,156,156,164,164,164,164,159,156,156,148,143,140,132,127,124,116,108,103,100,92,87,84,76,71,68,63,60,52,52,44,44,39,36,31,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,63,68,76,76,84,87,92,100,103,108,116,119,124,132,135,140,143,148,148,151,156,156,156,151,148,148,140,140,132,127,124,116,111,108,100,95,92,84,79,76,68,68,60,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,52,52,60,60,68,68,76,79,84,92,92,100,103,108,116,119,124,127,132,135,140,140,143,148,148,148,143,140,140,132,132,124,124,116,111,108,100,100,92,87,84,76,71,68,63,60,55,52,47,44,39,36,36,28,28,28,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,39,44,47,52,55,60,63,68,71,76,84,84,92,95,100,108,108,116,116,124,124,132,132,132,135,140,140,135,135,132,132,127,124,119,116,111,108,100,100,92,87,84,79,76,68,68,60,60,52,52,44,44,39,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,44,52,52,60,60,68,68,76,76,84,87,92,95,100,103,108,111,116,119,124,124,127,127,132,132,132,127,124,124,124,116,116,108,108,100,100,92,92,84,79,76,71,68,63,60,55,52,47,44,39,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,47,52,52,60,60,68,68,76,76,84,87,92,95,100,103,108,108,116,116,116,119,124,124,124,124,119,116,116,116,111,108,103,100,100,92,92,84,79,76,71,68,63,60,55,52,52,44,44,39,36,36,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,28,28,28,36,36,39,44,44,47,52,55,60,63,68,71,76,76,84,84,92,92,100,100,103,108,108,111,111,116,116,116,116,116,111,108,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,52,52,47,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,44,52,52,55,60,63,68,71,76,76,84,84,87,92,95,100,100,100,103,108,108,108,108,108,108,108,103,100,100,95,92,92,87,84,79,76,76,68,68,60,60,55,52,47,44,44,36,36,31,28,28,28,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,52,60,60,63,68,68,76,76,79,84,84,92,92,92,95,100,100,100,100,100,100,100,100,100,95,92,92,87,84,84,79,76,71,68,68,60,60,55,52,52,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,28,36,36,39,44,44,47,52,52,60,60,63,68,68,76,76,76,84,84,84,87,92,92,92,92,92,92,92,92,92,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,44,47,52,52,60,60,63,68,68,71,76,76,76,84,84,84,84,87,87,87,87,87,87,84,84,84,84,79,76,76,71,68,68,63,60,60,55,52,52,44,44,44,36,36,31,28,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,15,20,20,20,28,28,28,31,36,36,39,44,44,47,52,52,55,60,60,63,68,68,71,76,76,76,79,79,84,84,84,84,84,84,79,79,76,76,76,71,68,68,68,63,60,60,55,52,52,44,44,44,36,36,36,28,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,39,44,44,47,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,76,76,76,76,76,76,76,71,68,68,68,63,60,60,55,52,52,52,44,44,44,36,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,68,68,71,71,71,71,68,68,68,68,68,68,63,60,60,60,55,52,52,47,44,44,44,36,36,36,31,28,28,23,20,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,23,28,28,28,31,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,63,68,68,68,68,68,68,68,63,63,60,60,60,60,55,52,52,52,47,44,44,39,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,55,55,55,55,55,55,55,55,55,52,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,28,23,20,20,20,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,20,23,28,28,28,31,36,36,36,36,39,44,44,44,44,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,47,44,44,44,44,39,39,36,36,36,31,28,28,28,23,23,20,20,20,15,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,15,20,20,20,20,23,28,28,28,28,31,36,36,36,36,39,44,44,44,44,44,44,47,47,47,47,47,47,47,47,44,44,44,44,44,44,39,39,36,36,36,31,31,28,28,28,23,20,20,20,20,15,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,20,23,23,28,28,28,28,31,36,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,15,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,23,28,28,28,28,28,31,36,36,36,36,36,36,36,39,39,39,39,39,39,39,39,39,36,36,36,36,36,36,31,31,28,28,28,28,23,23,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,23,23,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,28,28,28,23,20,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,15,20,20,20,20,20,23,23,28,28,28,28,28,28,31,31,31,31,36,36,36,36,36,36,31,31,31,31,28,28,28,28,28,28,23,23,20,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,15,15,20,20,20,20,20,23,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,20,20,20,20,20,20,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,15,15,20,20,20,20,20,20,23,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,23,23,23,23,23,23,23,23,23,23,23,23,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,15,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,15,15,15,15,15,15,20,20,20,20,20,15,15,15,15,15,15,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t FLARE_TEXTURE_2[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,20,23,28,28,28,28,28,28,28,28,28,28,23,23,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,39,39,39,36,36,36,36,28,28,23,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,28,31,36,36,39,44,44,44,47,47,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,44,36,36,36,28,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,28,36,36,39,44,44,47,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,47,44,44,39,36,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,36,36,44,44,47,52,52,55,60,60,60,60,63,63,68,68,68,68,68,68,68,68,68,68,68,68,68,68,63,63,60,60,60,60,55,52,52,52,44,44,39,36,31,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,31,36,44,44,47,52,52,60,60,60,63,68,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,71,71,68,68,68,68,68,63,60,60,60,55,52,52,47,44,39,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,47,52,52,60,60,60,63,68,68,68,71,76,76,76,76,76,76,79,79,79,79,84,84,84,84,84,79,79,79,79,76,76,76,76,76,71,71,68,68,68,63,60,60,55,52,52,44,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,52,52,55,60,60,63,68,68,71,76,76,76,76,79,79,84,84,84,84,84,84,84,84,84,87,87,87,84,84,84,84,84,84,84,84,84,79,79,76,76,76,71,68,68,68,63,60,60,52,52,47,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,39,44,52,52,60,60,63,68,68,71,76,76,76,79,84,84,84,84,84,87,87,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,87,87,84,84,84,84,79,76,76,76,71,68,68,68,60,60,55,52,47,44,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,31,36,44,52,52,60,60,63,68,68,76,76,76,79,84,84,84,84,87,92,92,92,92,92,92,95,95,95,100,100,100,100,100,100,100,100,95,95,95,95,92,92,92,92,92,92,87,84,84,84,79,76,76,76,71,68,68,60,60,55,52,47,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,44,47,52,60,60,63,68,71,76,76,76,84,84,84,87,92,92,92,92,92,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,87,84,84,84,79,76,76,71,68,68,63,60,55,52,44,39,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,39,44,52,55,60,63,68,71,76,76,79,84,84,84,87,92,92,92,95,100,100,100,100,100,100,103,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,103,100,100,100,100,100,95,92,92,92,92,87,84,84,79,76,76,71,68,68,60,60,52,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,44,52,52,60,63,68,68,76,76,79,84,84,87,92,92,92,95,100,100,100,100,103,103,108,108,108,108,108,108,108,108,111,111,111,111,111,111,111,111,111,108,108,108,108,108,108,108,108,103,100,100,100,100,95,92,92,92,87,84,84,84,76,76,71,68,68,60,55,52,44,39,36,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,39,44,52,55,60,68,68,76,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,108,111,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,111,108,108,108,108,108,103,100,100,100,100,95,92,92,87,84,84,79,76,76,71,68,63,60,52,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,36,44,47,52,60,63,68,71,76,76,84,84,87,92,92,92,100,100,100,103,103,108,108,108,108,111,116,116,116,116,116,116,116,116,119,119,119,119,119,119,119,119,119,119,119,116,116,116,116,116,116,116,111,111,108,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,76,68,68,60,55,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,52,55,60,68,68,76,76,79,84,84,92,92,92,100,100,100,103,108,108,108,108,111,116,116,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,116,111,111,108,108,108,103,100,100,100,95,92,92,87,84,84,76,76,71,68,63,60,52,47,39,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,52,60,60,68,71,76,76,84,84,87,92,92,95,100,100,103,108,108,108,111,116,116,116,116,119,119,124,124,124,124,124,124,124,124,127,127,127,127,127,127,127,127,127,127,127,124,124,124,124,124,124,124,119,119,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,84,84,79,76,76,68,63,60,52,47,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,52,60,63,68,71,76,79,84,84,92,92,95,100,100,103,108,108,108,111,116,116,116,116,119,124,124,124,124,124,127,127,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,124,119,119,116,116,116,111,111,108,108,103,100,100,100,92,92,87,84,84,76,76,68,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,39,44,52,60,63,68,76,76,84,84,87,92,92,100,100,100,108,108,108,111,116,116,116,119,124,124,124,124,124,127,132,132,132,132,132,132,132,132,132,135,135,135,135,135,135,135,135,135,132,132,132,132,132,132,132,132,127,127,124,124,124,124,119,116,116,116,111,108,108,108,103,100,100,95,92,92,84,84,79,76,71,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,39,47,52,60,63,68,76,76,84,84,92,92,95,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,132,135,135,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,135,135,132,132,132,132,132,127,127,124,124,124,119,116,116,116,111,108,108,108,100,100,100,92,92,87,84,79,76,71,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,47,52,60,68,68,76,76,84,84,92,92,95,100,100,108,108,108,111,116,116,119,124,124,124,124,127,132,132,132,132,135,135,140,140,140,140,140,140,140,140,140,140,140,143,143,140,140,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,87,84,84,76,71,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,52,60,68,68,76,79,84,87,92,92,100,100,103,108,108,111,116,116,116,119,124,124,124,127,132,132,132,132,135,140,140,140,140,140,140,143,143,143,148,148,148,148,148,148,148,148,148,148,148,148,143,143,143,140,140,140,140,140,140,135,135,132,132,132,132,127,124,124,124,119,116,116,111,108,108,108,100,100,95,92,92,84,84,76,71,68,60,55,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,36,44,52,60,68,68,76,79,84,87,92,92,100,100,103,108,108,111,116,116,119,124,124,124,127,132,132,132,135,135,140,140,140,140,143,143,143,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,140,135,132,132,132,132,127,124,124,124,116,116,116,111,108,108,100,100,95,92,92,84,84,76,71,68,60,55,52,44,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,63,68,76,79,84,87,92,95,100,100,108,108,108,116,116,116,124,124,124,127,132,132,132,135,135,140,140,140,140,143,148,148,148,148,148,148,148,151,151,151,151,151,151,156,156,156,151,151,151,151,151,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,132,127,124,124,124,119,116,116,111,108,108,103,100,100,92,92,84,84,76,71,68,60,55,52,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,63,68,76,79,84,87,92,95,100,100,108,108,111,116,116,119,124,124,124,127,132,132,132,135,140,140,140,143,143,148,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,148,148,148,143,140,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,103,100,100,92,92,84,84,76,71,68,60,52,47,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,44,52,60,63,68,76,76,84,87,92,95,100,100,108,108,111,116,116,119,124,124,127,132,132,132,135,140,140,140,143,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,159,159,159,159,159,159,159,156,156,156,156,156,156,156,156,156,151,148,148,148,148,148,143,140,140,140,140,135,132,132,127,124,124,124,116,116,116,108,108,103,100,100,92,92,84,84,76,71,68,60,52,44,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,47,55,60,68,76,76,84,87,92,95,100,100,108,108,111,116,116,119,124,124,127,132,132,135,140,140,140,140,143,148,148,148,148,151,156,156,156,156,156,156,159,159,159,164,164,164,164,164,164,164,164,164,164,164,164,159,159,159,156,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,108,108,103,100,100,92,92,84,79,76,68,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,71,76,84,84,92,92,100,100,108,108,111,116,116,124,124,124,127,132,132,135,140,140,140,143,148,148,148,148,151,156,156,156,156,156,159,159,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,148,148,148,143,143,140,140,140,132,132,132,127,124,124,119,116,116,108,108,103,100,95,92,87,84,79,76,68,63,60,52,44,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,71,76,84,84,92,92,100,100,108,108,111,116,116,124,124,124,132,132,132,135,140,140,143,148,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,164,164,167,167,167,167,167,167,167,167,167,167,167,167,164,164,164,164,164,164,164,164,159,156,156,156,156,151,151,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,95,92,87,84,76,76,68,60,55,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,52,55,63,68,76,79,84,92,92,100,100,108,108,111,116,116,124,124,124,132,132,132,140,140,140,143,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,167,167,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,164,164,164,159,156,156,156,156,151,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,95,92,87,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,76,76,84,87,92,95,100,103,108,111,116,116,124,124,124,132,132,132,140,140,140,143,148,148,148,151,156,156,156,159,159,164,164,164,164,167,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,164,164,159,156,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,116,108,108,100,100,92,92,84,84,76,68,63,60,52,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,44,52,60,68,71,76,84,84,92,95,100,103,108,108,116,116,119,124,124,132,132,135,140,140,140,143,148,148,151,156,156,156,156,159,164,164,164,164,167,167,172,172,172,172,172,172,175,175,175,175,175,180,180,180,180,180,175,175,175,175,172,172,172,172,172,172,172,167,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,111,108,108,100,100,92,92,84,79,76,68,60,55,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,47,55,63,68,76,79,84,92,92,100,100,108,108,116,116,119,124,124,132,132,132,140,140,140,143,148,148,151,156,156,156,159,164,164,164,164,167,167,172,172,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,175,175,175,172,172,172,172,172,167,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,103,100,95,92,87,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,76,84,87,92,100,100,108,108,111,116,119,124,124,127,132,132,140,140,140,148,148,148,151,156,156,156,159,164,164,164,167,167,172,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,175,175,172,172,172,172,172,167,164,164,164,164,159,156,156,156,148,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,103,100,95,92,84,84,76,68,63,55,52,39,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,39,52,60,63,68,76,84,84,92,95,100,103,108,111,116,116,124,124,127,132,132,140,140,140,143,148,148,151,156,156,156,159,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,180,183,183,183,183,188,188,188,188,188,188,188,183,183,183,180,180,180,180,180,180,180,175,172,172,172,172,167,167,164,164,164,159,156,156,156,148,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,100,100,92,92,84,79,76,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,79,84,92,92,100,100,108,108,116,116,124,124,127,132,132,135,140,140,143,148,148,151,156,156,156,159,164,164,164,167,172,172,172,175,175,180,180,180,180,180,183,183,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,183,183,183,180,180,180,180,180,175,172,172,172,172,167,164,164,164,159,156,156,156,148,148,148,143,140,140,135,132,132,124,124,119,116,111,108,103,100,95,92,87,84,76,68,63,60,52,39,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,39,52,60,63,71,76,84,87,92,95,100,108,108,111,116,119,124,124,132,132,135,140,140,143,148,148,151,156,156,156,164,164,164,167,172,172,172,172,175,180,180,180,180,180,183,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,183,183,180,180,180,180,175,175,172,172,172,167,164,164,164,159,156,156,156,148,148,148,140,140,140,132,132,127,124,124,116,116,111,108,103,100,92,92,84,79,76,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,79,84,92,92,100,103,108,111,116,116,124,124,127,132,135,140,140,143,148,148,151,156,156,156,164,164,164,167,172,172,172,175,175,180,180,180,180,183,188,188,188,188,188,188,191,191,191,191,196,196,196,196,196,196,191,191,191,191,188,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,148,140,140,135,132,132,127,124,119,116,116,108,108,100,100,92,87,84,76,71,63,60,52,39,28,0,0,0,0,0,0,0,0,0,0,0,0,28,39,52,60,63,71,76,84,87,92,100,100,108,108,116,116,119,124,127,132,132,140,140,143,148,148,151,156,156,156,159,164,164,167,172,172,172,175,180,180,180,180,183,188,188,188,188,188,191,191,191,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,191,191,188,188,188,188,188,183,180,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,135,132,132,124,124,119,116,111,108,103,100,92,92,84,79,76,68,60,52,44,36,15,0,0,0,0,0,0,0,0,0,0,12,31,44,52,60,68,76,79,84,92,92,100,103,108,111,116,119,124,124,132,132,135,140,140,148,148,148,156,156,156,159,164,164,167,172,172,172,175,180,180,180,180,183,188,188,188,188,191,191,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,191,191,188,188,188,188,188,183,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,108,108,100,100,92,87,84,76,68,63,55,47,36,23,0,0,0,0,0,0,0,0,0,0,23,36,47,55,63,68,76,84,87,92,100,100,108,108,116,116,124,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,191,191,196,196,196,196,196,196,199,199,199,199,199,204,204,199,199,199,199,199,196,196,196,196,196,196,196,191,188,188,188,188,183,180,180,180,175,172,172,172,167,164,164,164,156,156,156,151,148,148,140,140,135,132,132,124,124,119,116,111,108,103,100,92,92,84,79,76,68,60,52,44,31,12,0,0,0,0,0,0,0,0,0,28,44,52,60,68,76,76,84,92,92,100,103,108,111,116,119,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,164,172,172,172,175,180,180,180,183,188,188,188,188,191,196,196,196,196,196,199,199,199,204,204,204,204,204,204,204,204,204,204,204,204,204,199,199,196,196,196,196,196,191,191,188,188,188,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,140,135,132,127,124,124,116,116,108,108,100,95,92,87,84,76,68,63,55,44,36,20,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,84,84,92,95,100,108,108,116,116,124,124,127,132,135,140,140,143,148,148,156,156,156,164,164,164,167,172,172,175,180,180,180,183,188,188,188,188,191,196,196,196,196,199,199,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,199,199,196,196,196,196,196,191,188,188,188,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,135,132,132,124,124,119,116,111,108,103,100,92,92,84,76,71,68,60,52,39,28,0,0,0,0,0,0,0,0,23,36,47,60,63,71,76,84,87,92,100,103,108,111,116,119,124,124,132,132,135,140,143,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,191,191,196,196,196,196,199,204,204,204,204,204,204,204,207,207,207,207,207,207,207,207,207,204,204,204,204,204,204,199,199,196,196,196,196,191,188,188,188,183,180,180,180,175,172,172,172,164,164,164,159,156,156,148,148,143,140,140,135,132,127,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,31,12,0,0,0,0,0,0,7,28,44,52,60,68,76,79,84,92,95,100,103,108,116,116,124,124,127,132,135,140,140,143,148,148,156,156,159,164,164,167,172,172,172,175,180,180,183,188,188,188,191,196,196,196,196,199,204,204,204,204,204,204,207,207,212,212,212,212,212,212,212,212,212,212,207,207,207,204,204,204,204,204,199,196,196,196,196,191,188,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,143,140,135,132,132,124,124,119,116,111,108,100,100,92,87,84,76,68,63,55,47,36,20,0,0,0,0,0,0,20,36,44,52,60,68,76,84,87,92,100,100,108,108,116,116,124,124,132,132,135,140,143,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,196,199,204,204,204,204,207,207,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,207,207,204,204,204,204,199,199,196,196,196,191,188,188,188,183,180,180,180,172,172,172,167,164,164,159,156,156,148,148,143,140,140,135,132,127,124,119,116,111,108,103,100,92,92,84,76,71,68,60,52,39,28,0,0,0,0,0,0,23,36,47,60,63,71,76,84,92,92,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,191,196,196,196,199,204,204,204,204,207,212,212,212,212,212,212,212,212,215,215,215,215,215,212,212,212,212,212,212,212,207,207,204,204,204,204,199,196,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,148,143,140,135,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,31,12,0,0,0,0,0,28,39,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,183,188,188,188,191,196,196,196,199,204,204,204,204,207,212,212,212,212,212,215,215,215,220,220,220,220,220,220,215,215,215,212,212,212,212,212,212,207,204,204,204,204,199,196,196,196,191,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,127,124,119,116,111,108,100,100,92,87,84,76,68,63,55,44,36,20,0,0,0,0,12,31,44,52,60,68,76,84,84,92,100,100,108,108,116,119,124,124,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,199,204,204,204,207,207,212,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,220,220,220,215,212,212,212,212,212,207,204,204,204,199,199,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,124,116,111,108,103,100,92,92,84,76,71,68,60,47,36,23,0,0,0,0,20,36,44,55,63,68,76,84,87,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,204,207,207,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,215,215,212,212,212,212,207,204,204,204,199,196,196,196,191,188,188,188,180,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,39,28,0,0,0,0,20,36,47,60,68,71,76,84,92,92,100,103,108,116,116,124,124,132,132,135,140,143,148,148,151,156,156,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,204,204,204,204,207,212,212,212,215,215,220,220,220,220,220,223,223,223,223,223,223,223,223,220,220,220,220,220,220,215,212,212,212,212,207,204,204,204,199,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,143,140,140,132,132,127,124,119,116,111,108,100,100,92,84,84,76,68,60,52,44,31,12,0,0,0,28,39,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,204,207,212,212,212,215,220,220,220,220,220,223,223,228,228,228,228,228,228,228,228,228,223,223,220,220,220,220,215,212,212,212,212,207,204,204,204,199,196,196,191,188,188,188,180,180,180,175,172,172,164,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,60,52,44,36,15,0,0,0,28,44,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,132,140,140,143,148,151,156,156,159,164,164,172,172,172,180,180,180,188,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,220,223,223,228,228,228,228,228,228,228,228,228,228,228,228,228,223,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,47,36,20,0,0,12,31,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,215,215,220,220,220,223,228,228,228,228,228,228,228,231,231,228,228,228,228,228,228,228,223,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,79,71,68,60,52,36,23,0,0,15,36,44,55,63,68,76,84,87,92,100,103,108,111,116,124,124,127,132,135,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,223,228,228,228,228,228,231,231,231,236,236,236,231,231,231,228,228,228,228,223,220,220,220,220,215,212,212,212,207,204,204,199,196,196,196,188,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,127,124,119,116,108,108,100,95,92,84,79,76,68,60,52,39,28,0,0,20,36,47,55,63,71,76,84,92,92,100,103,108,116,116,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,191,196,196,199,204,204,204,212,212,212,215,220,220,220,223,228,228,228,228,231,231,236,236,236,236,236,236,236,236,236,231,228,228,228,228,223,220,220,220,215,212,212,212,207,204,204,204,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,100,100,92,84,79,76,68,60,52,44,28,0,0,20,36,47,60,68,71,76,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,151,156,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,215,220,220,220,223,228,228,228,231,231,236,236,236,236,236,236,236,236,236,236,236,231,228,228,228,228,223,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,151,148,148,140,140,135,132,127,124,119,116,111,108,100,100,92,87,84,76,68,60,52,44,28,7,0,23,36,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,215,220,220,220,223,228,228,228,231,231,236,236,236,236,239,239,239,239,236,236,236,236,236,231,228,228,228,223,220,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,188,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,60,52,44,31,12,0,28,39,52,60,68,76,79,84,92,95,100,108,108,116,119,124,127,132,132,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,212,212,212,215,220,220,220,223,228,228,228,231,236,236,236,236,239,244,244,244,244,239,239,236,236,236,236,231,228,228,228,223,220,220,220,212,212,212,207,204,204,199,196,196,196,188,188,188,183,180,180,172,172,172,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,92,87,84,76,68,63,52,44,36,12,0,28,39,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,207,212,212,212,215,220,220,223,228,228,228,231,236,236,236,236,239,244,244,244,244,244,244,244,239,236,236,236,231,228,228,228,223,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,148,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,68,63,55,44,36,15,0,28,44,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,175,180,180,188,188,188,196,196,196,199,204,204,207,212,212,212,220,220,220,223,228,228,228,231,236,236,236,239,244,244,244,244,244,244,244,244,239,239,236,236,236,231,228,228,223,220,220,220,215,212,212,212,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,44,36,20,0,28,44,52,60,68,76,84,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,215,220,220,220,223,228,228,228,231,236,236,239,244,244,244,244,247,247,244,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,204,204,204,207,212,212,215,220,220,220,223,228,228,231,236,236,236,239,244,244,244,247,252,252,247,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,204,204,204,207,212,212,215,220,220,220,223,228,228,231,236,236,236,239,244,244,244,247,252,252,247,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,215,220,220,220,223,228,228,228,236,236,236,239,244,244,244,244,247,247,247,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,215,220,220,220,223,228,228,228,231,236,236,236,239,244,244,244,244,244,244,244,244,244,239,236,236,236,231,228,228,228,220,220,220,215,212,212,212,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,44,36,20,0,28,39,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,175,180,180,188,188,188,191,196,196,199,204,204,207,212,212,212,215,220,220,223,228,228,228,231,236,236,236,239,244,244,244,244,244,244,244,244,239,236,236,236,231,228,228,228,223,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,44,36,20,0,28,39,52,60,68,76,79,84,92,95,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,207,212,212,212,215,220,220,220,228,228,228,231,236,236,236,236,239,239,244,244,244,244,244,239,236,236,236,236,231,228,228,228,223,220,220,220,215,212,212,207,204,204,204,196,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,92,87,84,76,68,63,55,44,36,15,0,23,39,52,60,68,76,79,84,92,95,100,108,108,116,119,124,127,132,132,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,215,220,220,220,223,228,228,228,231,236,236,236,236,239,239,239,239,239,239,236,236,236,236,231,228,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,196,188,188,188,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,111,108,103,100,92,87,84,76,68,60,52,44,31,12,0,23,36,47,60,68,71,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,151,156,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,204,204,204,207,212,212,212,220,220,220,223,228,228,228,228,231,236,236,236,236,236,236,236,236,236,236,236,236,231,231,228,228,228,223,220,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,60,52,44,31,12,0,20,36,47,55,63,71,76,84,92,95,100,103,108,116,116,124,124,132,132,140,140,143,148,148,156,156,159,164,164,172,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,212,215,220,220,220,223,228,228,228,228,231,236,236,236,236,236,236,236,236,236,236,231,231,228,228,228,223,220,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,100,100,92,87,84,76,68,60,52,44,28,0,0,20,36,44,55,63,68,76,84,92,92,100,103,108,116,116,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,223,228,228,228,228,231,231,236,236,236,236,236,236,231,231,228,228,228,228,228,223,220,220,220,215,212,212,212,207,204,204,199,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,132,132,127,124,119,116,108,108,100,95,92,84,79,76,68,60,52,44,28,0,0,12,36,44,52,60,68,76,84,87,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,215,220,220,220,220,223,228,228,228,228,228,231,231,231,231,231,231,228,228,228,228,228,228,223,220,220,220,215,212,212,212,207,204,204,204,199,196,196,191,188,188,188,180,180,180,172,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,39,28,0,0,7,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,164,172,172,175,180,180,183,188,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,220,223,228,228,228,228,228,228,228,228,228,228,228,228,228,228,223,223,220,220,220,220,215,212,212,212,207,204,204,204,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,95,92,84,76,71,68,60,47,36,20,0,0,0,28,44,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,212,215,220,220,220,220,223,223,228,228,228,228,228,228,228,228,228,228,228,223,220,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,196,188,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,63,55,44,36,20,0,0,0,23,36,52,60,68,71,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,188,196,196,196,199,204,204,204,207,212,212,212,212,215,220,220,220,220,220,223,223,223,228,228,228,228,228,223,223,223,220,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,196,191,188,188,183,180,180,180,172,172,172,164,164,159,156,156,151,148,148,140,140,132,132,127,124,119,116,111,108,100,100,92,87,84,76,68,60,52,44,31,12,0,0,0,20,36,47,55,63,71,76,84,92,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,164,172,172,172,180,180,180,183,188,188,191,196,196,196,199,204,204,204,207,212,212,212,212,215,220,220,220,220,220,220,220,223,223,223,223,220,220,220,220,220,220,220,215,215,212,212,212,207,207,204,204,204,199,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,28,0,0,0,0,15,36,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,188,191,196,196,196,199,204,204,204,207,212,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,215,212,212,212,212,207,207,204,204,204,199,196,196,196,191,188,188,183,180,180,180,172,172,172,164,164,164,156,156,151,148,148,143,140,135,132,132,124,124,116,116,108,103,100,95,92,84,79,71,68,60,52,39,28,0,0,0,0,0,28,44,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,143,148,148,151,156,156,164,164,164,172,172,172,180,180,180,183,188,188,191,196,196,196,199,204,204,204,204,207,212,212,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,215,215,215,212,212,212,212,207,207,204,204,204,199,196,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,71,63,55,47,36,20,0,0,0,0,0,28,39,52,60,68,71,76,84,92,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,199,204,204,204,204,207,207,212,212,212,212,212,212,215,215,215,215,215,215,215,215,215,212,212,212,212,212,212,207,204,204,204,204,199,196,196,196,191,188,188,188,183,180,180,180,172,172,172,164,164,164,156,156,151,148,148,143,140,140,132,132,124,124,119,116,108,108,100,100,92,87,84,76,68,60,52,44,36,15,0,0,0,0,0,20,36,44,55,63,68,76,84,87,92,100,100,108,111,116,119,124,127,132,132,140,140,143,148,148,156,156,156,164,164,164,172,172,172,175,180,180,183,188,188,188,191,196,196,196,199,199,204,204,204,204,207,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,207,207,204,204,204,204,199,196,196,196,191,191,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,28,0,0,0,0,0,0,12,31,44,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,191,196,196,196,199,199,204,204,204,204,207,207,207,212,212,212,212,212,212,212,212,212,212,212,212,212,207,207,204,204,204,204,204,199,196,196,196,196,191,188,188,188,183,180,180,175,172,172,172,164,164,164,156,156,156,148,148,143,140,140,132,132,127,124,119,116,111,108,103,100,92,92,84,76,71,63,60,47,36,23,0,0,0,0,0,0,0,28,39,52,60,68,71,76,84,92,92,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,151,156,156,164,164,164,167,172,172,175,180,180,180,183,188,188,188,191,196,196,196,196,199,204,204,204,204,204,204,207,207,207,212,212,212,212,212,212,207,207,207,207,204,204,204,204,204,199,199,196,196,196,191,191,188,188,188,183,180,180,180,172,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,132,124,124,116,116,108,108,100,100,92,87,84,76,68,60,52,44,36,20,0,0,0,0,0,0,0,20,36,47,55,63,68,76,84,87,92,100,100,108,108,116,116,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,172,175,180,180,180,183,188,188,188,191,196,196,196,196,199,199,204,204,204,204,204,204,204,204,204,207,207,207,204,204,204,204,204,204,204,204,204,199,196,196,196,196,191,191,188,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,119,116,111,108,103,100,95,92,84,79,76,68,60,52,44,28,7,0,0,0,0,0,0,0,12,31,44,52,60,68,76,79,84,92,95,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,167,172,172,172,175,180,180,180,183,188,188,188,191,191,196,196,196,196,199,199,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,199,199,196,196,196,196,196,191,188,188,188,188,183,180,180,180,175,172,172,167,164,164,164,159,156,156,151,148,148,140,140,135,132,132,124,124,116,116,108,108,100,100,92,87,84,76,71,63,60,47,36,23,0,0,0,0,0,0,0,0,0,28,39,52,60,68,71,76,84,87,92,100,100,108,111,116,116,124,124,132,132,135,140,140,143,148,148,156,156,156,164,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,191,196,196,196,196,196,196,199,199,199,204,204,204,204,204,204,204,204,204,199,199,199,196,196,196,196,196,191,191,188,188,188,188,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,119,116,111,108,103,100,95,92,84,79,76,68,60,52,44,36,15,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,79,84,92,95,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,191,191,196,196,196,196,196,196,196,199,199,199,199,199,199,199,199,196,196,196,196,196,196,196,196,191,188,188,188,188,183,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,140,135,132,132,124,124,116,116,108,108,100,100,92,87,84,76,71,68,60,52,39,28,0,0,0,0,0,0,0,0,0,0,7,28,44,52,60,68,71,76,84,87,92,100,100,108,108,116,116,124,124,127,132,135,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,175,180,180,180,183,183,188,188,188,188,191,191,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,191,191,188,188,188,188,188,183,180,180,180,180,175,172,172,172,167,164,164,159,156,156,156,148,148,148,140,140,135,132,132,127,124,119,116,111,108,103,100,95,92,84,84,76,68,60,55,44,36,20,0,0,0,0,0,0,0,0,0,0,0,20,36,47,55,60,68,76,84,84,92,95,100,103,108,111,116,119,124,124,132,132,135,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,175,180,180,180,180,183,188,188,188,188,188,188,191,191,191,196,196,196,196,196,196,196,196,196,196,196,191,191,191,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,167,164,164,164,156,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,108,108,100,100,92,87,84,76,71,68,60,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,12,31,44,52,60,68,71,76,84,87,92,100,100,108,108,116,116,124,124,127,132,132,140,140,140,148,148,148,156,156,156,159,164,164,164,167,172,172,172,175,180,180,180,180,180,183,188,188,188,188,188,188,188,188,191,191,191,191,191,191,191,191,191,188,188,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,172,167,164,164,164,156,156,156,151,148,148,143,140,140,135,132,132,124,124,119,116,111,108,103,100,95,92,84,84,76,68,63,55,47,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,47,55,63,68,76,79,84,92,95,100,103,108,111,116,116,124,124,127,132,132,140,140,143,148,148,148,156,156,156,159,164,164,164,167,172,172,172,172,175,180,180,180,180,180,183,183,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,183,183,180,180,180,180,180,175,172,172,172,167,167,164,164,164,156,156,156,151,148,148,143,140,140,135,132,132,127,124,119,116,116,108,108,100,100,92,87,84,76,71,68,60,52,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,52,60,68,71,76,84,87,92,100,100,108,108,111,116,119,124,124,132,132,135,140,140,143,148,148,148,156,156,156,159,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,183,183,183,188,188,188,188,188,188,188,188,188,188,188,188,183,183,183,180,180,180,180,180,180,175,172,172,172,172,167,164,164,164,159,156,156,156,151,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,103,100,95,92,84,79,76,68,60,55,47,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,47,55,60,68,76,79,84,92,92,100,100,108,108,116,116,119,124,127,132,132,135,140,140,143,148,148,148,156,156,156,159,164,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,180,180,183,183,183,183,183,183,183,183,183,183,180,180,180,180,180,180,180,180,175,172,172,172,172,172,167,164,164,164,159,156,156,156,151,148,148,148,140,140,140,132,132,127,124,124,119,116,111,108,103,100,95,92,87,84,76,71,68,60,52,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,60,68,71,76,84,84,92,95,100,103,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,159,164,164,164,167,167,172,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,175,175,172,172,172,172,172,167,164,164,164,164,159,156,156,156,151,148,148,148,140,140,140,132,132,132,124,124,119,116,116,108,108,100,100,92,92,84,79,76,68,60,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,76,84,87,92,100,100,108,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,159,164,164,164,164,167,167,172,172,172,172,172,175,175,175,180,180,180,180,180,180,180,180,180,180,180,180,175,175,175,172,172,172,172,172,172,167,164,164,164,164,159,159,156,156,156,151,148,148,143,140,140,140,132,132,132,124,124,119,116,116,108,108,103,100,95,92,84,84,76,68,63,60,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,39,52,55,63,68,76,79,84,92,92,100,100,108,108,111,116,119,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,159,159,164,164,164,164,167,167,172,172,172,172,172,172,172,172,175,175,175,175,175,175,175,175,175,172,172,172,172,172,172,172,172,167,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,140,132,132,132,124,124,119,116,116,111,108,103,100,95,92,87,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,71,76,84,84,92,95,100,100,108,108,116,116,119,124,124,127,132,132,135,140,140,140,148,148,148,151,151,156,156,156,159,159,164,164,164,164,164,167,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,164,164,159,156,156,156,156,151,148,148,148,143,140,140,140,132,132,132,124,124,124,116,116,111,108,103,100,100,92,87,84,79,76,68,60,55,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,76,76,84,87,92,95,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,140,143,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,164,167,167,167,172,172,172,172,172,172,172,172,172,172,167,167,167,167,164,164,164,164,164,164,159,156,156,156,156,151,151,148,148,148,143,140,140,135,132,132,132,124,124,124,116,116,111,108,108,100,100,92,92,84,79,76,68,63,60,52,44,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,52,55,63,68,76,79,84,87,92,95,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,140,143,148,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,164,164,164,164,164,164,167,167,167,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,148,148,148,143,140,140,140,135,132,132,132,124,124,124,116,116,111,108,108,100,100,92,92,84,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,63,68,76,79,84,92,92,100,100,103,108,108,116,116,119,124,124,127,132,132,132,135,140,140,140,143,148,148,148,148,151,156,156,156,156,156,159,159,159,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,87,84,76,71,68,60,52,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,71,76,84,84,92,92,100,100,103,108,108,116,116,119,124,124,124,132,132,132,135,140,140,140,143,143,148,148,148,148,151,156,156,156,156,156,156,156,159,159,159,159,159,159,164,164,159,159,159,159,159,159,156,156,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,87,84,76,76,68,60,55,52,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,36,47,52,60,68,71,76,84,84,92,92,100,100,103,108,108,116,116,116,124,124,124,127,132,132,132,135,140,140,140,143,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,148,148,143,140,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,87,84,79,76,68,63,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,47,55,60,68,71,76,84,84,92,92,100,100,103,108,108,111,116,116,119,124,124,127,132,132,132,135,135,140,140,140,143,143,148,148,148,148,148,148,151,151,151,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,151,148,148,148,148,148,148,143,140,140,140,140,135,132,132,132,127,124,124,124,119,116,116,111,108,108,100,100,95,92,87,84,79,76,68,63,60,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,44,52,55,60,68,71,76,84,84,92,92,95,100,103,108,108,111,116,116,119,124,124,124,127,132,132,132,135,135,140,140,140,140,143,143,148,148,148,148,148,148,148,148,148,151,151,151,151,151,151,151,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,132,132,127,124,124,119,116,116,116,108,108,103,100,100,95,92,87,84,79,76,68,68,60,52,44,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,55,60,68,71,76,84,84,92,92,95,100,100,108,108,111,116,116,116,119,124,124,124,127,132,132,132,135,135,140,140,140,140,140,143,143,143,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,140,140,135,132,132,132,132,127,124,124,124,119,116,116,111,108,108,103,100,100,92,92,87,84,79,76,68,68,60,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,55,60,68,71,76,84,84,87,92,95,100,100,103,108,108,111,116,116,119,124,124,124,124,127,132,132,132,132,135,135,140,140,140,140,140,140,140,143,143,143,143,143,143,143,143,143,143,143,143,143,140,140,140,140,140,140,140,135,135,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,92,92,87,84,79,76,68,68,60,52,47,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,55,60,68,71,76,79,84,87,92,92,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,135,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,132,127,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,84,84,76,76,68,68,60,52,47,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,55,60,68,71,76,79,84,87,92,92,95,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,127,132,132,132,132,132,132,135,135,135,135,140,140,140,140,140,140,140,140,135,135,135,135,132,132,132,132,132,132,132,127,124,124,124,124,119,116,116,116,111,108,108,108,103,100,100,95,92,87,84,84,76,76,68,63,60,52,47,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,55,60,68,68,76,76,84,84,92,92,95,100,100,103,108,108,108,111,116,116,116,119,119,124,124,124,124,127,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,124,119,116,116,116,111,108,108,108,103,100,100,95,92,92,87,84,79,76,71,68,63,60,52,44,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,52,60,68,68,76,76,84,84,87,92,92,95,100,100,103,108,108,108,111,116,116,116,116,119,124,124,124,124,124,124,127,127,127,127,132,132,132,132,132,132,132,132,132,132,132,127,127,127,124,124,124,124,124,124,119,119,116,116,116,111,108,108,108,103,100,100,100,95,92,92,84,84,79,76,71,68,60,60,52,44,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,39,47,52,60,63,68,71,76,79,84,84,92,92,92,100,100,100,103,108,108,108,111,111,116,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,87,84,84,76,76,68,68,60,55,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,39,44,52,60,60,68,68,76,76,84,84,87,92,92,92,100,100,100,103,108,108,108,108,111,111,116,116,116,116,116,119,119,119,119,124,124,124,124,124,124,124,124,124,124,124,119,119,119,116,116,116,116,116,116,111,108,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,71,68,63,60,52,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,52,55,60,63,68,71,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,111,108,108,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,76,68,68,60,60,52,47,39,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,47,52,60,60,68,68,76,76,79,84,84,87,92,92,92,95,100,100,100,100,103,108,108,108,108,108,108,111,111,111,116,116,116,116,116,116,116,116,116,116,111,111,111,108,108,108,108,108,108,103,103,100,100,100,100,95,92,92,87,84,84,84,76,76,71,68,63,60,55,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,44,52,55,60,63,68,68,76,76,79,84,84,87,92,92,92,92,95,100,100,100,100,103,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,100,100,100,100,100,95,92,92,92,87,84,84,84,76,76,71,68,68,60,60,52,47,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,47,52,55,60,63,68,71,76,76,79,84,84,84,87,92,92,92,92,95,100,100,100,100,100,100,100,103,103,103,103,103,108,108,103,103,103,103,103,103,100,100,100,100,100,100,95,95,92,92,92,92,87,84,84,79,76,76,71,68,68,60,60,52,52,44,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,44,52,52,60,60,63,68,68,76,76,76,79,84,84,84,87,92,92,92,92,92,95,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,95,92,92,92,92,87,87,84,84,84,79,76,76,71,68,68,63,60,55,52,44,44,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,44,52,52,60,60,63,68,68,71,76,76,76,79,84,84,84,84,87,92,92,92,92,92,92,92,92,92,95,95,95,95,92,92,92,92,92,92,92,92,92,87,87,84,84,84,84,79,76,76,76,71,68,68,60,60,55,52,47,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,52,52,55,60,63,68,68,68,71,76,76,76,79,84,84,84,84,84,84,87,87,87,92,92,92,92,92,92,92,92,87,87,87,87,84,84,84,84,84,79,79,76,76,76,71,68,68,63,60,60,55,52,47,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,47,52,55,60,60,63,68,68,68,71,76,76,76,76,79,79,79,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,79,79,76,76,76,76,71,71,68,68,63,60,60,60,52,52,44,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,36,44,44,52,52,55,60,60,63,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,71,68,68,68,68,63,60,60,60,52,52,47,44,39,36,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,31,36,39,44,47,52,52,55,60,60,60,60,63,68,68,68,68,68,68,68,71,71,71,71,71,71,71,68,68,68,68,68,68,68,63,60,60,60,55,52,52,47,44,44,36,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,31,36,39,44,44,47,52,52,52,55,60,60,60,60,60,63,63,63,63,63,63,63,63,63,63,60,60,60,60,60,60,55,52,52,52,47,44,44,36,36,28,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,31,36,36,39,44,44,47,52,52,52,52,52,52,55,55,55,55,55,55,55,55,55,52,52,52,52,52,47,44,44,44,39,36,36,28,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,28,31,36,36,36,39,44,44,44,44,44,44,47,47,47,47,44,44,44,44,44,44,44,39,36,36,31,28,28,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,23,28,28,28,31,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,20,20,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t FLARE_TEXTURE_3[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,52,55,60,60,60,60,60,60,60,52,52,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,60,68,76,84,92,95,100,108,108,108,111,111,111,108,108,103,100,92,84,79,71,60,52,44,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,71,84,95,108,116,124,132,140,148,148,156,156,159,164,164,164,159,156,151,148,140,135,127,119,111,100,92,76,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,60,76,92,108,119,132,143,156,164,172,180,188,196,199,204,207,212,212,212,212,212,204,204,196,191,188,180,172,159,148,140,124,116,100,84,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,55,76,92,108,124,140,156,167,180,191,204,212,220,228,236,244,252,252,244,244,244,244,244,244,247,252,247,244,236,228,220,207,196,188,172,164,148,132,116,100,84,63,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,100,119,140,156,172,188,204,215,228,244,252,244,231,223,215,212,204,199,196,196,191,191,196,196,196,204,207,212,220,228,236,244,244,236,220,212,196,180,164,148,132,108,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,60,84,108,124,148,164,183,204,220,236,252,239,228,212,204,191,183,172,167,159,156,148,148,143,140,140,143,148,148,151,156,164,172,180,188,196,207,220,236,247,244,228,212,196,175,156,135,116,95,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,60,84,108,132,151,172,191,212,228,247,236,220,204,191,180,164,156,143,132,124,116,111,108,100,100,92,92,92,92,95,100,103,108,116,124,132,140,148,159,172,188,199,212,228,244,239,220,204,180,164,140,116,92,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,76,100,124,148,172,196,220,236,244,228,207,191,172,159,143,132,116,108,95,84,76,68,60,55,52,47,44,44,44,44,44,52,52,60,68,71,79,92,100,111,124,140,151,164,180,199,220,236,247,228,204,183,164,140,116,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,68,92,119,148,172,196,220,239,244,220,199,180,164,143,127,111,95,84,68,60,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,12,15,23,31,44,52,63,76,92,103,119,135,156,172,188,212,228,252,228,204,180,156,132,108,79,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,79,108,135,164,188,212,236,244,220,196,175,156,132,116,100,79,63,52,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,44,55,71,92,108,124,143,164,188,207,228,252,228,204,175,148,124,92,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,92,124,148,180,204,228,247,220,196,172,151,132,108,87,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,79,100,119,140,164,188,212,236,244,220,191,164,135,108,76,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,71,100,132,164,188,220,244,228,204,180,156,132,108,84,63,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,76,95,119,140,164,191,220,244,231,204,175,148,116,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,108,140,172,204,231,244,215,188,164,135,111,84,63,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,76,100,124,148,175,204,228,244,215,188,156,124,92,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,148,180,212,244,231,204,172,148,119,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,55,79,108,132,159,188,220,247,228,196,164,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,124,156,188,220,252,220,191,164,132,108,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,63,92,119,148,180,207,236,236,204,172,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,124,156,191,228,244,212,183,151,124,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,76,108,140,167,196,228,244,207,175,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,124,159,196,228,244,207,175,143,116,84,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,68,100,127,159,191,228,244,212,180,143,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,159,196,228,236,204,172,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,156,188,220,247,212,180,140,108,68,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,84,124,156,196,228,236,204,167,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,151,188,220,247,212,175,140,103,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,116,156,191,228,236,204,167,132,100,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,47,79,116,148,183,220,247,212,172,135,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,108,148,188,228,244,204,167,132,95,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,116,148,188,223,244,204,167,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,220,244,207,172,132,100,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,79,116,151,188,228,236,199,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,132,172,212,252,212,175,140,100,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,84,119,156,196,236,231,191,151,111,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,124,164,204,244,220,183,143,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,164,204,244,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,108,148,188,231,231,191,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,55,92,132,172,212,252,212,172,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,92,135,180,220,244,204,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,60,100,140,180,223,239,196,156,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,204,244,215,172,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,116,156,196,236,228,183,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,228,228,188,148,108,63,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,124,167,212,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,124,172,212,247,204,164,119,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,140,183,228,236,191,148,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,148,196,236,220,180,135,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,199,244,215,172,127,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,132,172,220,244,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,239,196,151,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,151,196,239,220,172,132,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,108,151,196,244,220,172,127,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,124,172,220,244,196,151,108,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,132,172,220,239,196,148,103,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,100,148,191,236,220,175,132,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,151,196,244,215,172,124,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,119,164,212,244,199,156,108,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,132,180,223,236,188,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,183,228,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,111,156,204,252,207,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,247,207,164,116,68,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,231,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,236,191,143,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,167,212,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,220,172,127,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,103,151,196,244,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,204,159,111,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,87,135,180,228,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,71,119,167,215,239,191,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,119,167,215,239,191,143,95,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,143,191,244,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,215,167,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,228,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,244,191,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,119,167,220,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,231,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,207,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,223,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,247,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,148,196,244,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,220,172,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,252,204,156,108,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,79,132,180,228,223,175,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,108,156,204,252,199,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,175,228,228,180,132,79,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,207,244,196,148,100,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,124,172,220,231,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,244,196,143,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,119,172,220,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,244,191,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,167,220,236,188,135,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,244,191,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,167,220,236,188,140,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,244,196,143,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,167,220,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,244,196,148,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,119,172,220,236,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,76,124,172,223,231,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,103,151,204,252,204,151,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,127,180,228,228,180,127,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,247,207,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,231,220,172,124,76,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,220,172,124,71,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,100,148,196,244,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,79,127,180,228,228,180,132,79,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,108,156,204,252,204,156,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,119,172,220,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,68,116,164,212,244,196,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,159,207,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,236,183,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,207,159,111,63,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,87,135,183,231,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,247,199,151,103,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,79,127,175,223,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,212,164,119,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,95,143,188,236,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,228,180,135,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,111,159,204,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,244,199,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,223,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,239,220,172,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,55,100,148,196,239,215,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,220,236,188,143,100,52,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,167,212,244,196,151,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,156,204,247,212,164,119,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,100,140,188,231,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,135,180,228,228,188,140,95,52,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,207,252,204,159,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,164,204,252,207,164,119,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,100,140,188,228,228,183,140,92,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,95,140,183,228,228,188,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,207,252,207,164,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,204,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,231,228,183,140,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,92,140,180,228,236,191,148,108,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,127,172,212,247,204,159,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,204,244,220,175,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,111,156,196,236,220,180,135,92,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,244,204,159,119,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,223,236,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,191,231,228,188,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,127,167,212,252,212,172,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,79,124,164,204,244,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,76,116,156,196,236,228,183,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,135,175,215,247,207,167,127,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,108,148,188,228,236,196,156,116,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,148,188,228,236,196,159,124,84,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,103,140,180,220,244,207,167,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,116,156,196,236,228,191,156,116,79,44,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,100,135,172,212,252,215,175,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,124,164,204,244,228,188,151,116,79,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,100,132,172,204,244,220,183,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,132,172,207,244,220,188,148,116,79,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,100,132,167,204,239,228,188,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,63,100,140,175,212,247,220,183,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,167,204,236,228,196,156,119,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,140,180,212,247,220,188,151,119,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,68,103,135,172,204,236,231,196,159,124,84,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,143,180,212,247,223,188,156,124,92,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,47,76,108,140,172,204,239,228,196,159,124,92,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,175,212,244,228,196,164,132,100,71,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,87,116,148,180,212,244,228,196,159,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,172,204,236,236,204,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,68,100,127,156,188,220,252,220,188,156,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,68,103,135,167,199,231,244,212,180,156,124,100,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,111,140,167,196,228,244,215,183,151,119,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,164,191,220,252,223,196,167,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,76,100,127,156,180,212,236,236,207,175,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,151,180,212,239,236,212,183,156,132,108,84,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,76,100,119,148,172,196,223,252,228,196,167,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,111,140,172,196,228,252,228,199,175,151,132,108,84,68,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,55,76,100,116,140,164,188,212,236,236,212,183,156,127,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,71,100,132,156,183,212,236,244,220,196,172,151,132,111,92,76,60,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,47,68,84,100,124,140,164,188,207,231,247,220,196,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,87,116,140,164,191,215,239,244,220,196,180,156,140,124,103,87,71,60,44,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,28,39,52,68,79,95,111,132,148,167,188,207,228,252,228,204,180,156,127,100,76,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,71,100,124,148,172,196,220,239,244,223,204,188,167,151,135,119,108,92,84,68,60,52,44,36,31,28,20,20,20,20,20,20,23,28,36,39,47,55,68,76,87,100,116,127,143,159,175,196,212,231,252,228,207,183,159,135,111,84,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,79,108,127,151,172,196,215,236,252,231,212,196,180,167,156,140,132,119,108,100,92,84,79,76,71,68,68,68,68,68,76,76,84,92,100,108,116,124,135,148,164,175,188,204,223,239,244,228,204,183,164,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,108,127,148,172,188,207,228,244,244,228,215,204,188,180,167,156,148,140,135,132,124,124,119,116,116,116,119,124,127,132,140,148,156,164,172,183,196,212,223,236,252,236,215,196,180,159,140,116,95,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,103,124,143,164,180,196,212,228,239,252,236,228,220,207,199,191,188,180,175,172,172,167,167,167,172,172,180,180,188,196,204,212,220,231,244,244,236,220,204,188,172,151,132,116,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,60,76,95,116,132,148,164,180,191,204,215,228,236,247,247,244,236,228,228,220,220,220,220,220,220,223,228,231,236,244,252,244,236,220,212,196,188,172,156,140,124,108,87,68,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,68,84,100,116,132,143,156,167,180,188,196,204,212,220,223,228,231,236,236,236,236,236,231,228,220,215,212,204,196,183,172,164,148,140,124,108,92,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,68,84,95,108,119,132,140,148,156,164,172,175,180,180,188,188,188,188,183,180,180,172,167,159,156,143,135,124,116,100,92,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,60,71,84,92,100,108,116,119,124,132,132,135,135,140,135,132,132,127,124,116,111,103,95,84,76,68,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,60,68,71,76,79,84,84,87,87,84,84,84,76,76,68,60,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,28,36,36,36,36,36,36,31,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t FLARE_TEXTURE_4[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,52,55,60,60,60,60,60,60,60,52,52,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,60,68,76,84,92,95,100,108,108,108,111,111,111,108,108,103,100,92,84,79,71,60,52,44,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,71,84,95,108,116,124,132,140,148,148,156,156,159,164,164,164,159,156,151,148,140,135,127,119,111,100,92,76,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,60,76,92,108,119,132,143,156,164,172,180,188,196,199,204,207,212,212,212,212,212,204,204,196,191,188,180,172,159,148,140,124,116,100,84,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,55,76,92,108,124,140,156,167,180,191,204,212,220,228,236,244,252,252,252,252,252,252,252,252,252,252,247,244,236,228,220,207,196,188,172,164,148,132,116,100,84,63,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,100,119,140,156,172,188,204,215,228,244,252,252,252,252,247,247,247,244,244,244,244,244,244,244,244,247,247,247,247,252,252,252,244,236,220,212,196,180,164,148,132,108,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,60,84,108,124,148,164,183,204,220,236,252,252,252,247,247,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,247,247,252,252,244,228,212,196,175,156,135,116,95,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,60,84,108,132,151,172,191,212,228,247,252,247,247,244,244,244,244,244,239,239,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,239,239,244,244,244,244,244,247,252,252,239,220,204,180,164,140,116,92,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,76,100,124,148,172,196,220,236,252,252,247,244,244,244,244,239,236,236,236,236,236,236,231,231,231,231,231,231,231,231,231,231,231,231,236,236,236,236,236,236,239,239,244,244,244,244,247,252,247,228,204,183,164,140,116,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,68,92,119,148,172,196,220,239,252,247,244,244,244,244,239,236,236,236,236,231,231,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,231,236,236,236,236,236,239,244,244,244,247,252,252,228,204,180,156,132,108,79,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,79,108,135,164,188,212,236,252,247,244,244,244,239,236,236,236,236,231,228,228,228,228,228,223,223,223,220,220,220,220,220,220,220,220,220,220,220,223,223,228,228,228,228,228,228,231,236,236,236,239,244,244,244,247,252,252,228,204,175,148,124,92,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,92,124,148,180,204,228,252,252,244,244,244,239,236,236,236,231,228,228,228,228,223,220,220,220,220,220,220,220,220,215,215,215,215,215,215,215,220,220,220,220,220,220,220,223,223,228,228,228,231,231,236,236,236,239,244,244,247,252,244,220,191,164,135,108,76,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,71,100,132,164,188,220,244,252,247,244,244,239,236,236,236,231,228,228,228,223,220,220,220,220,215,215,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,215,215,220,220,220,220,223,223,228,228,228,231,236,236,236,244,244,244,247,252,231,204,175,148,116,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,108,140,172,204,231,252,247,244,244,239,236,236,236,228,228,228,223,220,220,220,220,215,212,212,212,212,212,212,207,207,207,204,204,204,204,204,204,204,207,207,207,212,212,212,212,212,215,215,220,220,220,223,228,228,228,231,236,236,239,244,244,247,252,244,215,188,156,124,92,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,148,180,212,244,252,247,244,244,236,236,236,231,228,228,223,220,220,220,215,212,212,212,212,207,207,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,207,212,212,212,212,215,220,220,220,223,228,228,228,231,236,236,239,244,244,247,252,228,196,164,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,124,156,188,220,252,252,244,244,239,236,236,231,228,228,223,220,220,220,215,212,212,212,207,204,204,204,204,204,199,199,196,196,196,196,196,196,196,196,196,196,196,196,196,199,199,204,204,204,204,207,207,212,212,212,215,220,220,223,228,228,228,236,236,236,244,244,247,252,236,204,172,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,124,156,191,228,252,247,244,244,239,236,236,228,228,228,220,220,220,215,212,212,207,204,204,204,204,199,196,196,196,196,196,196,191,191,191,191,191,191,191,191,191,191,196,196,196,196,196,196,199,199,204,204,204,207,212,212,212,215,220,220,223,228,228,231,236,236,239,244,244,252,244,207,175,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,124,159,196,228,252,247,244,244,236,236,231,228,228,223,220,220,215,212,212,207,204,204,204,199,196,196,196,196,191,191,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,191,196,196,196,196,199,204,204,204,207,212,212,212,215,220,220,223,228,228,236,236,239,244,244,252,244,212,180,143,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,159,196,228,252,247,244,239,236,236,231,228,228,220,220,215,212,212,207,204,204,204,199,196,196,196,191,188,188,188,188,188,183,183,180,180,180,180,180,180,180,180,180,180,183,183,188,188,188,188,188,191,196,196,196,196,199,204,204,207,212,212,215,220,220,223,228,228,231,236,239,244,244,247,247,212,180,140,108,68,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,84,124,156,196,228,252,247,244,239,236,236,228,228,223,220,220,215,212,212,207,204,204,199,196,196,196,191,188,188,188,183,183,180,180,180,180,180,180,175,175,175,175,175,175,180,180,180,180,180,180,180,183,188,188,188,188,191,196,196,196,199,204,204,207,212,212,215,220,220,228,228,231,236,236,244,244,247,247,212,175,140,103,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,116,156,191,228,252,247,244,239,236,236,228,228,223,220,220,212,212,207,204,204,199,196,196,196,188,188,188,183,180,180,180,180,175,175,172,172,172,172,172,172,172,172,172,172,172,172,172,172,175,175,180,180,180,180,183,188,188,188,191,196,196,199,204,204,204,212,212,215,220,220,223,228,231,236,236,244,244,247,247,212,172,135,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,108,148,188,228,252,247,244,239,236,231,228,228,220,220,215,212,212,207,204,204,196,196,196,188,188,188,183,180,180,180,175,172,172,172,172,172,167,167,167,164,164,164,164,164,164,167,167,167,172,172,172,172,172,175,180,180,180,183,188,188,188,191,196,196,199,204,204,207,212,212,220,220,223,228,231,236,236,244,244,252,244,204,167,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,220,252,247,244,239,236,231,228,228,220,220,215,212,212,204,204,199,196,196,191,188,188,183,180,180,180,175,172,172,172,167,167,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,167,172,172,172,172,175,180,180,183,188,188,188,196,196,196,204,204,207,212,212,220,220,223,228,231,236,236,244,244,252,236,199,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,132,172,212,252,247,244,239,236,236,228,228,220,220,215,212,207,204,204,199,196,196,188,188,183,180,180,180,175,172,172,172,167,164,164,164,164,159,159,156,156,156,156,156,156,156,156,156,156,156,159,159,164,164,164,164,167,172,172,172,175,180,180,183,188,188,191,196,196,199,204,207,212,212,220,220,223,228,231,236,236,244,244,252,231,191,151,111,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,124,164,204,244,252,244,244,236,236,228,228,220,220,215,212,207,204,204,196,196,191,188,188,183,180,180,175,172,172,167,164,164,164,159,159,156,156,156,156,156,151,151,151,151,151,151,151,151,156,156,156,156,156,156,159,164,164,164,167,172,172,172,175,180,180,183,188,188,196,196,199,204,204,212,212,220,220,223,228,231,236,239,244,247,252,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,108,148,188,231,252,244,244,236,236,228,228,220,220,215,212,207,204,204,196,196,191,188,188,180,180,175,172,172,167,164,164,164,159,156,156,156,151,151,148,148,148,148,148,148,148,148,148,148,148,148,148,148,151,151,156,156,156,156,159,164,164,167,172,172,175,180,180,183,188,188,196,196,199,204,204,212,212,220,220,223,228,231,236,239,244,247,252,212,172,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,92,135,180,220,252,247,244,239,236,231,228,223,220,215,212,207,204,204,196,196,188,188,183,180,180,175,172,172,164,164,164,159,156,156,156,151,148,148,148,148,143,143,140,140,140,140,140,140,140,140,143,143,148,148,148,148,148,151,156,156,156,159,164,164,167,172,172,175,180,180,188,188,191,196,199,204,204,212,212,220,220,228,228,236,236,244,244,252,239,196,156,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,204,244,247,244,239,236,231,228,223,220,215,212,207,204,204,196,196,188,188,183,180,180,172,172,167,164,164,159,156,156,151,148,148,148,148,143,140,140,140,140,140,140,135,135,135,135,140,140,140,140,140,140,140,143,148,148,148,151,156,156,156,164,164,164,172,172,175,180,180,188,188,191,196,199,204,204,212,212,220,220,228,228,236,236,244,244,252,228,183,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,228,252,244,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,183,180,175,172,172,167,164,164,156,156,156,148,148,148,143,140,140,140,140,135,132,132,132,132,132,132,132,132,132,132,132,132,135,135,140,140,140,143,148,148,148,151,156,156,159,164,164,167,172,175,180,180,188,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,247,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,124,172,212,252,247,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,183,180,175,172,172,164,164,159,156,156,151,148,148,143,140,140,140,135,132,132,132,132,127,127,127,124,124,124,124,127,127,127,132,132,132,132,132,135,140,140,140,148,148,148,156,156,156,164,164,167,172,172,180,180,188,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,252,236,191,148,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,148,196,236,252,244,239,236,231,228,223,220,215,212,207,204,199,196,191,188,183,180,175,172,172,164,164,159,156,156,148,148,143,140,140,140,135,132,132,132,127,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,127,132,132,132,135,140,140,143,148,148,151,156,156,164,164,167,172,172,180,180,188,188,196,196,204,204,212,212,220,220,228,228,236,236,244,244,252,215,172,127,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,132,172,220,252,244,244,236,236,228,228,220,215,212,207,204,199,196,191,188,183,180,175,172,172,164,164,159,156,151,148,148,143,140,140,135,132,132,127,124,124,124,124,119,119,116,116,116,116,116,116,116,116,116,119,119,124,124,124,127,132,132,132,135,140,140,143,148,151,156,156,159,164,167,172,175,180,180,188,188,196,196,204,204,212,212,220,220,228,231,236,239,244,247,239,196,151,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,151,196,239,247,244,239,236,231,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,151,148,148,140,140,135,132,132,127,124,124,124,119,116,116,116,116,116,111,111,111,111,111,111,111,116,116,116,116,119,119,124,124,127,132,132,135,140,140,143,148,148,156,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,236,236,244,244,252,220,172,127,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,124,172,220,252,244,244,236,236,228,223,220,215,212,207,204,196,196,188,188,180,180,172,172,164,164,159,156,151,148,148,140,140,135,132,132,124,124,124,119,116,116,116,111,108,108,108,108,108,108,108,108,108,108,108,108,111,111,116,116,116,119,124,124,127,132,132,140,140,143,148,148,156,156,159,164,167,172,175,180,183,188,191,196,199,204,212,212,220,220,228,228,236,239,244,247,239,196,148,103,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,100,148,191,236,247,244,239,236,228,228,220,220,212,207,204,199,196,191,188,183,180,175,172,167,164,159,156,151,148,143,140,140,132,132,127,124,124,119,116,116,111,108,108,108,108,103,103,100,100,100,100,100,100,103,103,108,108,108,108,111,116,116,116,124,124,124,132,132,135,140,143,148,148,156,156,164,164,172,172,180,180,188,188,196,196,204,204,212,215,220,223,228,236,236,244,244,252,215,172,124,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,119,164,212,252,244,244,236,236,228,223,220,215,212,204,204,196,196,188,183,180,175,172,167,164,159,156,151,148,148,140,140,132,132,127,124,124,116,116,116,108,108,108,103,100,100,100,100,100,100,95,95,95,100,100,100,100,100,103,108,108,108,111,116,116,119,124,124,132,132,135,140,143,148,148,156,156,164,164,172,172,180,180,188,191,196,199,204,207,212,220,220,228,228,236,239,244,252,236,188,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,183,228,252,244,239,236,231,228,220,220,212,207,204,199,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,127,124,119,116,116,111,108,108,103,100,100,100,95,92,92,92,92,92,92,92,92,92,92,95,100,100,100,100,108,108,108,116,116,119,124,124,132,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,196,196,204,204,212,215,220,223,228,236,236,244,247,252,207,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,247,247,244,236,236,228,223,220,215,212,204,204,196,196,188,183,180,175,172,164,164,156,156,148,148,140,140,132,132,127,124,119,116,116,108,108,103,100,100,100,95,92,92,92,87,87,87,84,84,84,87,87,92,92,92,92,95,100,100,103,108,108,111,116,116,124,124,132,132,135,140,143,148,151,156,159,164,172,172,180,180,188,188,196,199,204,207,212,220,220,228,231,236,239,244,252,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,252,244,244,236,231,228,220,220,212,207,204,199,196,188,188,180,180,172,167,164,159,156,151,148,143,140,135,132,127,124,119,116,116,108,108,103,100,100,95,92,92,87,84,84,84,84,84,84,84,84,84,84,84,84,87,92,92,92,95,100,100,108,108,111,116,116,124,124,132,132,140,140,148,148,156,156,164,164,172,175,180,183,188,196,196,204,204,212,215,220,223,228,236,236,244,247,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,247,244,239,236,228,228,220,215,212,204,204,196,196,188,183,180,175,172,164,164,156,156,148,143,140,135,132,127,124,119,116,116,108,108,100,100,95,92,92,87,84,84,84,79,79,76,76,76,76,76,76,76,79,84,84,84,87,92,92,95,100,100,103,108,111,116,116,124,124,132,132,140,140,148,151,156,159,164,167,172,180,180,188,188,196,199,204,212,212,220,223,228,231,236,244,244,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,247,244,236,236,228,223,220,212,212,204,199,196,191,188,180,180,172,167,164,159,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,95,92,92,84,84,84,79,76,76,76,76,71,71,71,71,71,76,76,76,76,79,84,84,87,92,92,100,100,103,108,111,116,119,124,127,132,135,140,143,148,156,156,164,164,172,175,180,183,188,196,196,204,207,212,215,220,228,228,236,239,244,252,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,71,119,167,215,252,244,244,236,231,228,220,220,212,207,204,196,196,188,183,180,175,172,164,164,156,151,148,143,140,135,132,124,124,116,116,108,108,100,100,95,92,87,84,84,79,76,76,71,71,68,68,68,68,68,68,68,68,68,71,76,76,76,84,84,87,92,92,100,100,103,108,111,116,119,124,127,132,140,140,148,148,156,159,164,167,172,180,180,188,191,196,204,204,212,215,220,223,228,236,236,244,247,239,191,143,95,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,252,244,239,236,228,228,220,215,212,204,204,196,191,188,180,180,172,172,164,159,156,148,148,140,140,132,127,124,119,116,111,108,103,100,95,92,87,84,84,76,76,76,68,68,68,63,63,60,60,60,60,60,63,68,68,68,71,76,76,79,84,84,92,92,100,100,108,108,116,116,124,124,132,135,140,143,148,156,156,164,164,172,175,180,188,188,196,199,204,207,212,220,223,228,231,236,244,247,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,143,191,244,247,244,236,236,228,223,220,212,212,204,199,196,188,188,180,175,172,167,164,156,156,148,143,140,135,132,124,124,116,116,108,103,100,95,92,87,84,84,76,76,71,68,68,63,60,60,60,60,55,55,60,60,60,60,60,63,68,68,76,76,79,84,84,92,92,100,100,108,111,116,119,124,127,132,140,140,148,151,156,159,164,172,172,180,183,188,196,196,204,207,212,215,220,228,231,236,244,244,252,215,167,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,247,244,236,231,228,220,220,212,207,204,196,196,188,183,180,172,172,164,159,156,151,148,140,140,132,127,124,119,116,108,108,100,100,92,92,84,84,76,76,71,68,63,60,60,60,55,52,52,52,52,52,52,52,55,60,60,63,68,68,71,76,79,84,87,92,95,100,103,108,111,116,124,124,132,135,140,143,148,156,156,164,167,172,180,180,188,191,196,204,204,212,215,220,228,228,236,239,244,252,228,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,244,244,236,231,228,220,215,212,207,204,196,191,188,183,180,172,167,164,159,156,148,148,140,135,132,124,124,116,111,108,103,100,95,92,84,84,76,76,71,68,63,60,60,55,52,52,47,47,47,44,47,47,52,52,52,55,60,60,68,68,71,76,79,84,87,92,100,100,108,108,116,119,124,127,132,140,140,148,151,156,164,164,172,175,180,188,188,196,199,204,212,212,220,223,228,236,236,244,247,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,252,244,239,236,228,228,220,215,212,204,204,196,191,188,180,175,172,167,164,156,151,148,143,140,132,132,124,119,116,108,108,100,100,92,87,84,79,76,71,68,63,60,55,52,52,47,44,44,44,44,44,44,44,44,47,52,52,55,60,60,68,68,76,76,84,84,92,95,100,103,108,116,116,124,124,132,135,140,148,148,156,159,164,172,172,180,183,188,196,196,204,207,212,220,223,228,231,236,244,247,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,252,244,239,236,228,223,220,212,212,204,199,196,188,188,180,175,172,164,164,156,151,148,140,140,132,127,124,116,116,108,103,100,95,92,84,84,76,76,68,63,60,55,52,52,44,44,44,39,36,36,36,36,36,39,44,44,47,52,55,60,60,68,68,76,79,84,87,92,100,100,108,111,116,119,124,132,132,140,143,148,156,156,164,167,172,180,183,188,191,196,204,207,212,220,220,228,231,236,244,244,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,247,244,236,236,228,223,220,212,212,204,199,196,188,183,180,172,172,164,159,156,148,148,140,135,132,124,124,116,111,108,100,100,92,87,84,79,76,68,68,60,60,52,52,44,44,39,36,36,36,31,31,31,36,36,36,44,44,47,52,55,60,63,68,71,76,84,84,92,95,100,103,108,116,119,124,127,132,140,143,148,151,156,164,167,172,180,180,188,191,196,204,204,212,215,220,228,231,236,244,244,252,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,148,196,244,247,244,236,231,228,223,220,212,207,204,196,196,188,183,180,172,167,164,159,156,148,143,140,132,132,124,119,116,108,108,100,95,92,84,84,76,71,68,63,60,55,52,44,44,39,36,31,28,28,28,28,28,28,31,36,36,44,44,47,52,60,60,68,68,76,79,84,92,92,100,103,108,111,116,124,127,132,140,140,148,151,156,164,164,172,175,180,188,191,196,199,204,212,215,220,228,228,236,239,244,252,220,172,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,252,247,244,236,231,228,220,220,212,207,204,196,191,188,180,180,172,167,164,156,156,148,143,140,132,127,124,119,116,108,103,100,92,92,84,79,76,71,68,60,60,52,47,44,39,36,31,28,28,23,20,20,20,23,28,28,36,36,44,44,52,52,60,63,68,76,76,84,87,92,100,100,108,111,116,124,124,132,135,140,148,148,156,159,164,172,175,180,188,188,196,199,204,212,215,220,223,228,236,239,244,252,223,175,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,108,156,204,252,244,244,236,231,228,220,220,212,207,204,196,191,188,180,180,172,167,164,156,151,148,140,140,132,127,124,116,116,108,103,100,92,87,84,79,76,68,63,60,55,52,44,44,36,31,28,28,20,20,20,20,20,20,23,28,28,36,39,44,47,52,60,60,68,71,76,84,84,92,95,100,108,108,116,119,124,132,135,140,148,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,239,244,252,228,180,132,79,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,207,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,140,132,127,124,116,111,108,100,100,92,87,84,76,76,68,63,60,52,47,44,39,36,28,28,20,20,12,12,12,12,15,20,23,28,31,36,44,44,52,55,60,68,68,76,79,84,92,95,100,108,108,116,119,124,132,132,140,143,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,239,244,247,231,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,100,92,87,84,76,71,68,60,60,52,47,44,36,36,28,23,20,12,12,7,7,12,12,20,20,28,28,36,39,44,52,55,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,159,164,172,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,95,92,84,84,76,71,68,60,55,52,47,44,36,31,28,20,20,12,7,0,0,0,12,15,20,23,28,36,39,44,52,52,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,156,164,167,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,135,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,95,92,84,84,76,71,68,60,55,52,44,44,36,31,28,20,20,12,7,0,0,0,12,12,20,23,28,36,39,44,52,52,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,156,164,167,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,140,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,95,92,84,84,76,71,68,60,60,52,47,44,36,31,28,20,20,12,12,0,0,7,12,15,20,28,28,36,39,44,52,52,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,159,164,167,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,140,132,127,124,116,111,108,100,100,92,87,84,76,71,68,60,60,52,47,44,36,36,28,23,20,15,12,12,12,12,12,20,20,28,31,36,44,44,52,55,60,68,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,236,244,247,236,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,180,172,167,164,156,151,148,140,140,132,127,124,116,111,108,103,100,92,87,84,76,76,68,63,60,52,52,44,39,36,31,28,23,20,20,15,12,15,20,20,28,28,36,36,44,47,52,55,60,68,71,76,84,84,92,95,100,108,108,116,119,124,132,135,140,143,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,239,244,252,231,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,103,151,204,252,247,244,236,231,228,220,220,212,207,204,196,191,188,180,180,172,167,164,156,156,148,143,140,132,127,124,116,116,108,103,100,92,92,84,79,76,68,68,60,55,52,47,44,36,36,28,28,23,20,20,20,20,20,28,28,31,36,39,44,52,52,60,63,68,71,76,84,84,92,95,100,108,111,116,124,124,132,135,140,148,148,156,159,164,172,175,180,188,188,196,199,204,212,212,220,223,228,236,239,244,252,228,180,127,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,247,247,244,236,231,228,220,220,212,207,204,196,196,188,183,180,172,167,164,156,156,148,143,140,132,132,124,119,116,108,108,100,95,92,84,84,76,71,68,60,60,52,52,44,44,36,36,28,28,28,23,23,28,28,28,31,36,39,44,47,52,55,60,68,68,76,76,84,87,92,100,100,108,111,116,124,124,132,135,140,148,151,156,164,164,172,175,180,188,188,196,199,204,212,215,220,228,228,236,239,244,252,220,172,124,76,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,247,244,236,236,228,223,220,212,207,204,196,196,188,183,180,172,172,164,159,156,148,148,140,135,132,124,119,116,111,108,100,100,92,87,84,76,76,68,63,60,55,52,47,44,44,36,36,31,28,28,28,28,31,36,36,39,44,44,52,52,60,60,68,71,76,79,84,92,92,100,103,108,116,116,124,127,132,140,140,148,151,156,164,164,172,175,180,188,191,196,204,204,212,215,220,228,228,236,239,244,252,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,247,244,236,236,228,223,220,212,212,204,199,196,188,188,180,175,172,164,159,156,151,148,140,135,132,124,124,116,111,108,103,100,92,92,84,79,76,71,68,63,60,55,52,47,44,44,39,36,36,36,36,36,36,36,39,44,44,52,52,60,60,68,68,76,76,84,87,92,95,100,108,108,116,119,124,132,132,140,143,148,156,156,164,167,172,180,180,188,191,196,204,207,212,215,220,228,231,236,244,244,252,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,79,127,180,228,252,244,239,236,228,228,220,215,212,204,199,196,188,188,180,175,172,164,164,156,151,148,140,140,132,127,124,119,116,108,108,100,95,92,87,84,76,76,68,68,60,60,55,52,47,44,44,44,39,39,39,39,44,44,44,47,52,52,55,60,63,68,71,76,79,84,92,92,100,100,108,111,116,124,124,132,135,140,148,148,156,159,164,172,172,180,183,188,196,196,204,207,212,220,220,228,231,236,244,247,252,204,156,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,119,172,220,252,244,239,236,228,228,220,215,212,204,204,196,191,188,180,180,172,167,164,156,156,148,143,140,132,132,124,119,116,111,108,100,100,92,92,84,84,76,76,68,68,60,60,55,52,52,47,44,44,44,44,44,44,47,52,52,52,60,60,63,68,71,76,79,84,87,92,95,100,108,108,116,116,124,127,132,140,140,148,151,156,159,164,172,175,180,183,188,196,199,204,212,212,220,223,228,236,236,244,247,244,196,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,159,207,252,244,244,236,231,228,220,220,212,207,204,196,196,188,183,180,172,172,164,159,156,148,148,140,135,132,127,124,116,116,108,108,100,95,92,87,84,79,76,71,68,68,60,60,60,52,52,52,52,52,52,52,52,52,52,55,60,60,63,68,68,76,76,84,84,92,92,100,100,108,111,116,119,124,132,132,140,143,148,151,156,164,167,172,175,180,188,188,196,199,204,212,215,220,223,228,236,239,244,252,236,183,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,247,244,236,236,228,223,220,212,212,204,199,196,188,188,180,175,172,164,164,156,151,148,143,140,132,132,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,68,63,60,60,60,55,55,52,52,52,55,55,60,60,60,68,68,71,76,76,84,84,92,92,100,100,108,108,116,116,124,127,132,135,140,148,148,156,159,164,167,172,180,180,188,191,196,204,204,212,215,220,228,228,236,239,244,252,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,247,244,239,236,228,223,220,215,212,204,199,196,191,188,180,180,172,167,164,156,156,148,148,140,135,132,127,124,116,116,108,108,100,100,92,92,84,84,79,76,76,68,68,68,63,60,60,60,60,60,60,60,60,63,68,68,68,71,76,76,84,84,87,92,95,100,103,108,111,116,119,124,132,132,140,140,148,151,156,164,164,172,175,180,183,188,196,196,204,207,212,220,220,228,231,236,244,244,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,252,244,239,236,228,228,220,215,212,207,204,196,196,188,183,180,172,172,164,159,156,151,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,79,76,76,71,68,68,68,68,63,63,63,63,68,68,68,68,71,76,76,79,84,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,148,148,156,156,164,167,172,175,180,188,188,196,199,204,212,212,220,223,228,236,236,244,247,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,244,244,236,231,228,223,220,212,207,204,199,196,188,188,180,175,172,167,164,156,156,148,148,140,135,132,127,124,119,116,111,108,103,100,100,92,92,87,84,84,79,76,76,76,71,68,68,68,68,68,68,71,71,76,76,76,79,84,84,92,92,95,100,100,108,108,116,116,124,124,132,132,140,143,148,151,156,159,164,172,172,180,183,188,191,196,204,204,212,215,220,228,228,236,239,244,252,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,247,244,236,236,228,223,220,215,212,204,204,196,191,188,183,180,172,172,164,159,156,151,148,143,140,135,132,124,124,119,116,111,108,103,100,100,92,92,87,84,84,84,79,76,76,76,76,76,76,76,76,76,76,76,79,84,84,87,92,92,95,100,100,108,108,116,116,124,124,132,132,140,140,148,148,156,156,164,167,172,175,180,188,188,196,199,204,207,212,220,220,228,231,236,244,244,252,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,252,244,239,236,231,228,220,220,212,207,204,196,196,188,188,180,175,172,167,164,156,156,148,148,140,140,132,132,124,124,116,116,111,108,103,100,100,95,92,92,87,84,84,84,84,79,79,79,79,79,79,84,84,84,84,87,92,92,92,100,100,103,108,108,116,116,119,124,127,132,135,140,143,148,151,156,164,164,172,172,180,180,188,191,196,204,204,212,212,220,223,228,236,236,244,247,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,244,244,236,231,228,223,220,212,212,204,199,196,191,188,183,180,172,172,164,164,156,156,148,143,140,140,132,132,124,124,116,116,111,108,108,100,100,100,95,92,92,92,87,84,84,84,84,84,84,84,84,84,87,92,92,92,95,100,100,103,108,108,116,116,119,124,127,132,135,140,140,148,151,156,159,164,167,172,175,180,188,188,196,196,204,207,212,215,220,228,228,236,239,244,252,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,239,247,244,239,236,228,228,220,215,212,207,204,196,196,188,188,180,175,172,167,164,159,156,151,148,143,140,135,132,132,124,124,116,116,111,108,108,103,100,100,100,95,92,92,92,92,92,92,92,92,92,92,92,92,92,95,100,100,100,108,108,111,116,116,119,124,127,132,132,140,140,148,148,156,156,164,164,172,172,180,183,188,191,196,199,204,212,212,220,223,228,231,236,244,244,252,215,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,220,252,244,244,236,231,228,223,220,212,212,204,199,196,191,188,183,180,175,172,164,164,156,156,151,148,143,140,135,132,132,124,124,119,116,116,111,108,108,103,100,100,100,100,95,95,92,92,92,92,92,95,95,100,100,100,100,108,108,108,111,116,116,124,124,127,132,132,140,140,148,148,151,156,159,164,167,172,180,180,188,188,196,196,204,207,212,215,220,228,228,236,236,244,247,244,196,151,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,156,204,247,247,244,236,236,228,228,220,215,212,207,204,199,196,188,188,180,180,172,172,164,164,156,156,148,148,143,140,135,132,132,124,124,119,116,116,111,108,108,108,103,103,100,100,100,100,100,100,100,100,100,100,100,103,108,108,108,111,116,116,119,124,124,127,132,132,140,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,204,204,212,212,220,223,228,231,236,244,244,252,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,135,180,228,252,244,239,236,231,228,223,220,212,212,204,204,196,196,188,183,180,175,172,167,164,164,156,156,148,148,143,140,135,132,132,127,124,124,119,116,116,116,111,108,108,108,108,108,103,103,103,103,103,108,108,108,108,108,111,116,116,116,119,124,124,132,132,135,140,140,143,148,151,156,159,164,164,172,172,180,180,188,191,196,199,204,207,212,215,220,228,228,236,236,244,247,252,204,159,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,164,204,252,247,244,236,236,228,228,220,215,212,207,204,199,196,191,188,183,180,175,172,167,164,159,156,156,148,148,143,140,140,132,132,127,124,124,124,119,116,116,116,111,111,108,108,108,108,108,108,108,108,111,111,116,116,116,116,119,124,124,127,132,132,135,140,140,148,148,151,156,159,164,164,172,172,180,180,188,188,196,196,204,204,212,212,220,223,228,231,236,239,244,252,228,183,140,92,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,95,140,183,228,252,244,244,236,231,228,223,220,215,212,204,204,196,196,188,188,180,180,175,172,167,164,159,156,156,148,148,143,140,140,135,132,132,127,124,124,124,119,119,116,116,116,116,116,116,116,116,116,116,116,116,116,119,124,124,124,127,132,132,132,140,140,140,148,148,151,156,159,164,164,172,172,180,180,183,188,191,196,199,204,212,212,220,220,228,228,236,236,244,247,252,207,164,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,204,252,247,244,239,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,167,164,159,156,156,151,148,148,140,140,140,135,132,132,127,124,124,124,124,124,119,119,119,119,119,119,119,119,124,124,124,124,124,127,132,132,132,135,140,140,143,148,148,151,156,159,164,164,172,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,244,244,252,228,183,140,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,92,140,180,228,252,244,244,236,236,228,223,220,215,212,207,204,199,196,196,188,188,180,180,172,172,167,164,164,156,156,151,148,148,143,140,140,140,135,132,132,132,127,127,124,124,124,124,124,124,124,124,124,124,124,127,132,132,132,132,135,140,140,143,148,148,151,156,156,159,164,164,172,172,175,180,183,188,191,196,196,204,204,212,212,220,220,228,231,236,239,244,247,247,204,159,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,204,244,247,244,239,236,231,228,223,220,215,212,207,204,199,196,191,188,188,180,180,175,172,167,164,164,159,156,156,151,148,148,143,140,140,140,135,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,135,140,140,140,140,148,148,148,151,156,156,159,164,164,172,172,175,180,183,188,188,196,196,204,204,212,212,220,220,228,228,236,236,244,244,252,220,180,135,92,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,252,247,244,236,236,228,228,220,220,212,212,207,204,199,196,191,188,188,180,180,175,172,172,164,164,159,156,156,156,148,148,148,143,140,140,140,140,140,135,135,132,132,132,132,132,132,135,135,135,140,140,140,140,143,148,148,148,151,156,156,159,164,164,167,172,172,180,180,183,188,188,196,196,204,204,212,212,215,220,223,228,231,236,239,244,252,236,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,191,231,252,244,244,236,236,228,228,220,220,212,212,204,204,199,196,191,188,188,180,180,175,172,172,167,164,164,159,156,156,156,151,148,148,148,143,143,140,140,140,140,140,140,140,140,140,140,140,140,140,143,148,148,148,148,151,156,156,156,164,164,164,167,172,172,180,180,183,188,188,196,196,204,204,207,212,215,220,223,228,231,236,239,244,247,252,212,172,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,79,124,164,204,244,247,244,239,236,231,228,223,220,220,212,212,204,204,199,196,191,188,188,183,180,180,172,172,172,164,164,164,159,156,156,156,151,148,148,148,148,148,148,143,143,143,143,143,143,143,148,148,148,148,148,151,151,156,156,156,159,164,164,167,172,172,175,180,180,183,188,191,196,196,204,204,207,212,215,220,223,228,228,236,236,244,244,252,228,183,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,135,175,215,252,247,244,239,236,231,228,223,220,220,212,212,204,204,199,196,196,188,188,183,180,180,175,172,172,167,164,164,164,159,156,156,156,156,151,151,148,148,148,148,148,148,148,148,148,148,151,151,156,156,156,156,159,164,164,164,167,172,172,172,180,180,180,188,188,191,196,196,204,204,207,212,215,220,220,228,228,236,236,244,244,252,236,196,156,116,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,148,188,228,252,244,244,239,236,231,228,223,220,220,212,212,204,204,199,196,196,191,188,188,180,180,180,175,172,172,167,164,164,164,164,159,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,159,159,164,164,164,167,172,172,172,175,180,180,183,188,188,191,196,196,204,204,207,212,215,220,220,228,228,236,236,239,244,247,244,207,167,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,116,156,196,236,252,244,244,236,236,231,228,223,220,220,212,212,207,204,204,196,196,191,188,188,183,180,180,180,175,172,172,172,167,164,164,164,164,164,159,159,159,159,156,156,159,159,159,159,164,164,164,164,164,167,167,172,172,172,175,180,180,183,188,188,191,196,196,199,204,204,212,212,215,220,220,228,228,236,236,239,244,247,252,215,175,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,124,164,204,244,252,244,244,236,236,231,228,223,220,220,212,212,207,204,204,199,196,196,191,188,188,183,180,180,180,175,172,172,172,172,167,167,164,164,164,164,164,164,164,164,164,164,164,164,164,167,172,172,172,172,175,175,180,180,180,188,188,188,191,196,196,199,204,204,212,212,215,220,220,228,228,231,236,239,244,247,252,220,183,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,132,172,207,244,247,244,244,236,236,231,228,223,220,220,215,212,212,204,204,199,196,196,196,188,188,188,183,180,180,180,180,175,172,172,172,172,172,172,172,172,167,167,167,172,172,172,172,172,172,172,175,175,180,180,180,183,188,188,188,191,196,196,199,204,204,207,212,212,215,220,223,228,228,236,236,239,244,247,252,228,188,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,63,100,140,175,212,247,247,244,244,236,236,231,228,228,220,220,215,212,212,207,204,204,199,196,196,196,188,188,188,188,183,180,180,180,180,180,175,175,172,172,172,172,172,172,172,172,175,175,175,180,180,180,180,180,183,188,188,188,191,196,196,196,204,204,204,212,212,212,220,220,223,228,228,236,236,239,244,247,252,228,196,156,119,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,140,180,212,247,247,244,244,236,236,231,228,228,223,220,220,212,212,212,204,204,204,199,196,196,196,191,188,188,188,188,183,183,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,183,183,188,188,188,188,191,196,196,196,199,204,204,207,212,212,215,220,220,223,228,228,236,236,239,244,247,252,231,196,159,124,84,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,143,180,212,247,252,244,244,239,236,236,228,228,223,220,220,215,212,212,207,204,204,204,199,196,196,196,196,191,188,188,188,188,188,188,183,183,183,183,183,183,183,183,188,188,188,188,188,188,188,191,196,196,196,199,204,204,204,207,212,212,212,220,220,220,228,228,231,236,236,239,244,247,252,228,196,159,124,92,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,175,212,244,252,244,244,239,236,236,231,228,228,220,220,220,215,212,212,207,204,204,204,204,199,196,196,196,196,191,191,191,188,188,188,188,188,188,188,188,188,188,188,191,191,196,196,196,196,196,199,204,204,204,207,212,212,212,215,220,220,223,228,228,231,236,236,244,244,247,252,228,196,159,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,172,204,236,252,247,244,244,236,236,231,228,228,223,220,220,220,215,212,212,212,207,204,204,204,204,199,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,199,199,204,204,204,204,207,212,212,212,215,220,220,223,228,228,231,236,236,239,244,244,247,252,220,188,156,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,68,103,135,167,199,231,252,247,244,244,239,236,236,231,228,228,223,220,220,220,215,212,212,212,207,207,204,204,204,204,204,199,199,199,199,196,196,196,196,199,199,199,199,204,204,204,204,204,204,207,212,212,212,212,215,220,220,223,228,228,228,231,236,236,239,244,244,252,244,215,183,151,119,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,164,191,220,252,252,244,244,239,236,236,236,228,228,228,223,220,220,220,215,215,212,212,212,212,207,207,204,204,204,204,204,204,204,204,204,204,204,204,204,204,207,207,212,212,212,212,212,215,220,220,220,223,228,228,228,231,236,236,239,244,244,247,252,236,207,175,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,151,180,212,239,252,247,244,244,239,236,236,236,228,228,228,223,223,220,220,220,215,215,212,212,212,212,212,212,212,212,207,207,207,207,212,212,212,212,212,212,212,212,215,215,220,220,220,220,223,228,228,228,231,236,236,236,244,244,244,252,252,228,196,167,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,111,140,172,196,228,252,252,244,244,244,239,236,236,236,231,228,228,228,223,223,220,220,220,220,220,215,215,215,212,212,212,212,212,212,212,212,212,215,215,215,220,220,220,220,220,223,228,228,228,228,231,236,236,236,239,244,244,247,252,236,212,183,156,127,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,71,100,132,156,183,212,236,252,247,244,244,244,239,236,236,236,231,228,228,228,228,228,223,223,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,223,223,228,228,228,228,231,236,236,236,236,244,244,244,247,252,247,220,196,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,87,116,140,164,191,215,239,252,247,244,244,244,239,236,236,236,236,231,231,228,228,228,228,228,228,223,223,223,223,223,223,223,223,223,223,228,228,228,228,228,228,228,231,236,236,236,236,239,244,244,244,247,252,252,228,204,180,156,127,100,76,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,71,100,124,148,172,196,220,239,252,252,247,244,244,244,239,236,236,236,236,236,231,231,231,228,228,228,228,228,228,228,228,228,228,228,228,228,231,231,236,236,236,236,236,239,244,244,244,244,247,252,252,228,207,183,159,135,111,84,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,79,108,127,151,172,196,215,236,252,252,247,244,244,244,244,244,239,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,239,239,244,244,244,244,247,252,252,244,228,204,183,164,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,108,127,148,172,188,207,228,244,252,252,247,247,244,244,244,244,244,244,239,239,239,239,236,236,236,236,236,239,239,239,239,244,244,244,244,244,244,247,252,252,252,236,215,196,180,159,140,116,95,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,103,124,143,164,180,196,212,228,239,252,252,252,247,247,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,247,247,252,252,252,244,236,220,204,188,172,151,132,116,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,60,76,95,116,132,148,164,180,191,204,215,228,236,247,252,252,252,252,252,247,247,247,247,247,247,252,252,252,252,252,252,244,236,220,212,196,188,172,156,140,124,108,87,68,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,68,84,100,116,132,143,156,167,180,188,196,204,212,220,223,228,231,236,236,236,236,236,231,228,220,215,212,204,196,183,172,164,148,140,124,108,92,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,68,84,95,108,119,132,140,148,156,164,172,175,180,180,188,188,188,188,183,180,180,172,167,159,156,143,135,124,116,100,92,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,60,71,84,92,100,108,116,119,124,132,132,135,135,140,135,132,132,127,124,116,111,103,95,84,76,68,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,60,68,71,76,79,84,84,87,87,84,84,84,76,76,68,60,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,28,36,36,36,36,36,36,31,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t FLARE_TEXTURE_5[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,52,55,60,60,60,60,60,60,60,52,52,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,60,68,76,84,92,95,100,108,108,108,111,111,111,108,108,103,100,92,84,79,71,60,52,44,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,71,84,95,108,116,124,132,140,148,148,156,156,159,164,164,164,159,156,151,148,140,135,127,119,111,100,92,76,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,60,76,92,108,119,132,143,156,164,172,180,188,196,199,204,207,212,212,212,212,212,204,204,196,191,188,180,172,159,148,140,124,116,100,84,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,55,76,92,108,124,140,156,167,180,191,204,212,220,228,236,244,252,252,252,252,252,252,252,252,252,252,247,244,236,228,220,207,196,188,172,164,148,132,116,100,84,63,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,100,119,140,156,172,188,204,215,228,244,252,247,244,244,244,239,236,236,236,236,236,236,236,236,236,236,236,239,244,244,247,252,244,236,220,212,196,180,164,148,132,108,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,60,84,108,124,148,164,183,204,220,236,252,247,244,239,236,236,231,228,228,228,223,220,220,220,220,220,220,220,220,223,223,228,228,228,236,236,239,244,244,252,244,228,212,196,175,156,135,116,95,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,60,84,108,132,151,172,191,212,228,247,247,244,236,236,228,228,223,220,220,215,212,212,212,212,207,207,207,207,207,207,207,212,212,212,212,220,220,220,228,228,231,236,239,244,252,239,220,204,180,164,140,116,92,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,76,100,124,148,172,196,220,236,252,244,239,236,228,228,220,220,212,212,207,204,204,199,199,196,196,196,196,196,196,196,196,196,196,196,199,204,204,204,212,212,215,220,223,228,231,236,244,247,247,228,204,183,164,140,116,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,68,92,119,148,172,196,220,239,247,244,236,231,228,220,215,212,207,204,204,196,196,191,188,188,188,188,183,183,180,180,180,180,180,183,183,188,188,188,191,196,196,199,204,204,212,212,220,223,228,236,239,244,252,228,204,180,156,132,108,79,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,79,108,135,164,188,212,236,252,244,236,228,223,220,212,207,204,199,196,191,188,188,183,180,180,175,172,172,172,172,172,172,172,172,172,172,172,172,175,180,180,180,183,188,188,196,196,204,204,212,215,220,228,231,236,244,252,228,204,175,148,124,92,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,92,124,148,180,204,228,252,244,236,228,223,220,212,204,204,196,191,188,183,180,180,172,172,172,164,164,164,164,159,159,159,156,156,159,159,159,164,164,164,164,167,172,172,175,180,180,188,188,196,196,204,207,212,220,228,231,239,244,244,220,191,164,135,108,76,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,71,100,132,164,188,220,244,244,236,228,223,220,212,204,199,196,188,183,180,175,172,172,164,164,159,156,156,156,151,151,148,148,148,148,148,148,148,148,148,151,156,156,156,159,164,164,167,172,172,180,180,188,191,196,204,207,212,220,228,236,244,252,231,204,175,148,116,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,108,140,172,204,231,252,244,236,228,220,212,204,199,196,188,183,180,172,172,164,164,156,156,151,148,148,148,143,140,140,140,140,140,140,140,140,140,140,140,140,140,143,148,148,151,156,156,159,164,167,172,175,180,188,188,196,204,207,215,220,228,236,244,244,215,188,156,124,92,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,148,180,212,244,244,236,228,220,212,207,199,196,188,180,180,172,167,164,156,156,151,148,148,140,140,140,135,132,132,132,132,127,127,127,127,127,127,132,132,132,132,132,135,140,140,143,148,148,156,156,164,164,172,172,180,188,191,196,204,212,220,228,236,244,252,228,196,164,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,124,156,188,220,252,244,236,228,220,212,204,196,188,183,180,172,164,164,156,151,148,148,140,140,135,132,132,127,124,124,124,124,119,119,119,116,116,116,119,119,119,124,124,124,124,132,132,132,135,140,143,148,148,156,159,164,172,172,180,188,196,199,204,212,220,228,236,247,236,204,172,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,124,156,191,228,252,239,231,223,215,207,199,191,188,180,172,167,164,156,151,148,143,140,135,132,127,124,124,119,116,116,116,116,111,111,108,108,108,108,108,108,111,111,116,116,116,116,119,124,124,127,132,132,140,140,148,148,156,159,164,172,175,180,188,196,204,212,220,228,236,244,244,207,175,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,124,159,196,228,247,239,228,220,212,204,196,188,180,175,172,164,156,151,148,140,140,132,132,124,124,119,116,116,111,108,108,108,108,103,100,100,100,100,100,100,100,100,103,103,108,108,108,111,116,116,116,124,124,127,132,135,140,148,148,156,159,164,172,180,188,196,199,207,215,228,236,244,244,212,180,143,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,159,196,228,247,236,228,220,212,204,196,188,180,172,164,159,156,148,143,140,132,132,124,124,116,116,111,108,108,103,100,100,100,100,95,92,92,92,92,92,92,92,92,95,95,100,100,100,100,108,108,108,116,116,119,124,127,132,135,140,148,151,156,164,172,175,183,188,196,204,212,223,236,244,247,212,180,140,108,68,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,84,124,156,196,228,247,236,228,220,212,199,191,183,180,172,164,156,148,148,140,132,132,124,119,116,116,108,108,103,100,100,95,92,92,92,92,87,87,84,84,84,84,84,84,84,87,87,92,92,92,95,100,100,100,103,108,111,116,116,124,127,132,140,140,148,156,159,164,172,180,188,196,204,212,220,231,244,247,212,175,140,103,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,116,156,191,228,247,236,228,220,207,199,191,183,175,167,164,156,148,140,135,132,124,124,116,111,108,108,100,100,95,92,92,87,84,84,84,84,79,79,79,76,76,76,76,79,79,79,84,84,84,84,87,92,92,92,100,100,103,108,108,116,119,124,127,132,140,148,151,156,164,172,180,188,196,204,212,220,231,244,247,212,172,135,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,108,148,188,228,247,236,228,220,207,199,188,180,172,164,159,151,148,140,132,127,124,116,116,108,108,100,100,92,92,87,84,84,84,79,76,76,76,76,76,71,71,71,71,71,71,71,76,76,76,76,76,79,84,84,87,92,92,95,100,103,108,111,116,119,124,132,135,140,148,156,164,172,180,188,196,204,212,220,231,244,244,204,167,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,220,252,239,228,220,207,199,188,180,172,164,156,151,143,140,132,124,119,116,108,108,100,100,92,92,87,84,84,79,76,76,76,71,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,71,76,76,76,79,84,84,92,92,95,100,103,108,116,116,124,127,132,140,148,156,164,172,180,188,196,204,212,223,236,244,236,199,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,132,172,212,252,239,228,220,212,199,188,180,172,164,156,148,143,135,132,124,116,116,108,103,100,92,92,87,84,79,76,76,71,68,68,68,68,63,60,60,60,60,60,60,60,60,60,60,60,60,63,63,68,68,68,71,76,76,79,84,84,92,92,95,100,108,108,116,124,127,132,140,148,156,164,172,180,188,196,204,212,223,236,244,231,191,151,111,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,124,164,204,244,244,231,220,212,199,191,180,172,164,156,148,140,135,127,124,116,111,108,100,95,92,87,84,79,76,76,71,68,68,63,60,60,60,60,55,55,55,52,52,52,52,52,52,52,55,55,60,60,60,60,63,68,68,68,76,76,79,84,84,92,92,100,103,108,116,119,124,132,140,148,156,164,172,180,188,196,204,215,228,236,252,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,108,148,188,231,244,236,223,212,204,191,183,172,164,156,148,140,135,127,124,116,108,103,100,92,92,84,84,76,76,71,68,68,63,60,60,60,55,52,52,52,52,52,52,47,47,47,47,47,52,52,52,52,52,52,55,60,60,60,63,68,68,76,76,79,84,87,92,100,100,108,111,116,124,132,140,148,156,164,172,180,188,196,207,220,228,239,252,212,172,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,92,135,180,220,252,236,228,215,204,196,183,175,164,156,148,140,135,127,124,116,108,103,100,92,87,84,79,76,71,68,68,63,60,60,55,52,52,52,47,47,44,44,44,44,44,44,44,44,44,44,44,44,44,47,52,52,52,52,55,60,60,63,68,68,76,76,84,84,92,95,100,108,111,116,124,132,140,148,156,164,172,180,188,199,212,220,231,244,239,196,156,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,204,244,244,228,220,207,196,188,180,167,159,151,143,135,127,124,116,108,100,100,92,87,84,76,76,68,68,63,60,60,55,52,52,47,44,44,44,44,44,39,39,39,39,36,36,36,39,39,39,44,44,44,44,44,47,52,52,52,55,60,60,68,68,71,76,79,84,92,92,100,108,111,116,124,132,140,148,156,164,172,180,191,204,212,223,236,247,228,183,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,228,244,236,220,212,199,188,180,172,164,151,143,135,127,124,116,108,100,100,92,84,84,76,76,68,68,60,60,55,52,52,47,44,44,44,39,39,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,39,44,44,44,47,52,52,52,60,60,63,68,71,76,79,84,92,92,100,108,111,116,124,132,140,148,156,164,172,183,196,204,215,228,239,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,124,172,212,252,236,228,212,204,191,180,172,164,156,148,140,132,124,116,108,100,100,92,84,84,76,71,68,63,60,60,52,52,47,44,44,44,39,36,36,36,36,36,31,31,31,28,28,28,28,28,31,31,31,36,36,36,36,36,39,44,44,47,52,52,55,60,60,68,68,76,76,84,87,92,100,108,111,119,124,132,140,148,156,167,180,188,196,207,220,231,244,236,191,148,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,148,196,236,244,228,220,207,196,188,175,164,156,148,140,132,124,116,108,103,100,92,84,79,76,71,68,63,60,55,52,52,44,44,44,39,36,36,36,31,31,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,31,36,36,36,36,39,44,44,47,52,52,60,60,68,68,76,76,84,87,92,100,108,116,119,127,135,143,151,164,172,180,191,204,212,223,236,252,215,172,127,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,132,172,220,252,236,223,212,199,188,180,172,159,148,140,132,124,116,111,103,100,92,84,84,76,71,68,60,60,52,52,47,44,44,39,36,36,36,31,28,28,28,28,28,23,23,23,23,23,23,23,23,23,23,28,28,28,28,28,31,31,36,36,36,44,44,44,52,52,55,60,63,68,76,76,84,92,95,100,108,116,124,132,140,148,156,164,172,183,196,204,220,228,244,239,196,151,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,151,196,239,244,228,220,204,196,183,172,164,156,148,135,127,119,116,108,100,92,87,84,76,71,68,60,60,52,52,47,44,44,36,36,36,31,28,28,28,28,23,23,20,20,20,20,20,20,20,20,20,20,20,20,20,23,28,28,28,28,31,36,36,36,39,44,44,52,52,55,60,63,68,76,79,84,92,95,100,108,116,124,132,140,148,156,167,180,188,199,212,223,236,247,220,172,127,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,124,172,220,247,236,223,212,199,188,180,167,156,148,140,132,124,116,108,100,92,87,84,76,71,68,60,60,52,52,44,44,39,36,36,31,28,28,28,28,23,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,23,23,28,28,28,31,36,36,39,44,44,47,52,55,60,63,68,76,79,84,92,100,103,111,119,127,135,143,156,164,172,183,196,204,220,228,244,239,196,148,103,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,100,148,191,236,244,228,220,204,196,180,172,164,151,143,132,124,116,108,103,95,92,84,76,76,68,63,60,52,52,44,44,39,36,36,31,28,28,28,23,20,20,20,20,20,15,15,15,15,12,12,12,12,12,15,15,15,20,20,20,20,20,23,23,28,28,28,36,36,36,44,44,47,52,55,60,68,68,76,84,87,92,100,108,116,124,132,140,148,156,167,180,188,199,212,223,236,252,215,172,124,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,119,164,212,252,236,223,212,199,188,180,164,156,148,140,132,124,116,108,100,92,84,79,76,68,63,60,52,52,44,44,39,36,36,31,28,28,23,20,20,20,20,20,15,15,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,20,23,28,28,28,31,36,36,44,44,47,52,60,60,68,71,76,84,92,95,100,108,116,124,132,140,151,164,172,180,196,204,220,228,244,236,188,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,183,228,244,231,220,204,196,183,172,164,151,140,132,124,116,108,100,92,87,84,76,68,68,60,55,52,47,44,39,36,36,31,28,28,23,20,20,20,20,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,20,28,28,28,31,36,36,44,44,52,52,60,60,68,76,79,84,92,100,108,116,124,132,140,148,156,167,180,188,199,212,223,236,252,207,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,247,239,228,212,204,188,180,167,156,148,140,132,119,111,108,100,92,84,76,71,68,60,60,52,47,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,12,12,12,7,7,7,7,7,7,7,7,12,12,12,12,12,12,12,15,15,20,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,84,87,92,100,108,116,124,132,140,151,164,172,183,196,207,220,231,244,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,247,236,220,207,196,183,172,164,151,143,132,124,116,108,100,92,87,79,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,12,12,7,7,7,7,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,15,20,20,20,23,28,28,31,36,39,44,47,52,55,60,68,71,76,84,92,100,108,111,124,132,140,148,156,167,180,188,204,212,228,239,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,244,228,215,204,191,180,172,156,148,140,132,124,116,108,100,92,84,76,71,68,60,55,52,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,60,63,68,76,79,87,92,100,108,116,124,132,143,156,164,172,188,196,212,220,236,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,236,228,212,199,188,175,164,156,148,135,124,116,108,100,92,87,79,76,68,63,60,52,47,44,39,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,55,60,68,71,76,84,92,100,108,116,124,132,140,148,159,172,180,196,204,220,231,244,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,71,119,167,215,247,236,220,207,196,183,172,164,151,140,132,124,116,108,100,92,84,76,71,68,60,55,52,44,44,36,36,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,23,28,28,31,36,39,44,47,52,60,63,68,76,84,87,95,100,108,116,127,135,148,156,167,180,188,204,212,228,244,239,191,143,95,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,244,228,220,204,191,180,172,156,148,140,127,119,111,103,95,87,84,76,68,63,60,52,47,44,39,36,31,28,28,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,36,36,44,44,52,55,60,68,71,76,84,92,100,108,116,124,132,143,156,164,172,188,196,212,223,236,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,143,191,244,239,228,212,204,188,180,164,156,148,135,124,116,108,100,92,84,79,71,68,60,55,52,44,44,36,36,28,28,23,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,28,28,31,36,39,44,47,52,60,63,68,76,84,92,95,103,111,124,132,140,148,159,172,183,196,207,220,236,247,215,167,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,236,223,212,196,188,172,164,151,140,132,124,116,108,100,92,84,76,68,63,60,52,47,44,39,36,31,28,28,20,20,20,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,36,36,44,44,52,55,60,68,76,79,87,92,100,108,116,127,140,148,156,167,180,191,204,220,228,244,228,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,247,236,220,207,196,183,172,159,148,140,132,119,111,103,95,87,84,76,68,60,60,52,44,44,36,36,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,28,28,31,36,39,44,52,52,60,68,71,76,84,92,100,108,116,124,132,143,156,164,180,188,204,212,228,244,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,244,231,220,204,191,180,172,156,148,140,127,116,108,100,92,84,79,76,68,60,55,52,44,39,36,31,28,28,20,20,20,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,132,140,151,164,172,188,196,212,228,236,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,244,228,215,204,188,180,164,156,148,135,124,116,108,100,92,84,76,71,68,60,52,47,44,39,36,31,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,20,20,20,28,28,36,36,44,44,52,55,60,68,76,84,87,95,103,111,124,132,140,148,164,172,183,196,212,220,236,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,244,228,212,199,188,175,164,156,143,132,124,116,108,100,92,84,76,68,63,60,52,47,44,36,36,28,28,23,20,20,15,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,39,44,52,55,60,68,76,79,87,92,100,108,119,127,140,148,159,172,180,196,207,220,236,247,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,148,196,244,239,228,212,199,188,172,164,151,140,132,124,116,108,100,92,84,76,68,60,55,52,44,44,36,36,28,28,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,39,44,47,52,60,68,71,76,84,92,100,108,116,127,140,148,156,172,180,191,204,220,231,244,220,172,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,252,236,223,212,196,188,172,164,151,140,132,124,111,103,95,87,79,76,68,60,55,52,44,39,36,31,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,23,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,135,148,156,167,180,191,204,220,228,244,223,175,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,108,156,204,252,236,220,212,196,183,172,159,148,140,132,119,111,100,92,87,79,76,68,60,55,52,44,39,36,31,28,23,20,20,15,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,180,188,204,215,228,244,228,180,132,79,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,207,252,236,220,207,196,183,172,159,148,140,127,119,108,100,92,84,79,71,68,60,52,52,44,39,36,31,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,36,36,44,44,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,180,188,204,212,228,244,231,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,236,220,207,196,180,172,159,148,140,127,119,108,100,92,84,76,71,68,60,52,47,44,39,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,143,156,164,175,188,204,212,228,244,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,236,220,207,196,180,172,156,148,140,127,116,108,100,92,84,76,71,68,60,52,47,44,36,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,140,156,164,175,188,199,212,228,244,236,188,135,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,236,220,207,196,180,172,156,148,140,127,116,108,100,92,84,76,71,68,60,52,47,44,36,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,140,156,164,175,188,199,212,228,244,236,188,140,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,236,220,207,196,180,172,159,148,140,127,116,108,100,92,84,76,71,68,60,52,47,44,36,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,143,156,164,175,188,199,212,228,244,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,236,220,207,196,180,172,159,148,140,127,119,108,100,92,84,79,71,68,60,52,47,44,39,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,143,156,164,175,188,204,212,228,244,236,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,236,220,207,196,183,172,159,148,140,132,119,111,100,92,84,79,71,68,60,52,52,44,39,36,31,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,36,36,44,44,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,180,188,204,215,228,244,231,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,103,151,204,252,236,223,212,196,183,172,164,148,140,132,119,111,103,95,87,79,76,68,60,55,52,44,39,36,31,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,23,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,135,148,156,164,180,188,204,215,228,244,228,180,127,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,247,236,223,212,196,188,172,164,151,140,132,124,116,103,95,87,84,76,68,60,55,52,44,44,36,31,28,28,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,36,36,44,47,52,60,68,71,76,84,92,100,108,116,124,135,148,156,167,180,191,204,220,231,244,220,172,124,76,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,239,228,212,199,188,175,164,156,140,132,124,116,108,100,92,84,76,68,63,60,52,44,44,36,36,28,28,20,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,39,44,52,52,60,68,71,79,84,92,100,108,116,127,140,148,156,172,180,196,204,220,236,247,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,244,228,212,204,188,180,164,156,143,132,124,116,108,100,92,84,76,68,63,60,52,47,44,36,36,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,79,87,95,103,111,119,132,140,148,159,172,183,196,207,220,236,252,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,79,127,180,228,244,228,220,204,191,180,167,156,148,135,124,116,108,100,92,84,76,71,68,60,52,52,44,39,36,31,28,28,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,36,36,44,44,52,60,60,68,76,84,92,100,108,116,124,132,140,151,164,172,188,196,212,223,236,252,204,156,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,119,172,220,247,236,220,204,196,180,172,159,148,140,132,119,111,100,95,87,79,76,68,60,55,52,44,44,36,36,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,39,44,47,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,175,188,199,212,228,239,244,196,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,159,207,252,236,220,212,196,183,172,164,151,140,132,124,116,108,100,92,84,76,68,63,60,52,47,44,36,36,31,28,23,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,31,36,44,44,52,55,60,68,71,79,84,92,100,108,116,124,135,148,156,167,180,188,204,215,228,244,236,183,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,239,228,212,199,188,175,164,156,143,132,124,116,108,100,92,84,76,71,68,60,52,52,44,39,36,31,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,31,36,36,44,47,52,60,60,68,76,84,87,95,103,111,119,132,140,148,159,172,180,196,204,220,231,244,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,244,228,215,204,188,180,167,156,148,135,127,116,108,100,92,87,79,76,68,60,55,52,47,44,36,36,31,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,39,44,52,52,60,68,68,76,84,92,100,108,116,124,132,140,151,164,172,183,196,212,220,236,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,244,231,220,204,196,180,172,159,148,140,132,124,116,103,100,92,84,76,68,63,60,52,52,44,39,36,36,28,28,23,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,55,60,68,76,79,84,92,100,108,116,124,135,143,156,164,175,188,199,212,228,239,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,236,223,212,196,188,172,164,156,143,132,124,116,108,100,92,84,79,76,68,60,55,52,47,44,36,36,31,28,28,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,36,36,39,44,52,52,60,63,68,76,84,92,95,103,111,119,132,140,148,156,172,180,191,204,215,228,244,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,239,228,212,204,188,180,167,156,148,140,127,119,111,103,95,92,84,76,68,63,60,52,52,44,44,36,36,28,28,28,20,20,20,15,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,31,36,39,44,47,52,55,60,68,76,79,84,92,100,108,116,124,132,140,151,164,172,183,196,207,220,236,247,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,244,231,220,204,196,180,172,164,148,140,132,124,116,108,100,92,84,79,76,68,60,60,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,84,87,95,103,108,119,127,135,148,156,164,180,188,199,212,228,236,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,236,223,212,196,188,175,164,156,148,135,127,116,108,103,95,92,84,76,68,68,60,55,52,44,44,39,36,31,28,28,23,20,20,20,15,15,12,12,12,12,12,12,7,7,7,7,7,7,7,7,7,7,7,12,12,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,60,60,68,76,79,84,92,100,108,116,124,132,140,148,159,172,180,191,204,220,228,244,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,239,244,228,215,204,191,180,172,159,148,140,132,124,116,108,100,92,84,79,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,20,20,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,23,28,28,31,36,36,39,44,47,52,55,60,68,71,76,84,92,95,103,108,116,127,135,148,156,164,175,188,196,212,220,236,247,215,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,220,247,236,220,207,196,188,172,164,156,148,135,127,119,111,103,95,92,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,28,23,20,20,20,15,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,20,23,28,28,31,36,36,39,44,47,52,55,60,63,68,76,84,87,92,100,108,116,124,132,140,148,159,172,180,191,204,212,228,239,244,196,151,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,156,204,247,239,228,212,204,188,180,172,159,148,140,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,44,36,36,31,28,28,28,23,20,20,20,20,20,15,15,12,12,12,12,12,12,12,12,12,12,15,15,15,20,20,20,20,23,28,28,28,31,36,36,39,44,44,52,52,60,63,68,76,79,84,92,100,103,111,119,127,135,148,156,164,172,188,196,207,220,236,244,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,135,180,228,244,231,220,207,196,188,172,164,156,148,140,127,119,116,108,100,92,84,79,76,68,68,60,55,52,47,44,44,36,36,36,31,28,28,28,23,20,20,20,20,20,20,15,15,15,15,15,15,15,15,20,20,20,20,20,20,23,23,28,28,28,31,36,36,39,44,44,52,52,60,60,68,71,76,84,92,95,100,108,116,124,132,140,148,159,172,180,188,204,212,228,239,252,204,159,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,164,204,252,236,228,212,204,191,180,172,159,151,140,132,124,116,108,103,100,92,84,79,76,68,63,60,55,52,47,44,44,39,36,36,31,28,28,28,28,23,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,23,23,28,28,28,31,36,36,36,44,44,47,52,52,60,60,68,71,76,84,87,92,100,108,116,124,132,140,148,156,164,175,188,196,207,220,231,244,228,183,140,92,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,95,140,183,228,244,231,220,207,196,188,175,164,156,148,140,132,124,116,108,100,95,92,84,76,76,68,63,60,55,52,52,44,44,39,36,36,36,31,28,28,28,28,28,23,23,20,20,20,20,20,20,20,20,23,23,23,28,28,28,28,31,31,36,36,39,44,44,47,52,52,60,60,68,71,76,84,84,92,100,108,111,119,127,135,143,151,164,172,180,191,204,212,228,239,252,207,164,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,204,252,239,228,215,204,196,180,172,164,156,148,135,127,124,116,108,100,92,92,84,76,76,68,63,60,60,52,52,47,44,44,39,36,36,36,31,28,28,28,28,28,28,28,28,28,23,28,28,28,28,28,28,28,28,31,31,36,36,36,39,44,44,47,52,55,60,60,68,71,76,84,84,92,100,103,108,116,124,132,140,148,156,167,180,188,196,212,220,236,244,228,183,140,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,92,140,180,228,244,236,220,212,199,188,180,172,159,151,140,132,127,119,111,108,100,92,87,84,76,76,68,68,60,60,52,52,47,44,44,44,39,36,36,36,36,31,31,28,28,28,28,28,28,28,28,28,28,28,31,31,36,36,36,36,39,44,44,47,52,52,55,60,63,68,71,76,84,84,92,100,103,108,116,124,132,140,148,156,164,172,183,196,204,215,228,239,247,204,159,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,204,244,244,228,220,204,196,188,175,164,156,148,140,132,124,116,111,108,100,92,87,84,79,76,68,68,60,60,55,52,52,47,44,44,44,39,36,36,36,36,36,36,36,31,31,31,31,31,36,36,36,36,36,36,39,44,44,44,44,52,52,52,60,60,63,68,71,76,84,84,92,100,100,108,116,124,132,140,148,156,164,172,180,188,204,212,223,236,247,220,180,135,92,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,252,236,228,212,204,196,183,172,164,156,148,140,132,124,116,111,108,100,92,92,84,79,76,71,68,63,60,60,55,52,52,47,44,44,44,44,39,39,36,36,36,36,36,36,36,36,36,36,36,39,44,44,44,44,47,52,52,52,55,60,60,68,68,76,76,84,84,92,100,100,108,116,124,127,135,143,151,159,172,180,188,196,207,220,231,244,236,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,191,231,244,236,220,212,199,188,180,172,164,156,148,140,132,124,116,111,108,100,95,92,84,84,76,76,68,68,63,60,60,55,52,52,52,47,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,47,52,52,52,55,60,60,63,68,71,76,79,84,87,92,100,103,108,116,124,127,135,140,148,156,167,175,188,196,204,215,228,239,252,212,172,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,79,124,164,204,244,244,228,220,207,196,188,180,172,164,156,148,140,132,124,116,111,108,100,95,92,87,84,79,76,71,68,68,63,60,60,55,52,52,52,52,47,47,47,44,44,44,44,44,44,44,47,47,52,52,52,52,55,60,60,60,63,68,68,76,76,84,84,92,92,100,103,108,116,124,127,132,140,148,156,164,172,183,196,204,212,223,236,247,228,183,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,135,175,215,252,236,228,215,204,196,188,180,172,164,156,148,140,132,124,119,116,108,100,100,92,92,84,84,76,76,71,68,68,63,60,60,60,55,55,52,52,52,52,52,52,52,52,52,52,52,52,52,55,60,60,60,60,68,68,68,76,76,79,84,87,92,95,100,108,108,116,124,127,135,140,148,156,164,172,180,191,204,212,220,236,244,236,196,156,116,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,148,188,228,247,236,228,212,204,196,188,180,172,164,156,148,140,132,124,119,116,108,103,100,95,92,87,84,79,76,76,71,68,68,68,63,60,60,60,60,60,60,55,55,55,55,55,60,60,60,60,60,60,63,68,68,68,76,76,79,84,84,92,92,100,100,108,111,116,124,132,135,140,148,156,164,172,180,188,199,212,220,228,244,244,207,167,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,116,156,196,236,244,236,223,212,204,196,188,180,172,164,156,148,140,132,127,124,116,111,108,100,100,92,92,87,84,84,76,76,76,71,68,68,68,68,63,63,63,60,60,60,60,60,63,63,68,68,68,68,68,71,76,76,79,84,84,87,92,95,100,103,108,116,119,124,132,140,143,148,156,164,172,180,188,199,207,220,228,239,252,215,175,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,124,164,204,244,244,236,220,212,204,196,188,180,172,164,156,148,140,135,132,124,119,116,108,108,100,100,92,92,87,84,84,79,76,76,76,76,71,68,68,68,68,68,68,68,68,68,68,71,71,76,76,76,79,84,84,84,92,92,95,100,103,108,111,116,124,127,132,140,148,151,156,164,172,180,188,199,207,220,228,236,252,220,183,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,132,172,207,244,244,231,220,212,204,196,188,180,172,164,156,148,143,140,132,127,124,116,116,108,108,100,100,95,92,92,87,84,84,84,79,76,76,76,76,76,76,76,76,76,76,76,76,79,79,84,84,84,87,92,92,95,100,103,108,108,116,119,124,132,135,140,148,156,159,167,172,180,188,199,207,220,228,236,247,228,188,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,63,100,140,175,212,247,244,231,220,212,204,196,188,180,172,164,156,151,148,140,135,132,124,124,116,111,108,108,100,100,95,92,92,92,87,87,84,84,84,84,84,84,84,84,84,84,84,84,84,87,92,92,92,95,100,100,103,108,108,116,116,124,127,132,140,143,148,156,164,172,175,183,191,199,207,220,228,236,247,228,196,156,119,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,140,180,212,247,244,231,223,212,204,196,188,180,172,167,164,156,148,143,140,132,132,124,124,116,116,108,108,103,100,100,100,95,92,92,92,92,92,92,92,92,92,92,92,92,92,92,95,100,100,100,103,108,108,111,116,119,124,127,132,135,140,148,151,156,164,172,180,188,196,204,212,220,228,236,247,231,196,159,124,84,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,143,180,212,247,244,236,223,215,207,199,191,183,180,172,164,156,156,148,140,140,132,132,124,124,116,116,111,108,108,108,103,100,100,100,100,100,100,100,100,100,100,100,100,100,100,103,108,108,108,111,116,116,119,124,127,132,135,140,148,148,156,164,167,172,180,188,196,204,212,220,228,236,247,228,196,159,124,92,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,175,212,244,244,236,228,220,212,204,196,188,180,172,167,164,156,151,148,140,140,132,132,127,124,124,116,116,116,111,108,108,108,108,108,108,108,108,108,108,108,108,108,108,111,116,116,116,119,124,124,132,132,135,140,148,148,156,159,164,172,180,183,188,196,204,212,220,228,239,252,228,196,159,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,172,204,236,244,236,228,220,212,204,196,191,183,180,172,167,164,156,151,148,143,140,135,132,132,127,124,124,124,119,116,116,116,116,116,116,116,116,116,116,116,116,116,119,124,124,124,132,132,135,140,140,148,148,156,159,164,172,175,180,188,196,204,207,215,223,236,244,252,220,188,156,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,68,103,135,167,199,231,252,239,231,223,215,207,204,196,188,183,180,172,167,164,156,156,148,148,143,140,140,132,132,132,127,127,124,124,124,124,124,124,124,124,124,124,124,127,132,132,132,135,140,140,143,148,151,156,159,164,172,172,180,188,191,196,204,212,220,228,236,244,244,215,183,151,119,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,164,191,220,252,244,236,228,220,212,204,199,196,188,180,180,172,167,164,159,156,156,148,148,143,140,140,140,140,135,132,132,132,132,132,132,132,132,135,135,140,140,140,143,148,148,151,156,156,164,164,172,175,180,188,188,196,204,212,215,223,231,239,247,236,207,175,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,151,180,212,239,247,239,231,223,220,212,204,199,196,188,183,180,172,172,167,164,159,156,156,151,148,148,148,148,143,143,143,140,140,143,143,143,148,148,148,148,151,156,156,159,164,164,172,172,180,180,188,191,196,204,207,212,220,228,236,244,252,228,196,167,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,111,140,172,196,228,252,244,236,228,223,220,212,204,199,196,188,188,180,180,172,172,167,164,164,164,159,156,156,156,156,156,156,156,156,156,156,156,156,156,159,164,164,167,172,172,175,180,183,188,191,196,204,207,212,220,228,236,239,247,236,212,183,156,127,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,71,100,132,156,183,212,236,252,244,236,228,223,220,212,207,204,196,196,188,188,183,180,180,172,172,172,172,167,164,164,164,164,164,164,164,164,164,167,172,172,172,175,180,180,183,188,191,196,199,204,212,212,220,228,231,239,244,247,220,196,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,87,116,140,164,191,215,239,247,244,236,228,223,220,212,212,204,204,196,196,191,188,188,183,180,180,180,180,180,175,175,175,175,175,180,180,180,180,183,188,188,188,196,196,199,204,207,212,220,220,228,236,239,244,252,228,204,180,156,127,100,76,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,71,100,124,148,172,196,220,239,252,244,236,231,228,220,220,212,212,207,204,204,196,196,196,191,191,188,188,188,188,188,188,188,188,188,191,196,196,196,199,204,204,212,212,215,220,228,228,236,239,244,252,228,207,183,159,135,111,84,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,79,108,127,151,172,196,215,236,252,244,239,236,231,228,223,220,220,212,212,212,207,204,204,204,204,204,199,199,199,204,204,204,204,204,207,212,212,215,220,220,228,228,236,236,244,247,244,228,204,183,164,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,108,127,148,172,188,207,228,244,252,244,244,236,236,228,228,228,220,220,220,220,215,212,212,212,212,212,212,215,215,220,220,220,223,228,228,231,236,239,244,247,252,236,215,196,180,159,140,116,95,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,103,124,143,164,180,196,212,228,239,252,247,244,244,236,236,236,231,228,228,228,228,228,228,228,228,228,228,231,236,236,236,239,244,244,252,244,236,220,204,188,172,151,132,116,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,60,76,95,116,132,148,164,180,191,204,215,228,236,247,252,247,244,244,244,244,244,244,244,244,244,244,244,244,247,252,252,244,236,220,212,196,188,172,156,140,124,108,87,68,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,68,84,100,116,132,143,156,167,180,188,196,204,212,220,223,228,231,236,236,236,236,236,231,228,220,215,212,204,196,183,172,164,148,140,124,108,92,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,68,84,95,108,119,132,140,148,156,164,172,175,180,180,188,188,188,188,183,180,180,172,167,159,156,143,135,124,116,100,92,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,60,71,84,92,100,108,116,119,124,132,132,135,135,140,135,132,132,127,124,116,111,103,95,84,76,68,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,60,68,71,76,79,84,84,87,87,84,84,84,76,76,68,60,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,28,36,36,36,36,36,36,31,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t * FLARE_TEXTURES[6] ={
|
|
FLARE_TEXTURE_0,
|
|
FLARE_TEXTURE_1,
|
|
FLARE_TEXTURE_2,
|
|
FLARE_TEXTURE_3,
|
|
FLARE_TEXTURE_4,
|
|
FLARE_TEXTURE_5,
|
|
};
|
|
const int FLARE_TEXTURE_WIDTHS[10] = {
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
};
|
|
const int FLARE_TEXTURE_HEIGHTS[10] = {
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
};
|
|
}
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_lens_flare = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_LENS_FLARE_H
|
|
#define IGL_OPENGL2_LENS_FLARE_H
|
|
|
|
#include "../opengl/OpenGL_convenience.h"
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
|
|
struct Flare{
|
|
int type; /* flare texture index, 0..5 */
|
|
float scale;
|
|
float loc; /* postion on axis */
|
|
float color[3];
|
|
Flare():
|
|
type(-1),
|
|
scale(0),
|
|
loc(0)
|
|
{}
|
|
Flare(int type, float location, float scale, const float color[3], float colorScale) :
|
|
type(type),
|
|
scale(scale),
|
|
loc(location)
|
|
{
|
|
this->color[0] = color[0] * colorScale;
|
|
this->color[1] = color[1] * colorScale;
|
|
this->color[2] = color[2] * colorScale;
|
|
}
|
|
};
|
|
|
|
|
|
// Initialize shared data for lens flates
|
|
//
|
|
// Inputs:
|
|
// start_id starting texture id location (should have at least id:id+16 free)
|
|
// Outputs:
|
|
// shine list of texture ids for shines
|
|
// flare list of texture ids for flares
|
|
IGL_INLINE void lens_flare_load_textures(
|
|
std::vector<GLuint> & shine_ids,
|
|
std::vector<GLuint> & flare_ids);
|
|
|
|
// Create a set of lens flares
|
|
//
|
|
// Inputs:
|
|
// A primary color
|
|
// B secondary color
|
|
// C secondary color
|
|
// Outputs:
|
|
// flares list of flare objects
|
|
IGL_INLINE void lens_flare_create(
|
|
const float * A,
|
|
const float * B,
|
|
const float * C,
|
|
std::vector<Flare> & flares);
|
|
|
|
// Draw lens flares
|
|
//
|
|
// Inputs:
|
|
// flares list of Flare objects
|
|
// shine_ids list of shine textures
|
|
// flare_ids list of flare texture ids
|
|
// light position of light
|
|
// near_clip near clipping plane
|
|
// shine_tic current "tic" in shine textures
|
|
// Outputs:
|
|
// shine_tic current "tic" in shine textures
|
|
IGL_INLINE void lens_flare_draw(
|
|
const std::vector<Flare> & flares,
|
|
const std::vector<GLuint> & shine_ids,
|
|
const std::vector<GLuint> & flare_ids,
|
|
const Eigen::Vector3f & light,
|
|
const float near_clip,
|
|
int & shine_tic);
|
|
}
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "lens_flare.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_model_proj_viewport = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_MODEL_PROJ_VIEW_H
|
|
#define IGL_OPENGL2_MODEL_PROJ_VIEW_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Collect the model-view, projection and viewport matrices
|
|
//
|
|
// Outputs:
|
|
// model 4x4 modelview matrix
|
|
// proj 4x4 projection matrix
|
|
// viewport 4x1 viewport vector
|
|
//
|
|
template <typename Derivedmodel, typename Derivedproj, typename Derivedviewport>
|
|
IGL_INLINE void model_proj_viewport(
|
|
Eigen::PlainObjectBase<Derivedmodel> & model,
|
|
Eigen::PlainObjectBase<Derivedproj> & proj,
|
|
Eigen::PlainObjectBase<Derivedviewport> & viewport);
|
|
}
|
|
}
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "model_proj_viewport.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_MouseController = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_MOUSECONTROLLER_H
|
|
#define IGL_OPENGL2_MOUSECONTROLLER_H
|
|
// Needs to be included before others
|
|
#include <Eigen/StdVector>
|
|
#include "RotateWidget.h"
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
#include <vector>
|
|
|
|
// Class for control a skeletal FK rig with the mouse.
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
class MouseController
|
|
{
|
|
public:
|
|
typedef Eigen::VectorXi VectorXb;
|
|
// Propogate selection to descendants so that selected bones and their
|
|
// subtrees are all selected.
|
|
//
|
|
// Input:
|
|
// S #S list of whether selected
|
|
// P #S list of bone parents
|
|
// Output:
|
|
// T #S list of whether selected
|
|
static inline void propogate_to_descendants_if(
|
|
const VectorXb & S,
|
|
const Eigen::VectorXi & P,
|
|
VectorXb & T);
|
|
// Create a matrix of colors for the selection and their descendants.
|
|
//
|
|
// Inputs:
|
|
// selection #S list of whether a bone is selected
|
|
// selected_color color for selected bones
|
|
// unselected_color color for unselected bones
|
|
// Outputs:
|
|
// C #P by 4 list of colors
|
|
static inline void color_if(
|
|
const VectorXb & S,
|
|
const Eigen::Vector4f & selected_color,
|
|
const Eigen::Vector4f & unselected_color,
|
|
Eigen::MatrixXf & C);
|
|
private:
|
|
// m_is_selecting whether currently selecting
|
|
// m_selection #m_rotations list of whether a bone is selected
|
|
// m_down_x x-coordinate of mouse location at down
|
|
// m_down_y y-coordinate 〃
|
|
// m_drag_x x-coordinate of mouse location at drag
|
|
// m_drag_y y-coordinate 〃
|
|
// m_widget rotation widget for selected bone
|
|
// m_width width of containing window
|
|
// m_height height 〃
|
|
// m_rotations list of rotations for each bone
|
|
// m_rotations_at_selection list of rotations for each bone at time of
|
|
// selection
|
|
// m_fk_rotations_at_selection list of rotations for each bone at time of
|
|
// selection
|
|
// m_root_enabled Whether root is enabled
|
|
bool m_is_selecting;
|
|
VectorXb m_selection;
|
|
int m_down_x,m_down_y,m_drag_x,m_drag_y;
|
|
int m_width,m_height;
|
|
igl::opengl2::RotateWidget m_widget;
|
|
Eigen::Quaterniond m_widget_rot_at_selection;
|
|
typedef std::vector<
|
|
Eigen::Quaterniond,
|
|
Eigen::aligned_allocator<Eigen::Quaterniond> > RotationList;
|
|
RotationList
|
|
m_rotations,m_rotations_at_selection,m_fk_rotations_at_selection;
|
|
bool m_root_enabled;
|
|
public:
|
|
MouseController();
|
|
// Returns const reference to m_selection
|
|
inline const VectorXb & selection() const{return m_selection;};
|
|
// 〃 m_is_selecting
|
|
inline const bool & is_selecting() const{return m_is_selecting;}
|
|
inline bool is_widget_down() const{return m_widget.is_down();}
|
|
// 〃 m_rotations
|
|
inline const RotationList & rotations() const{return m_rotations;}
|
|
// Returns non-const reference to m_root_enabled
|
|
inline bool & root_enabled(){ return m_root_enabled;}
|
|
inline void reshape(const int w, const int h);
|
|
// Process down, drag, up mouse events
|
|
//
|
|
// Inputs:
|
|
// x x-coordinate of mouse click with respect to container
|
|
// y y-coordinate 〃
|
|
// Returns true if accepted (action taken).
|
|
inline bool down(const int x, const int y);
|
|
inline bool drag(const int x, const int y);
|
|
inline bool up(const int x, const int y);
|
|
// Draw selection box and widget
|
|
inline void draw() const;
|
|
// Set `m_selection` based on the last drag selection and initialize
|
|
// widget.
|
|
//
|
|
// Inputs:
|
|
// C #C by dim list of joint positions at rest
|
|
// BE #BE by 2 list of bone indices at rest
|
|
// P #P list of bone parents
|
|
inline void set_selection_from_last_drag(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::VectorXi & P,
|
|
const Eigen::VectorXi & RP);
|
|
// Set from explicit selection
|
|
inline void set_selection(
|
|
const Eigen::VectorXi & S,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::VectorXi & P,
|
|
const Eigen::VectorXi & RP);
|
|
// Set size of skeleton
|
|
//
|
|
// Inputs:
|
|
// n number of bones
|
|
inline void set_size(const int n);
|
|
// Resets m_rotation elements to identity
|
|
inline void reset_rotations();
|
|
inline void reset_selected_rotations();
|
|
inline bool set_rotations(const RotationList & vQ);
|
|
// Sets all entries in m_selection to false
|
|
inline void clear_selection();
|
|
// Returns true iff some element in m_selection is true
|
|
inline bool any_selection() const;
|
|
public:
|
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
|
};
|
|
}
|
|
}
|
|
|
|
// Implementation
|
|
#include "../line_segment_in_rectangle.h"
|
|
#include "draw_rectangular_marquee.h"
|
|
#include "project.h"
|
|
#include "../forward_kinematics.h"
|
|
#include "../matlab_format.h"
|
|
#include "../any_of.h"
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <functional>
|
|
|
|
inline void igl::opengl2::MouseController::propogate_to_descendants_if(
|
|
const VectorXb & S,
|
|
const Eigen::VectorXi & P,
|
|
VectorXb & T)
|
|
{
|
|
using namespace std;
|
|
const int n = S.rows();
|
|
assert(P.rows() == n);
|
|
// dynamic programming
|
|
T = S;
|
|
vector<bool> seen(n,false);
|
|
// Recursively look up chain and see if ancestor is selected
|
|
const function<bool(int)> look_up = [&](int e) -> bool
|
|
{
|
|
if(e==-1)
|
|
{
|
|
return false;
|
|
}
|
|
if(!seen[e])
|
|
{
|
|
seen[e] = true;
|
|
T(e) |= look_up(P(e));
|
|
}
|
|
return T(e);
|
|
};
|
|
for(int e = 0;e<n;e++)
|
|
{
|
|
if(!seen[e])
|
|
{
|
|
T(e) = look_up(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::color_if(
|
|
const VectorXb & S,
|
|
const Eigen::Vector4f & selected_color,
|
|
const Eigen::Vector4f & unselected_color,
|
|
Eigen::MatrixXf & C)
|
|
{
|
|
C.resize(S.rows(),4);
|
|
for(int e=0;e<S.rows();e++)
|
|
{
|
|
C.row(e) = S(e)?selected_color:unselected_color;
|
|
}
|
|
}
|
|
|
|
inline igl::opengl2::MouseController::MouseController():
|
|
m_is_selecting(false),
|
|
m_selection(),
|
|
m_down_x(-1),m_down_y(-1),m_drag_x(-1),m_drag_y(-1),
|
|
m_width(-1),m_height(-1),
|
|
m_widget(),
|
|
m_widget_rot_at_selection(),
|
|
m_rotations(),
|
|
m_rotations_at_selection(),
|
|
m_root_enabled(true)
|
|
{
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::reshape(const int w, const int h)
|
|
{
|
|
m_width = w;
|
|
m_height = h;
|
|
}
|
|
|
|
inline bool igl::opengl2::MouseController::down(const int x, const int y)
|
|
{
|
|
using namespace std;
|
|
m_down_x = m_drag_x =x;
|
|
m_down_y = m_drag_y =y;
|
|
const bool widget_down = any_selection() && m_widget.down(x,m_height-y);
|
|
if(!widget_down)
|
|
{
|
|
m_is_selecting = true;
|
|
}
|
|
return m_is_selecting || widget_down;
|
|
}
|
|
|
|
inline bool igl::opengl2::MouseController::drag(const int x, const int y)
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
m_drag_x = x;
|
|
m_drag_y = y;
|
|
if(m_is_selecting)
|
|
{
|
|
return m_is_selecting;
|
|
}else
|
|
{
|
|
if(!m_widget.drag(x,m_height-y))
|
|
{
|
|
return false;
|
|
}
|
|
assert(any_selection());
|
|
assert(m_selection.size() == (int)m_rotations.size());
|
|
for(int e = 0;e<m_selection.size();e++)
|
|
{
|
|
if(m_selection(e))
|
|
{
|
|
// Let:
|
|
// w.θr = w.θ ⋅ w.θ₀*
|
|
// w.θr takes (absolute) frame of w.θ₀ to w.θ:
|
|
// w.θ = w.θr ⋅ w.θ₀
|
|
// Define:
|
|
// w.θ₀ = θfk ⋅ θx,
|
|
// the absolute rotation of the x axis to the deformed bone at
|
|
// selection. Likewise,
|
|
// w.θ = θfk' ⋅ θx,
|
|
// the current absolute rotation of the x axis to the deformed bone.
|
|
// Define recursively:
|
|
// θfk = θfk(p) ⋅ Θr,
|
|
// then because we're only changeing this relative rotation
|
|
// θfk' = θfk(p) ⋅ Θr ⋅ θr* ⋅ θr'
|
|
// θfk' = θfk ⋅ θr* ⋅ θr'
|
|
// w.θ ⋅ θx* = θfk ⋅ θr* ⋅ θr'
|
|
// θr ⋅ θfk* ⋅ w.θ ⋅ θx* = θr'
|
|
// θr ⋅ θfk* ⋅ w.θr ⋅ w.θ₀ ⋅ θx* = θr'
|
|
// θr ⋅ θfk* ⋅ w.θr ⋅ θfk ⋅θx ⋅ θx* = θr'
|
|
// θr ⋅ θfk* ⋅ w.θr ⋅ θfk = θr'
|
|
// which I guess is the right multiply change after being changed to
|
|
// the bases of θfk, the rotation of the bone relative to its rest
|
|
// frame.
|
|
//
|
|
const Quaterniond & frame = m_fk_rotations_at_selection[e];
|
|
m_rotations[e] =
|
|
m_rotations_at_selection[e] *
|
|
frame.conjugate() *
|
|
(m_widget.rot*m_widget_rot_at_selection.conjugate()) *
|
|
frame;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
inline bool igl::opengl2::MouseController::up(const int x, const int y)
|
|
{
|
|
m_is_selecting = false;
|
|
m_widget.up(x,m_height-y);
|
|
return false;
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::draw() const
|
|
{
|
|
using namespace igl;
|
|
if(any_selection())
|
|
{
|
|
m_widget.draw();
|
|
}
|
|
if(m_is_selecting)
|
|
{
|
|
// Remember settings
|
|
GLboolean dt;
|
|
glGetBooleanv(GL_DEPTH_TEST,&dt);
|
|
int old_vp[4];
|
|
glGetIntegerv(GL_VIEWPORT,old_vp);
|
|
|
|
// True screen space
|
|
glViewport(0,0,m_width,m_height);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
gluOrtho2D(0,m_width,0,m_height);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
draw_rectangular_marquee(
|
|
m_down_x,
|
|
m_height-m_down_y,
|
|
m_drag_x,
|
|
m_height-m_drag_y);
|
|
|
|
// Restore settings
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
glViewport(old_vp[0],old_vp[1],old_vp[2],old_vp[3]);
|
|
dt?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::set_selection_from_last_drag(
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::VectorXi & P,
|
|
const Eigen::VectorXi & RP)
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
using namespace igl;
|
|
m_rotations_at_selection = m_rotations;
|
|
assert(BE.rows() == P.rows());
|
|
m_selection = VectorXb::Zero(BE.rows());
|
|
// m_rotation[e] is the relative rotation stored at bone e (as seen by the
|
|
// joint traveling with its parent)
|
|
// vQ[e] is the absolute rotation of a bone at rest to its current position:
|
|
// vQ[e] = vQ[p(e)] * m_rotation[e]
|
|
vector<Quaterniond,aligned_allocator<Quaterniond> > vQ;
|
|
vector<Vector3d> vT;
|
|
forward_kinematics(C,BE,P,m_rotations,vQ,vT);
|
|
// Loop over deformed bones
|
|
for(int e = 0;e<BE.rows();e++)
|
|
{
|
|
Affine3d a = Affine3d::Identity();
|
|
a.translate(vT[e]);
|
|
a.rotate(vQ[e]);
|
|
Vector3d s = a * (Vector3d)C.row(BE(e,0));
|
|
Vector3d d = a * (Vector3d)C.row(BE(e,1));
|
|
Vector3d projs = project(s);
|
|
Vector3d projd = project(d);
|
|
m_selection(e) = line_segment_in_rectangle(
|
|
projs.head(2),projd.head(2),
|
|
Vector2d(m_down_x,m_height-m_down_y),
|
|
Vector2d(m_drag_x,m_height-m_drag_y));
|
|
}
|
|
return set_selection(m_selection,C,BE,P,RP);
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::set_selection(
|
|
const Eigen::VectorXi & S,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::VectorXi & P,
|
|
const Eigen::VectorXi & RP)
|
|
{
|
|
using namespace igl;
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
vector<Quaterniond,aligned_allocator<Quaterniond> > & vQ =
|
|
m_fk_rotations_at_selection;
|
|
vector<Vector3d> vT;
|
|
forward_kinematics(C,BE,P,m_rotations,vQ,vT);
|
|
if(&m_selection != &S)
|
|
{
|
|
m_selection = S;
|
|
}
|
|
assert(m_selection.rows() == BE.rows());
|
|
assert(BE.rows() == P.rows());
|
|
assert(BE.rows() == RP.rows());
|
|
// Zero-out S up a path of ones from e
|
|
auto propagate = [&](const int e, const VectorXb & S, VectorXb & N)
|
|
{
|
|
if(S(e))
|
|
{
|
|
int f = e;
|
|
while(true)
|
|
{
|
|
int p = P(f);
|
|
if(p==-1||!S(p))
|
|
{
|
|
break;
|
|
}
|
|
N(f) = false;
|
|
f = p;
|
|
}
|
|
}
|
|
};
|
|
VectorXb prev_selection = m_selection;
|
|
// Combine upward, group rigid parts, repeat
|
|
while(true)
|
|
{
|
|
// Spread selection accross rigid pieces
|
|
VectorXb SRP(VectorXb::Zero(RP.maxCoeff()+1));
|
|
for(int e = 0;e<BE.rows();e++)
|
|
{
|
|
SRP(RP(e)) |= m_selection(e);
|
|
}
|
|
for(int e = 0;e<BE.rows();e++)
|
|
{
|
|
m_selection(e) = SRP(RP(e));
|
|
}
|
|
// Clear selections below m_selection ancestors
|
|
VectorXb new_selection = m_selection;
|
|
for(int e = 0;e<P.rows();e++)
|
|
{
|
|
propagate(e,m_selection,new_selection);
|
|
}
|
|
m_selection = new_selection;
|
|
if(m_selection==prev_selection)
|
|
{
|
|
break;
|
|
}
|
|
prev_selection = m_selection;
|
|
}
|
|
|
|
// Now selection should contain just bone roots of m_selection subtrees
|
|
if(any_of(m_selection))
|
|
{
|
|
// Taking average
|
|
m_widget.pos.setConstant(0);
|
|
m_widget_rot_at_selection.coeffs().setConstant(0);
|
|
m_widget.rot.coeffs().array().setConstant(0);
|
|
Quaterniond cur_rot(0,0,0,0);
|
|
int num_selection = 0;
|
|
// Compute average widget for selection
|
|
for(int e = 0;e<BE.rows();e++)
|
|
{
|
|
if(m_selection(e))
|
|
{
|
|
Vector3d s = C.row(BE(e,0));
|
|
Vector3d d = C.row(BE(e,1));
|
|
auto b = (d-s).transpose().eval();
|
|
{
|
|
Affine3d a = Affine3d::Identity();
|
|
a.translate(vT[e]);
|
|
a.rotate(vQ[e]);
|
|
m_widget.pos += a*s;
|
|
}
|
|
// Rotation of x axis to this bone
|
|
Quaterniond rot_at_bind;
|
|
rot_at_bind.setFromTwoVectors(Vector3d(1,0,0),b);
|
|
const Quaterniond abs_rot = vQ[e] * rot_at_bind;
|
|
m_widget_rot_at_selection.coeffs() += abs_rot.coeffs();
|
|
num_selection++;
|
|
}
|
|
}
|
|
// Take average
|
|
m_widget.pos.array() /= (double)num_selection;
|
|
m_widget_rot_at_selection.coeffs().array() /= (double)num_selection;
|
|
m_widget_rot_at_selection.normalize();
|
|
m_widget.rot = m_widget_rot_at_selection;
|
|
}
|
|
m_widget.m_is_enabled = true;
|
|
for(int s = 0;s<m_selection.rows();s++)
|
|
{
|
|
// a root is selected then disable.
|
|
if(!m_root_enabled && m_selection(s) && P(s) == -1)
|
|
{
|
|
m_widget.m_is_enabled = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::set_size(const int n)
|
|
{
|
|
using namespace Eigen;
|
|
clear_selection();
|
|
m_rotations.clear();
|
|
m_rotations.resize(n,Quaterniond::Identity());
|
|
m_selection = VectorXb::Zero(n);
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::reset_rotations()
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
fill(m_rotations.begin(),m_rotations.end(),Quaterniond::Identity());
|
|
// cop out. just clear selection
|
|
clear_selection();
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::reset_selected_rotations()
|
|
{
|
|
using namespace Eigen;
|
|
for(int e = 0;e<m_selection.size();e++)
|
|
{
|
|
if(m_selection(e))
|
|
{
|
|
m_rotations[e] = Quaterniond::Identity();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline bool igl::opengl2::MouseController::set_rotations(const RotationList & vQ)
|
|
{
|
|
if(vQ.size() != m_rotations.size())
|
|
{
|
|
return false;
|
|
}
|
|
assert(!any_selection());
|
|
m_rotations = vQ;
|
|
return true;
|
|
}
|
|
|
|
inline void igl::opengl2::MouseController::clear_selection()
|
|
{
|
|
m_selection.setConstant(false);
|
|
}
|
|
|
|
inline bool igl::opengl2::MouseController::any_selection() const
|
|
{
|
|
return igl::any_of(m_selection);
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_print_gl_get = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_PRINT_GL_GET_H
|
|
#define IGL_OPENGL2_PRINT_GL_GET_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include "../opengl/OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Prints the value of pname found by issuing glGet*(pname,*)
|
|
// Inputs:
|
|
// pname enum key to gl parameter
|
|
IGL_INLINE void print_gl_get(GLenum pname);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "print_gl_get.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_project = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_PROJECT_H
|
|
#define IGL_OPENGL2_PROJECT_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Wrapper for gluProject that uses the current GL_MODELVIEW_MATRIX,
|
|
// GL_PROJECTION_MATRIX, and GL_VIEWPORT
|
|
// Inputs:
|
|
// obj* 3D objects' x, y, and z coordinates respectively
|
|
// Outputs:
|
|
// win* pointers to screen space x, y, and z coordinates respectively
|
|
// Returns return value of gluProject call
|
|
IGL_INLINE int project(
|
|
const double objX,
|
|
const double objY,
|
|
const double objZ,
|
|
double* winX,
|
|
double* winY,
|
|
double* winZ);
|
|
// Eigen wrapper
|
|
template <typename Derivedobj, typename Derivedwin>
|
|
IGL_INLINE int project(
|
|
const Eigen::PlainObjectBase<Derivedobj> & obj,
|
|
Eigen::PlainObjectBase<Derivedwin> & win);
|
|
// Eigen wrapper with return
|
|
template <typename Derivedobj>
|
|
IGL_INLINE Eigen::PlainObjectBase<Derivedobj> project(
|
|
const Eigen::PlainObjectBase<Derivedobj> & obj);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "project.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_right_axis = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_RIGHT_AXIS_H
|
|
#define IGL_OPENGL2_RIGHT_AXIS_H
|
|
#include "../igl_inline.h"
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Determines the right axis or depth axis of the current gl matrix
|
|
// Outputs:
|
|
// x pointer to x-coordinate in scene coordinates of the un-normalized
|
|
// right axis
|
|
// y pointer to y-coordinate in scene coordinates of the un-normalized
|
|
// right axis
|
|
// z pointer to z-coordinate in scene coordinates of the un-normalized
|
|
// right axis
|
|
// mv pointer to modelview matrix
|
|
//
|
|
// Note: Right axis is returned *UN-normalized*
|
|
IGL_INLINE void right_axis(double * x, double * y, double * z);
|
|
IGL_INLINE void right_axis(const double * mv, double * x, double * y, double * z);
|
|
}
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "right_axis.cpp"
|
|
#endif
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_RotateWidget = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_ROTATE_WIDGET_H
|
|
#define IGL_OPENGL2_ROTATE_WIDGET_H
|
|
#include <Eigen/Geometry>
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
#include "../material_colors.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// 3D Rotate tool widget similar to Maya's. Works best if field of view angle
|
|
// is less than ~25.
|
|
class RotateWidget
|
|
{
|
|
// If a is true then use A else use desaturated A
|
|
static inline void glColor4fv(const bool a, const Eigen::Vector4f & A);
|
|
public:
|
|
inline static Eigen::Quaterniond axis_q(const int a);
|
|
inline static Eigen::Vector3d view_direction(const int x, const int y);
|
|
inline static Eigen::Vector3d view_direction(const Eigen::Vector3d & pos);
|
|
Eigen::Vector3d pos;
|
|
Eigen::Quaterniond rot,down_rot;
|
|
// This line causes trouble if RotateWidget.h is included before bbw.h
|
|
Eigen::Vector2d down_xy,drag_xy,down_dir;
|
|
Eigen::Vector3d udown,udrag;
|
|
double outer_radius_on_screen;
|
|
double outer_over_inner;
|
|
bool m_is_enabled;
|
|
enum DownType
|
|
{
|
|
DOWN_TYPE_X = 0,
|
|
DOWN_TYPE_Y = 1,
|
|
DOWN_TYPE_Z = 2,
|
|
DOWN_TYPE_OUTLINE = 3,
|
|
DOWN_TYPE_TRACKBALL = 4,
|
|
DOWN_TYPE_NONE = 5,
|
|
NUM_DOWN_TYPES = 6
|
|
} down_type, selected_type;
|
|
inline RotateWidget();
|
|
// Vector from origin to mouse click "Unprojected" onto plane with depth of
|
|
// origin and scale to so that outer radius is 1
|
|
//
|
|
// Inputs:
|
|
// x mouse x position
|
|
// y mouse y position
|
|
// Returns vector
|
|
inline Eigen::Vector3d unproject_onto(const int x, const int y) const;
|
|
// Shoot ray from mouse click to sphere
|
|
//
|
|
// Inputs:
|
|
// x mouse x position
|
|
// y mouse y position
|
|
// Outputs:
|
|
// hit position of hit
|
|
// Returns true only if there was a hit
|
|
inline bool intersect(
|
|
const int x,
|
|
const int y,
|
|
Eigen::Vector3d & hit) const;
|
|
inline double unprojected_inner_radius() const;
|
|
inline bool down(const int x, const int y);
|
|
inline bool drag(const int x, const int y);
|
|
inline bool up(const int x, const int y);
|
|
inline bool is_down() const;
|
|
inline void draw() const;
|
|
inline void draw_guide() const;
|
|
public:
|
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
|
};
|
|
}
|
|
}
|
|
|
|
// Implementation
|
|
#include "../opengl/OpenGL_convenience.h"
|
|
#include "../PI.h"
|
|
#include "../EPS.h"
|
|
#include "../ray_sphere_intersect.h"
|
|
#include "../mat_to_quat.h"
|
|
#include "../trackball.h"
|
|
#include "project.h"
|
|
#include "unproject.h"
|
|
#include <iostream>
|
|
#include <cassert>
|
|
|
|
inline void igl::opengl2::RotateWidget::glColor4fv(
|
|
const bool a,
|
|
const Eigen::Vector4f & A)
|
|
{
|
|
if(a)
|
|
{
|
|
::glColor4fv(A.data());
|
|
}else
|
|
{
|
|
Eigen::Vector4f B;
|
|
const double f = 0.95; // desaturate by 95%
|
|
const double L = 0.3*A(0) + 0.6*A(1) + 0.1*A(2);
|
|
B.head(3) = A.head(3).array() + f*(L-A.head(3).array());
|
|
B(3) = A(3);
|
|
::glColor4fv(B.data());
|
|
}
|
|
}
|
|
|
|
inline Eigen::Quaterniond igl::opengl2::RotateWidget::axis_q(const int a)
|
|
{
|
|
assert(a<3 && a>=0);
|
|
const Eigen::Quaterniond axes[3] = {
|
|
Eigen::Quaterniond(Eigen::AngleAxisd(igl::PI*0.5,Eigen::Vector3d(0,1,0))),
|
|
Eigen::Quaterniond(Eigen::AngleAxisd(igl::PI*0.5,Eigen::Vector3d(1,0,0))),
|
|
Eigen::Quaterniond::Identity()};
|
|
return axes[a];
|
|
}
|
|
|
|
inline Eigen::Vector3d igl::opengl2::RotateWidget::view_direction(const int x, const int y)
|
|
{
|
|
using namespace Eigen;
|
|
const Vector3d win_s(x,y,0), win_d(x,y,1);
|
|
const Vector3d s = unproject(win_s);
|
|
const Vector3d d = unproject(win_d);
|
|
return d-s;
|
|
}
|
|
|
|
inline Eigen::Vector3d igl::opengl2::RotateWidget::view_direction(const Eigen::Vector3d & pos)
|
|
{
|
|
using namespace Eigen;
|
|
const Vector3d ppos = project(pos);
|
|
return view_direction(ppos(0),ppos(1));
|
|
}
|
|
|
|
inline igl::opengl2::RotateWidget::RotateWidget():
|
|
pos(0,0,0),
|
|
rot(Eigen::Quaterniond::Identity()),
|
|
down_rot(rot),
|
|
down_xy(-1,-1),drag_xy(-1,-1),
|
|
outer_radius_on_screen(91.),
|
|
outer_over_inner(1.13684210526),
|
|
m_is_enabled(true),
|
|
down_type(DOWN_TYPE_NONE),
|
|
selected_type(DOWN_TYPE_NONE)
|
|
{
|
|
}
|
|
|
|
inline Eigen::Vector3d igl::opengl2::RotateWidget::unproject_onto(
|
|
const int x,
|
|
const int y) const
|
|
{
|
|
using namespace Eigen;
|
|
// KNOWN BUG: This projects to same depths as pos. I think what we actually
|
|
// want is The intersection with the plane perpendicular to the view
|
|
// direction at pos. If the field of view angle is small then this difference
|
|
// is negligible.
|
|
//const Vector3d ppos = project(pos);
|
|
//const Vector3d uxy = unproject( Vector3d(x,y,ppos(2)));
|
|
// http://en.wikipedia.org/wiki/Line-plane_intersection
|
|
//
|
|
// Hrrmmm. There's still something wrong here if the ball's in the corner of
|
|
// the screen. Am I somehow not accounting for perspective correctly?
|
|
//
|
|
// Q: What about just projecting the circle's equation and solving for the
|
|
// distance?
|
|
const Vector3d l0 = unproject(Vector3d(x,y,0));
|
|
const Vector3d l = unproject(Vector3d(x,y,1))-l0;
|
|
const Vector3d n = view_direction(pos);
|
|
const double t = (pos-l0).dot(n)/l.dot(n);
|
|
const Vector3d uxy = l0+t*l;
|
|
return (uxy-pos)/unprojected_inner_radius()*outer_over_inner*outer_over_inner;
|
|
}
|
|
|
|
inline bool igl::opengl2::RotateWidget::intersect(
|
|
const int x,
|
|
const int y,
|
|
Eigen::Vector3d & hit) const
|
|
{
|
|
using namespace Eigen;
|
|
Vector3d view = view_direction(x,y);
|
|
const Vector3d ppos = project(pos);
|
|
Vector3d uxy = unproject(Vector3d(x,y,ppos(2)));
|
|
double t0,t1;
|
|
if(!ray_sphere_intersect(uxy,view,pos,unprojected_inner_radius(),t0,t1))
|
|
{
|
|
return false;
|
|
}
|
|
hit = uxy+t0*view;
|
|
return true;
|
|
}
|
|
|
|
|
|
inline double igl::opengl2::RotateWidget::unprojected_inner_radius() const
|
|
{
|
|
using namespace Eigen;
|
|
Vector3d off,ppos,ppos_off,pos_off;
|
|
project(pos,ppos);
|
|
ppos_off = ppos;
|
|
ppos_off(0) += outer_radius_on_screen/outer_over_inner;
|
|
unproject(ppos_off,pos_off);
|
|
return (pos-pos_off).norm();
|
|
}
|
|
inline bool igl::opengl2::RotateWidget::down(const int x, const int y)
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
if(!m_is_enabled)
|
|
{
|
|
return false;
|
|
}
|
|
down_type = DOWN_TYPE_NONE;
|
|
selected_type = DOWN_TYPE_NONE;
|
|
down_xy = Vector2d(x,y);
|
|
drag_xy = down_xy;
|
|
down_rot = rot;
|
|
Vector3d ppos = project(pos);
|
|
const double r = (ppos.head(2) - down_xy).norm();
|
|
const double thresh = 3;
|
|
if(fabs(r - outer_radius_on_screen)<thresh)
|
|
{
|
|
udown = unproject_onto(x,y);
|
|
udrag = udown;
|
|
down_type = DOWN_TYPE_OUTLINE;
|
|
selected_type = DOWN_TYPE_OUTLINE;
|
|
// project mouse to same depth as pos
|
|
return true;
|
|
}else if(r < outer_radius_on_screen/outer_over_inner+thresh*0.5)
|
|
{
|
|
Vector3d hit;
|
|
const bool is_hit = intersect(down_xy(0),down_xy(1),hit);
|
|
if(!is_hit)
|
|
{
|
|
//cout<<"~~~!is_hit"<<endl;
|
|
}
|
|
auto on_meridian = [&](
|
|
const Vector3d & hit,
|
|
const Quaterniond & rot,
|
|
const Quaterniond & m,
|
|
Vector3d & pl_hit) -> bool
|
|
{
|
|
// project onto rotate plane
|
|
pl_hit = hit-pos;
|
|
pl_hit = (m.conjugate()*rot.conjugate()*pl_hit).eval();
|
|
pl_hit(2) = 0;
|
|
pl_hit = (rot*m*pl_hit).eval();
|
|
pl_hit.normalize();
|
|
pl_hit *= unprojected_inner_radius();
|
|
pl_hit += pos;
|
|
return (project(pl_hit).head(2)-project(hit).head(2)).norm()<2*thresh;
|
|
};
|
|
udown = (hit-pos).normalized()/outer_radius_on_screen;
|
|
udrag = udown;
|
|
for(int a = 0;a<3;a++)
|
|
{
|
|
Vector3d pl_hit;
|
|
if(on_meridian(hit,rot,Quaterniond(axis_q(a)),pl_hit))
|
|
{
|
|
udown = (pl_hit-pos).normalized()/outer_radius_on_screen;
|
|
udrag = udown;
|
|
down_type = DownType(DOWN_TYPE_X+a);
|
|
selected_type = down_type;
|
|
{
|
|
Vector3d dir3 = axis_q(a).conjugate()*down_rot.conjugate()*(hit-pos);
|
|
dir3 = AngleAxisd(-PI*0.5,Vector3d(0,0,1))*dir3;
|
|
dir3 = (rot*axis_q(a)*dir3).eval();
|
|
down_dir = (project((hit+dir3).eval())-project(hit)).head(2);
|
|
down_dir.normalize();
|
|
//// flip y because y coordinate is going to be given backwards in
|
|
//// drag()
|
|
//down_dir(1) *= -1;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
//assert(is_hit);
|
|
down_type = DOWN_TYPE_TRACKBALL;
|
|
selected_type = DOWN_TYPE_TRACKBALL;
|
|
return true;
|
|
}else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
inline bool igl::opengl2::RotateWidget::drag(const int x, const int y)
|
|
{
|
|
using namespace std;
|
|
using namespace Eigen;
|
|
if(!m_is_enabled)
|
|
{
|
|
return false;
|
|
}
|
|
drag_xy = Vector2d(x,y);
|
|
switch(down_type)
|
|
{
|
|
case DOWN_TYPE_NONE:
|
|
return false;
|
|
default:
|
|
{
|
|
const Quaterniond & q = axis_q(down_type-DOWN_TYPE_X);
|
|
const double dtheta = -(drag_xy - down_xy).dot(down_dir)/
|
|
outer_radius_on_screen/outer_over_inner*PI/2.;
|
|
Quaterniond dq(AngleAxisd(dtheta,down_rot*q*Vector3d(0,0,1)));
|
|
rot = dq * down_rot;
|
|
udrag = dq * udown;
|
|
return true;
|
|
}
|
|
case DOWN_TYPE_OUTLINE:
|
|
{
|
|
Vector3d ppos = project(pos);
|
|
// project mouse to same depth as pos
|
|
udrag = unproject_onto(x,y);
|
|
const Vector2d A = down_xy - ppos.head(2);
|
|
const Vector2d B = drag_xy - ppos.head(2);
|
|
const double dtheta = atan2(A(0)*B(1)-A(1)*B(0),A(0)*B(0)+A(1)*B(1));
|
|
Vector3d n = view_direction(pos).normalized();
|
|
Quaterniond dq(AngleAxisd(dtheta,-n));
|
|
//Vector3d n = udrag.cross(udown).normalized();
|
|
//Quaterniond dq(AngleAxisd(fabs(dtheta),-n));
|
|
rot = dq * down_rot;
|
|
}
|
|
return true;
|
|
case DOWN_TYPE_TRACKBALL:
|
|
{
|
|
Vector3d ppos = project(pos);
|
|
const double r = (double)outer_radius_on_screen/outer_over_inner*2.0;
|
|
//const int h = w;
|
|
Vector4i vp;
|
|
glGetIntegerv(GL_VIEWPORT,vp.data());
|
|
const int h = vp(3);
|
|
Quaterniond dq;
|
|
trackball(
|
|
r,r,
|
|
1,
|
|
Quaterniond::Identity(),
|
|
double( down_xy(0)-ppos(0) )+r/2.,
|
|
double((h-down_xy(1))-(h-ppos(1)))+r/2.,
|
|
double( x-ppos(0) )+r/2.,
|
|
double( (h-y)-(h-ppos(1)))+r/2.,
|
|
dq);
|
|
// We've computed change in rotation according to this view:
|
|
// R = mv * r, R' = rot * (mv * r)
|
|
// But we only want new value for r:
|
|
// R' = mv * r'
|
|
// mv * r' = rot * (mv * r)
|
|
// r' = mv* * rot * mv * r
|
|
Matrix4d mv;
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,mv.data());
|
|
Quaterniond scene_rot;
|
|
// Convert modelview matrix to quaternion
|
|
mat4_to_quat(mv.data(),scene_rot.coeffs().data());
|
|
scene_rot.normalize();
|
|
rot = scene_rot.conjugate() * dq * scene_rot * down_rot;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
inline bool igl::opengl2::RotateWidget::up(const int /*x*/, const int /*y*/)
|
|
{
|
|
// even if disabled process up
|
|
down_type = DOWN_TYPE_NONE;
|
|
return false;
|
|
}
|
|
|
|
inline bool igl::opengl2::RotateWidget::is_down() const
|
|
{
|
|
return down_type != DOWN_TYPE_NONE;
|
|
}
|
|
|
|
inline void igl::opengl2::RotateWidget::draw() const
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT | GL_LINE_BIT);
|
|
glDisable(GL_CLIP_PLANE0);
|
|
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glLineWidth(2.0);
|
|
|
|
double r = unprojected_inner_radius();
|
|
Vector3d view = view_direction(pos).normalized();
|
|
|
|
auto draw_circle = [&](const bool cull)
|
|
{
|
|
Vector3d view = view_direction(pos).normalized();
|
|
glBegin(GL_LINES);
|
|
const double th_step = (2.0*igl::PI/100.0);
|
|
for(double th = 0;th<2.0*igl::PI+th_step;th+=th_step)
|
|
{
|
|
Vector3d a(cos(th),sin(th),0.0);
|
|
Vector3d b(cos(th+th_step),sin(th+th_step),0.0);
|
|
if(!cull || (0.5*(a+b)).dot(view)<FLOAT_EPS)
|
|
{
|
|
glVertex3dv(a.data());
|
|
glVertex3dv(b.data());
|
|
}
|
|
}
|
|
glEnd();
|
|
};
|
|
|
|
|
|
glPushMatrix();
|
|
glTranslated(pos(0),pos(1),pos(2));
|
|
|
|
glScaled(r,r,r);
|
|
// Draw outlines
|
|
{
|
|
glPushMatrix();
|
|
glColor4fv(m_is_enabled,MAYA_GREY);
|
|
Quaterniond q;
|
|
q.setFromTwoVectors(Vector3d(0,0,1),view);
|
|
glMultMatrixd(Affine3d(q).matrix().data());
|
|
draw_circle(false);
|
|
glScaled(outer_over_inner,outer_over_inner,outer_over_inner);
|
|
if(selected_type == DOWN_TYPE_OUTLINE)
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_YELLOW);
|
|
}else
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_CYAN);
|
|
}
|
|
draw_circle(false);
|
|
glPopMatrix();
|
|
}
|
|
// Draw quartiles
|
|
{
|
|
glPushMatrix();
|
|
glMultMatrixd(Affine3d(rot).matrix().data());
|
|
if(selected_type == DOWN_TYPE_Z)
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_YELLOW);
|
|
}else
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_BLUE);
|
|
}
|
|
draw_circle(true);
|
|
if(selected_type == DOWN_TYPE_Y)
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_YELLOW);
|
|
}else
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_GREEN);
|
|
}
|
|
glRotated(90.0,1.0,0.0,0.0);
|
|
draw_circle(true);
|
|
if(selected_type == DOWN_TYPE_X)
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_YELLOW);
|
|
}else
|
|
{
|
|
glColor4fv(m_is_enabled,MAYA_RED);
|
|
}
|
|
glRotated(90.0,0.0,1.0,0.0);
|
|
draw_circle(true);
|
|
glPopMatrix();
|
|
}
|
|
glColor4fv(m_is_enabled,MAYA_GREY);
|
|
draw_guide();
|
|
glPopMatrix();
|
|
|
|
glPopAttrib();
|
|
};
|
|
|
|
inline void igl::opengl2::RotateWidget::draw_guide() const
|
|
{
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
glPushAttrib(
|
|
GL_DEPTH_BUFFER_BIT |
|
|
GL_ENABLE_BIT |
|
|
GL_POLYGON_BIT |
|
|
GL_POINT_BIT |
|
|
GL_TRANSFORM_BIT |
|
|
GL_STENCIL_BUFFER_BIT |
|
|
GL_LIGHTING_BIT);
|
|
|
|
// http://www.codeproject.com/Articles/23444/A-Simple-OpenGL-Stipple-Polygon-Example-EP_OpenGL_
|
|
const GLubyte halftone[] = {
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
|
|
|
|
|
|
switch(down_type)
|
|
{
|
|
case DOWN_TYPE_NONE:
|
|
case DOWN_TYPE_TRACKBALL:
|
|
goto finish;
|
|
case DOWN_TYPE_OUTLINE:
|
|
glScaled(outer_over_inner,outer_over_inner,outer_over_inner);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
{
|
|
const Vector3d nudown(udown.normalized()),
|
|
nudrag(udrag.normalized());
|
|
glPushMatrix();
|
|
glDisable(GL_CULL_FACE);
|
|
glDisable(GL_POINT_SMOOTH);
|
|
glPointSize(5.);
|
|
glBegin(GL_POINTS);
|
|
glVertex3dv(nudown.data());
|
|
glVertex3d(0,0,0);
|
|
glVertex3dv(nudrag.data());
|
|
glEnd();
|
|
glBegin(GL_LINE_STRIP);
|
|
glVertex3dv(nudown.data());
|
|
glVertex3d(0,0,0);
|
|
glVertex3dv(nudrag.data());
|
|
glEnd();
|
|
glEnable(GL_POLYGON_STIPPLE);
|
|
glPolygonStipple(halftone);
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glVertex3d(0,0,0);
|
|
Quaterniond dq = rot * down_rot.conjugate();
|
|
//dq.setFromTwoVectors(nudown,nudrag);
|
|
for(double t = 0;t<1;t+=0.1)
|
|
{
|
|
const Vector3d p = Quaterniond::Identity().slerp(t,dq) * nudown;
|
|
glVertex3dv(p.data());
|
|
}
|
|
glVertex3dv(nudrag.data());
|
|
glEnd();
|
|
glPopMatrix();
|
|
}
|
|
finish:
|
|
glPopAttrib();
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_shine_textures = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_SHINE_TEXTURES_H
|
|
#define IGL_OPENGL2_SHINE_TEXTURES_H
|
|
|
|
#include <stdint.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
|
|
const uint8_t SHINE_TEXTURE_0[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,7,20,15,7,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,36,36,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,12,20,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,28,36,36,0,0,0,0,0,0,0,0,0,0,0,12,28,20,12,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,39,28,31,28,0,0,0,0,0,0,0,0,0,0,0,28,28,20,15,28,28,12,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,44,31,36,28,0,0,0,0,0,0,0,0,0,0,15,31,28,20,36,36,20,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,0,0,0,0,0,0,0,0,12,12,7,12,12,47,47,44,44,36,0,0,0,0,0,0,0,0,0,0,31,36,28,28,44,28,12,0,0,0,12,23,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,15,15,15,20,20,47,47,44,44,23,0,0,0,0,0,0,7,12,7,20,36,36,28,44,39,20,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,39,23,0,0,0,0,0,0,0,12,15,12,12,12,47,47,44,44,15,0,0,0,0,0,0,12,12,12,36,36,36,44,52,28,7,0,0,7,20,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,39,7,0,0,0,0,0,0,12,20,20,0,0,47,47,47,47,7,0,0,0,0,0,12,15,15,23,36,44,44,60,44,20,0,0,0,28,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,0,0,0,0,0,12,23,23,12,12,52,52,52,52,0,0,0,0,0,0,20,23,23,39,47,47,60,60,28,0,0,0,28,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,44,12,0,0,0,0,0,0,28,31,31,23,52,60,52,52,0,0,0,0,0,0,28,28,36,44,60,55,68,44,12,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,52,36,0,0,0,0,0,0,31,39,52,36,60,68,52,52,0,0,0,0,0,20,28,36,44,60,63,76,60,23,0,0,23,47,36,12,0,0,0,0,0,0,0,0,0,0,0,12,23,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,52,20,0,0,15,15,0,36,44,60,36,71,76,55,52,0,0,0,0,0,31,36,44,52,71,76,76,36,0,0,23,47,39,12,0,7,12,0,0,0,0,0,0,0,7,20,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,52,39,0,0,20,20,12,36,55,92,39,79,100,68,60,0,0,0,0,20,36,47,52,76,84,92,60,20,0,20,47,44,20,0,12,20,15,0,0,0,0,0,0,20,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,55,20,0,20,23,20,31,79,111,44,84,127,84,55,0,0,0,0,36,39,60,68,92,92,79,28,0,20,47,52,23,0,0,12,20,7,0,0,0,0,20,36,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,7,0,0,0,0,0,0,0,31,60,47,0,7,28,28,20,84,116,52,100,164,100,52,0,0,0,12,44,60,63,92,103,100,52,7,20,47,60,28,0,12,15,7,7,0,0,0,15,36,47,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,12,12,7,0,0,0,0,0,7,52,60,28,0,28,28,20,84,119,79,119,188,116,44,0,0,0,36,44,76,76,111,108,76,20,12,44,60,31,12,20,28,12,0,0,0,12,36,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,7,0,0,0,0,20,20,12,0,0,0,12,20,7,0,0,0,0,0,28,63,52,0,28,36,28,76,116,100,124,188,116,36,0,0,7,47,68,79,108,119,100,36,12,44,68,36,20,28,39,23,0,0,7,31,60,68,52,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,20,20,12,0,0,12,15,23,20,12,0,0,20,23,12,0,0,0,0,0,55,68,31,12,39,39,76,119,132,127,180,100,28,0,0,28,55,92,95,140,124,68,20,44,68,44,28,31,44,28,7,0,20,52,76,71,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,28,20,12,0,0,20,36,31,15,0,7,23,28,12,0,0,0,0,28,68,60,12,44,44,71,116,151,140,175,100,20,0,7,55,84,108,140,148,100,36,44,71,52,36,36,47,28,0,12,39,76,87,71,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,31,23,12,0,20,36,39,28,7,12,28,36,20,0,0,0,0,55,71,39,36,44,76,116,167,156,180,100,15,12,39,76,111,127,167,132,60,44,76,60,44,44,52,28,7,28,68,92,92,63,28,0,0,7,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,20,7,12,31,44,36,15,12,28,36,20,0,0,0,28,71,68,36,52,76,119,172,180,188,108,20,28,76,108,140,172,164,103,60,76,68,52,52,52,28,20,52,95,108,84,47,12,0,12,20,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,39,39,23,15,28,47,44,28,20,36,44,23,12,12,12,55,76,52,60,76,124,164,188,180,100,20,60,103,143,164,183,132,92,87,84,68,60,52,31,36,84,116,108,76,28,7,15,28,23,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,44,39,28,28,44,52,36,28,36,52,36,28,20,36,76,76,84,84,148,175,207,172,100,36,108,140,175,191,164,124,108,100,76,68,52,44,60,100,124,100,52,20,20,31,28,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,52,52,44,39,44,60,52,44,44,60,47,39,28,68,84,108,100,172,196,228,167,108,76,156,188,204,196,156,132,124,92,76,60,60,84,116,116,84,52,31,36,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,55,55,52,55,60,60,55,60,71,68,52,52,84,108,127,188,220,239,164,116,119,188,228,212,188,156,140,111,84,71,79,100,124,111,84,63,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,52,60,68,68,76,71,76,84,87,79,63,84,100,148,188,236,252,172,140,164,220,236,212,180,164,132,100,87,100,116,132,124,100,84,68,52,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,0,0,0,0,0,12,39,60,68,84,92,87,92,100,108,95,87,108,148,191,244,252,183,172,212,244,236,212,188,148,124,108,116,135,151,140,111,87,68,44,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,20,28,28,20,0,0,0,20,52,68,84,108,111,116,116,132,116,124,148,204,239,252,204,199,244,252,236,215,172,148,135,143,156,164,140,108,87,68,44,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,36,36,39,31,12,0,28,63,95,127,140,143,143,164,156,164,212,244,252,228,228,252,252,244,212,188,167,180,180,156,124,108,92,60,36,28,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,39,44,47,52,44,44,63,100,140,167,191,204,204,212,223,252,252,244,244,252,252,244,228,212,204,183,156,132,108,68,44,36,36,31,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,52,55,60,76,100,132,156,188,228,244,239,244,252,252,252,252,252,252,252,244,228,204,164,116,79,68,79,76,60,44,31,20,20,12,7,0,0,0,0,7,15,15,7,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,55,60,68,87,132,180,228,244,252,252,252,252,252,252,252,252,252,244,212,172,143,135,127,108,87,76,68,68,68,68,68,60,55,52,68,68,60,55,52,47,39,28,36,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,15,28,28,28,28,28,28,28,23,20,15,15,15,15,15,15,15,15,12,20,44,68,79,103,164,220,244,252,252,252,252,252,252,252,252,244,223,204,191,180,172,180,180,172,151,135,132,132,127,124,116,108,124,119,108,95,92,76,60,44,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,31,68,84,84,84,84,84,84,92,92,92,84,84,84,84,84,92,95,100,92,87,84,87,103,140,188,228,244,252,252,252,252,252,252,252,252,239,212,191,191,180,159,140,124,124,124,124,132,132,124,111,100,84,87,76,60,52,52,47,47,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,52,52,52,52,52,52,60,63,68,68,68,71,84,95,116,132,148,159,172,188,207,223,231,244,247,252,252,252,252,252,252,252,252,252,244,220,172,132,108,92,84,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,63,71,76,76,76,84,103,132,156,164,172,167,172,196,228,244,252,252,252,252,252,252,252,252,252,252,244,220,188,159,132,100,76,55,47,44,39,36,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,28,44,44,52,52,71,84,103,127,140,148,143,140,132,119,132,148,172,196,228,244,252,252,244,244,252,252,252,239,220,223,244,244,223,204,183,164,140,127,108,84,60,39,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,28,47,55,84,100,111,100,92,79,71,68,68,71,84,87,100,140,196,228,236,236,252,228,220,228,247,247,252,239,212,183,188,212,228,228,228,223,196,159,124,92,68,63,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,52,52,52,52,60,60,60,60,55,39,28,36,52,71,108,164,204,215,207,212,236,244,188,180,212,239,236,236,247,212,167,132,140,164,188,191,188,188,180,167,164,148,116,84,63,60,52,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,44,47,52,52,52,52,44,28,7,0,12,28,44,60,92,124,151,188,188,172,175,204,228,215,148,156,220,236,212,212,236,220,180,127,92,92,103,132,151,148,140,151,148,132,132,148,140,111,76,60,52,52,47,39,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,36,36,39,44,44,44,44,36,15,0,0,0,0,12,28,36,44,71,92,108,140,172,164,140,148,180,204,215,164,108,148,239,244,188,188,204,204,188,156,108,68,63,68,87,111,119,108,100,124,140,132,108,111,124,124,103,71,52,44,44,44,39,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,28,31,36,36,36,36,20,0,0,0,0,0,0,0,12,23,28,36,60,71,76,100,148,164,135,108,111,156,180,196,183,108,84,164,252,252,183,164,175,196,180,172,140,92,60,39,44,68,79,95,100,84,68,87,116,124,116,103,103,103,100,84,63,44,39,36,36,36,31,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,20,23,28,23,12,0,0,0,0,0,0,0,0,0,0,0,15,23,44,52,52,71,108,135,140,116,84,84,132,156,164,188,148,52,84,180,252,252,196,140,148,188,164,172,164,108,76,60,31,20,44,68,76,79,76,68,52,60,79,100,108,103,108,103,95,84,63,52,39,36,31,31,23,20,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,39,52,76,100,116,116,87,55,68,116,127,127,172,175,95,20,100,204,252,252,220,132,116,172,156,140,156,140,84,63,55,31,12,12,44,68,68,68,60,52,44,44,52,68,87,95,100,100,92,84,68,47,31,28,23,20,12,20,12,15,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,60,71,92,100,92,52,39,52,100,116,108,143,188,140,44,20,119,220,252,252,236,140,92,132,167,124,116,143,119,68,52,52,31,12,0,20,44,63,63,55,44,36,36,36,36,44,55,76,84,87,84,76,71,63,44,20,7,12,12,15,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,36,52,71,84,84,63,28,28,44,84,103,87,108,167,167,84,7,36,140,236,252,244,228,148,76,87,156,132,100,111,135,103,52,39,44,31,12,0,0,20,47,60,60,47,31,23,31,28,28,28,28,36,52,68,71,68,68,60,52,36,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,52,60,71,60,36,12,20,36,76,92,79,76,127,172,116,28,0,60,151,236,231,220,204,143,68,52,116,156,100,79,116,124,84,39,28,39,28,12,0,0,0,28,52,60,55,39,20,12,20,28,20,20,12,0,12,36,55,60,55,52,44,36,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,36,52,63,55,39,12,0,12,36,60,84,76,60,87,151,132,60,0,0,68,148,220,212,204,188,148,68,31,79,140,119,79,68,116,108,68,28,20,28,23,12,0,0,0,0,28,52,52,52,36,12,0,12,20,12,0,0,0,0,7,28,44,44,39,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,52,39,20,0,0,12,28,52,71,76,44,55,116,143,87,20,0,0,76,143,196,196,183,183,143,76,28,52,100,132,87,52,68,116,95,52,20,12,20,12,0,0,0,0,0,7,28,47,47,44,28,7,0,0,0,0,0,0,0,0,0,0,20,28,28,20,15,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,52,39,20,0,0,0,7,23,39,60,71,44,28,76,132,103,44,0,0,12,71,132,183,188,156,167,140,84,44,23,76,116,95,60,44,79,108,84,44,15,0,0,12,12,0,0,0,0,0,12,28,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,23,0,0,0,0,7,20,28,52,68,44,12,44,100,116,68,12,0,0,20,71,132,167,172,132,140,116,100,52,0,55,79,100,71,36,39,84,100,68,36,12,0,12,12,0,0,0,0,0,0,0,12,31,44,39,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,31,12,0,0,0,0,0,12,20,44,63,44,12,20,63,108,84,36,0,0,0,12,60,124,148,164,124,119,100,108,52,0,28,68,92,76,60,20,52,92,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,36,20,0,0,0,0,0,0,0,12,36,60,47,15,0,44,87,92,52,7,0,0,0,20,60,124,140,156,116,100,92,108,47,15,0,55,68,76,60,36,15,60,92,68,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,31,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,23,12,0,0,0,0,0,0,0,0,23,52,47,20,0,28,63,95,68,28,0,0,0,0,20,52,135,135,148,111,84,100,108,47,36,0,36,60,68,52,47,20,20,68,84,52,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,28,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,12,0,0,0,0,0,0,0,0,0,20,47,52,20,0,12,44,84,76,44,0,0,0,0,0,23,44,124,116,108,108,71,108,92,52,44,0,7,55,60,47,44,36,0,28,76,79,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,15,44,52,23,0,0,36,60,84,55,20,0,0,0,0,0,28,44,108,87,76,103,68,108,71,60,44,0,0,36,55,52,36,44,20,0,39,79,68,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,0,0,0,0,0,0,0,12,36,52,28,0,0,20,44,76,63,36,0,0,0,0,0,0,28,52,76,68,55,100,68,108,60,71,44,7,0,12,52,52,31,36,36,0,0,52,84,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,7,28,47,28,0,0,12,36,60,68,52,12,0,0,0,0,0,0,15,52,63,55,44,92,63,100,52,84,36,23,0,0,36,52,36,28,36,20,0,12,60,79,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,28,0,0,0,28,44,63,52,28,0,0,0,0,0,0,0,12,60,52,47,39,79,60,84,52,76,36,36,0,0,12,52,47,20,28,28,7,0,23,68,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,28,7,0,0,12,36,52,55,44,7,0,0,0,0,0,0,7,20,68,47,44,36,68,60,68,47,60,31,31,0,0,0,36,47,28,15,28,20,0,0,31,68,63,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,7,0,0,0,28,36,52,44,20,0,0,0,0,0,0,0,0,12,60,47,36,28,52,52,44,47,52,28,28,0,0,0,15,44,44,12,20,20,0,0,0,36,76,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,15,28,44,44,36,0,0,0,0,0,0,0,0,0,0,52,47,23,28,52,47,31,47,44,28,20,7,0,0,0,36,44,20,7,20,12,0,0,7,47,76,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,0,0,0,0,20,28,44,39,15,0,0,0,0,0,0,0,0,0,0,44,44,12,28,47,44,28,47,44,36,20,15,0,0,0,20,39,36,0,12,12,12,0,0,15,52,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,12,20,31,36,28,0,0,0,0,0,0,0,0,0,0,0,44,39,0,28,47,52,36,52,44,36,12,12,0,0,0,0,36,36,15,0,12,12,0,0,0,20,60,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,12,15,20,36,36,12,0,0,0,0,0,0,0,0,0,0,0,39,39,0,23,44,47,28,52,39,39,12,12,0,0,0,0,20,36,28,0,0,0,0,0,0,0,28,55,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,15,20,28,31,20,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,20,36,44,20,44,36,36,7,7,0,0,0,0,0,31,36,12,0,0,0,0,0,0,0,31,52,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,12,20,28,28,0,0,0,0,0,0,0,0,0,0,0,0,23,36,36,0,15,36,28,12,20,28,28,0,7,0,0,0,0,0,20,31,23,0,0,0,0,0,0,0,7,31,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,7,7,23,28,15,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,15,36,15,0,0,28,28,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,12,31,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,15,0,15,36,23,0,0,23,23,7,0,0,0,0,0,0,0,20,28,20,0,0,0,0,0,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,15,0,12,28,28,12,12,31,31,20,0,0,0,0,0,0,0,7,28,23,0,0,0,0,0,0,0,0,0,7,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,28,28,20,20,23,23,20,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,20,20,7,7,15,20,20,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,23,20,0,0,12,28,28,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,28,20,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,31,28,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,20,12,0,0,0,15,15,7,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_1[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,20,20,7,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,12,0,0,0,0,12,12,12,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,20,20,15,0,0,0,0,12,12,0,0,0,0,12,12,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,12,20,20,0,0,0,0,12,15,15,0,0,12,20,20,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,20,20,0,0,0,0,28,31,28,0,0,0,12,12,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,20,20,0,0,0,12,36,44,28,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,28,28,20,0,0,20,47,60,28,0,0,7,7,0,20,20,20,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,28,31,28,0,0,15,44,68,36,0,0,20,20,12,20,20,12,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,15,36,36,0,0,12,44,68,36,0,0,28,28,12,23,23,12,0,0,0,12,12,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,36,36,0,0,0,44,68,36,0,0,23,23,0,28,28,0,0,0,0,12,7,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,28,31,15,36,36,12,0,0,28,60,36,0,0,20,20,12,28,28,0,0,0,12,12,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,28,7,0,0,0,0,0,12,12,0,0,0,0,0,0,0,23,36,28,36,36,28,0,0,28,60,36,0,0,20,20,28,36,36,0,0,0,20,20,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,36,23,12,0,0,0,0,0,15,12,0,0,0,0,0,0,12,36,36,36,44,39,0,0,44,52,20,0,12,36,36,36,36,36,0,0,15,20,20,0,0,0,15,28,23,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,28,12,0,0,0,0,15,15,0,0,0,0,0,0,0,36,36,31,44,44,0,12,52,60,28,0,28,36,36,39,39,20,0,0,28,28,12,0,0,0,28,31,12,0,0,0,0,0,0,0,12,20,15,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,44,44,28,7,0,0,0,7,20,12,0,0,0,0,0,0,36,39,36,44,44,0,0,52,84,55,12,44,39,39,44,44,7,0,0,28,28,0,0,0,20,36,28,0,0,0,0,0,0,0,12,31,28,12,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,44,39,31,20,0,0,0,12,20,12,0,0,0,0,0,20,44,44,47,44,20,0,52,92,71,15,47,31,39,44,44,0,0,20,31,28,0,0,7,36,36,12,0,0,0,0,0,0,12,36,44,20,7,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,28,52,52,36,20,7,0,12,28,28,0,0,0,0,0,0,44,44,55,52,36,12,60,100,84,12,52,36,55,44,44,0,0,31,36,12,0,0,28,39,28,0,0,0,0,0,0,7,28,52,28,12,20,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,63,52,44,28,0,0,20,36,23,0,0,0,0,0,44,44,63,52,52,23,76,108,87,0,52,44,76,47,44,0,12,36,36,0,0,12,44,44,12,0,0,0,0,0,7,36,52,36,20,20,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,76,68,52,28,7,0,36,36,12,0,0,0,0,31,47,63,52,52,20,68,124,108,0,44,44,76,52,36,0,28,44,36,0,0,28,44,28,0,0,0,0,0,0,36,60,44,20,20,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,79,71,52,28,7,20,44,36,0,0,0,0,12,52,55,60,52,28,63,140,116,0,47,47,68,52,20,0,44,44,20,0,12,44,44,12,0,0,0,0,0,36,68,52,28,23,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,76,87,84,60,28,12,44,52,28,0,0,0,0,52,52,79,55,44,60,143,124,0,52,55,60,52,0,12,44,44,0,0,36,52,28,0,0,0,0,0,36,76,71,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,68,92,95,92,60,20,28,60,52,12,0,0,0,44,52,92,55,71,71,159,124,0,52,71,60,52,0,36,47,39,0,20,52,47,12,0,0,0,0,31,76,84,55,36,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,79,103,108,100,60,20,52,68,39,0,0,0,20,55,92,60,71,68,164,119,20,60,92,60,55,0,47,52,20,0,44,55,28,0,0,0,0,28,79,92,68,44,47,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,84,116,116,108,60,36,68,68,20,0,0,0,60,76,76,68,68,164,124,47,76,108,60,47,15,52,52,0,23,60,52,7,0,0,0,23,76,100,76,52,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,52,100,132,140,108,52,55,76,52,0,0,0,52,63,103,63,92,172,140,76,92,119,60,36,39,52,44,0,52,60,28,0,0,0,20,71,103,87,63,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,156,108,60,71,76,28,0,0,36,60,119,63,116,180,159,92,92,124,60,23,55,60,20,28,63,52,0,0,0,20,68,108,92,68,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,76,124,172,167,103,68,76,60,12,0,12,63,116,76,127,172,172,111,108,116,63,28,60,60,12,55,68,28,0,0,15,63,108,103,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,84,148,196,167,100,84,79,44,0,0,60,100,103,124,156,180,127,127,116,68,47,60,44,36,68,52,0,0,12,60,108,111,84,55,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,100,180,212,164,100,92,76,20,0,44,84,132,124,156,188,140,148,108,68,60,63,36,60,68,28,0,20,68,108,119,95,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,132,212,220,151,108,92,55,0,20,76,140,124,172,196,148,159,100,76,68,63,47,71,52,0,20,76,119,132,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,148,220,212,156,124,87,31,0,68,148,148,183,199,175,180,100,87,68,68,68,71,28,20,76,124,143,119,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,68,159,223,212,167,124,68,12,60,135,164,191,199,204,196,108,87,76,76,76,52,20,71,132,159,132,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,71,167,228,212,172,111,44,36,124,183,207,212,228,191,127,79,92,79,76,44,71,140,167,140,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,15,84,180,223,212,164,92,36,100,180,220,220,231,183,148,84,116,92,84,79,156,196,156,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,12,0,20,92,188,220,220,151,68,84,172,239,236,244,204,164,108,124,116,108,156,212,180,95,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,15,31,36,23,7,28,100,191,236,212,127,84,148,236,244,252,228,172,143,132,151,164,212,191,108,31,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,20,20,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,28,36,44,39,23,36,111,199,239,188,111,135,223,252,252,236,183,172,180,188,207,188,108,31,0,0,0,0,15,20,15,7,0,0,0,0,0,0,0,0,12,20,20,12,7,20,28,44,44,39,36,28,23,20,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,31,20,0,0,0,0,0,12,20,28,28,39,44,52,52,39,52,124,204,228,156,143,196,252,252,236,212,204,220,215,188,108,31,0,0,12,28,28,23,20,12,0,0,0,0,0,20,31,36,36,44,60,63,60,52,52,44,44,36,36,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,44,44,28,7,0,0,20,28,36,44,68,76,68,60,76,140,212,204,172,188,247,252,236,236,231,236,188,108,31,0,20,39,44,36,28,15,0,0,7,28,44,52,60,76,84,92,87,84,76,63,52,44,44,44,36,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,39,44,47,60,71,76,76,60,36,23,28,39,47,68,92,100,92,111,172,212,207,212,244,252,247,247,236,188,103,44,36,52,52,44,39,28,20,36,60,79,100,116,124,108,103,100,92,76,60,52,47,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,76,84,84,84,84,84,76,76,76,76,100,132,143,164,204,223,236,244,252,252,236,188,116,84,76,76,68,68,71,76,92,111,124,132,132,132,124,116,84,68,60,52,36,23,20,15,12,0,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,84,84,84,87,100,127,143,156,172,196,215,236,252,252,252,244,212,159,132,140,148,148,132,119,119,124,132,140,148,143,135,119,108,92,71,52,44,31,36,44,44,39,28,23,39,52,47,44,44,44,55,60,52,55,52,36,23,28,47,39,28,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,92,100,108,132,172,212,244,247,252,252,252,244,215,196,207,228,212,196,196,204,204,196,188,175,164,148,143,143,148,148,140,140,140,116,108,108,103,100,84,76,76,79,68,60,60,60,60,60,55,55,52,36,23,28,47,39,28,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,12,12,20,20,20,20,20,44,60,76,76,76,76,76,76,76,76,76,76,76,71,68,68,76,76,84,92,92,92,92,92,92,92,92,92,92,92,100,111,132,156,180,199,223,244,252,252,252,252,247,244,244,252,247,247,252,247,231,204,175,156,156,156,159,164,167,164,151,132,116,108,84,76,68,68,71,71,68,63,63,60,60,60,55,52,52,44,44,36,23,12,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,12,20,23,23,20,20,20,39,60,68,68,68,76,84,92,92,100,103,108,135,159,167,172,172,164,156,164,180,180,175,172,164,164,156,151,151,156,172,188,204,220,236,244,247,252,252,252,252,252,252,252,252,252,247,244,239,220,188,164,124,92,63,44,28,28,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,23,28,36,39,68,92,100,100,100,84,68,68,84,84,79,76,84,100,116,124,127,124,127,148,175,204,220,228,236,252,252,252,252,252,252,252,252,247,244,228,199,164,135,124,108,92,68,52,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,7,0,0,0,12,31,52,60,68,68,68,68,76,100,132,164,172,164,164,183,215,236,244,244,244,252,252,252,252,252,239,212,196,188,188,172,140,108,79,60,52,47,44,36,36,28,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,55,60,60,60,63,68,71,92,116,132,132,116,108,111,135,156,183,215,236,220,215,239,252,252,252,252,252,239,220,191,164,148,148,135,108,68,28,12,20,28,36,36,28,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,44,47,52,52,52,52,55,60,60,60,60,76,92,100,100,100,100,92,95,111,132,164,212,236,196,175,204,244,252,252,252,252,252,252,228,196,164,140,132,143,156,143,116,76,36,12,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,36,39,44,44,44,47,52,52,44,28,15,23,44,68,84,100,100,100,87,63,52,76,108,140,164,199,220,188,140,156,215,228,236,252,252,252,252,252,231,215,196,151,103,92,116,143,164,159,140,100,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,20,23,28,28,36,36,39,44,36,20,0,0,0,20,36,52,60,68,76,92,84,63,31,20,47,100,127,140,156,180,204,183,116,116,167,220,188,212,252,252,252,252,252,236,204,196,188,156,92,52,60,92,135,164,172,156,124,84,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,15,20,20,23,23,20,12,0,0,0,0,0,20,36,44,47,52,55,60,52,39,23,7,0,36,84,124,132,127,132,164,196,175,100,71,135,183,188,143,188,244,236,236,236,236,252,223,188,164,172,156,100,39,20,39,79,124,156,172,159,132,95,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,0,7,0,0,0,0,0,0,0,12,28,36,36,44,44,44,39,20,12,0,0,0,23,68,116,140,124,100,103,148,191,167,95,44,87,180,172,148,127,167,228,220,220,199,220,247,247,212,164,143,156,156,108,44,0,0,28,63,100,140,159,156,116,84,55,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,31,36,36,28,12,0,0,0,0,0,12,47,95,132,132,100,68,87,140,172,148,92,28,44,127,180,148,108,132,156,212,204,204,164,191,228,252,247,207,148,116,148,148,108,44,0,0,0,15,52,79,108,132,132,108,76,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,28,20,12,0,0,0,0,0,0,0,31,79,116,124,108,68,44,79,132,159,127,84,28,20,76,156,140,127,84,116,132,180,196,188,151,148,191,244,252,244,204,132,100,124,132,100,47,15,0,0,0,12,31,60,79,100,108,95,68,44,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,23,23,20,0,0,0,0,0,0,0,0,0,20,55,92,119,108,68,28,20,68,132,148,116,68,28,0,44,108,159,108,100,76,84,100,140,180,180,148,100,156,220,252,252,244,196,119,76,95,116,103,60,20,0,0,0,0,0,28,44,63,76,84,76,52,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,7,0,0,0,0,0,0,0,0,0,0,12,39,71,100,100,79,36,12,15,68,116,119,84,44,20,0,20,76,140,132,87,84,76,52,76,103,148,172,143,71,108,172,244,252,252,244,196,108,60,76,108,100,68,28,0,0,0,0,0,0,15,36,52,60,68,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,60,79,92,76,44,15,0,15,60,108,111,68,28,0,0,0,52,95,135,100,68,71,71,44,76,84,127,172,151,79,55,127,204,236,244,252,244,188,100,52,55,92,92,71,36,12,0,0,0,0,0,0,12,28,44,52,55,55,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,76,52,20,0,0,20,55,92,92,68,36,7,0,0,28,68,116,103,63,60,68,60,44,76,76,100,151,159,92,23,79,156,215,228,244,244,228,164,84,36,44,84,87,71,39,20,0,0,0,0,0,0,0,0,20,36,36,39,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,68,68,52,28,12,0,0,20,52,79,71,47,36,20,0,0,0,52,84,108,76,28,63,68,44,44,76,68,63,108,151,103,20,36,108,180,212,223,231,212,188,135,63,28,36,68,76,68,44,23,0,0,0,0,0,0,0,0,0,12,28,31,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,39,60,68,52,31,12,0,0,0,23,55,68,52,28,20,12,0,0,0,28,63,100,84,55,12,68,68,20,44,68,55,39,71,148,119,28,7,60,132,180,196,212,199,172,151,116,52,20,28,52,68,68,47,28,7,0,0,0,0,0,0,0,0,0,12,20,28,28,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,44,55,52,36,20,0,0,0,0,28,52,60,36,12,12,7,0,0,0,12,52,76,92,68,28,20,63,63,0,44,60,31,20,47,132,127,44,0,20,84,140,172,196,204,172,143,127,100,44,12,20,44,60,60,47,28,12,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,44,36,20,7,0,0,0,0,28,52,52,28,0,0,0,0,0,0,0,36,60,79,68,52,0,44,63,55,0,44,60,15,0,20,103,124,60,0,0,39,100,148,172,191,180,140,116,108,92,44,12,12,36,47,44,39,23,7,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,31,28,28,20,12,0,0,0,0,0,28,52,44,20,0,0,0,0,0,0,0,12,52,60,76,63,28,0,55,60,36,0,47,60,20,7,0,76,116,76,7,0,12,68,124,143,172,183,148,111,100,100,84,36,0,7,20,31,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,20,12,0,0,0,0,0,0,7,28,52,36,15,0,0,0,0,0,0,0,0,36,52,68,63,55,0,0,60,60,12,0,52,60,23,15,0,60,103,84,23,0,0,36,92,124,143,172,164,116,84,87,87,76,28,0,0,12,20,15,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,7,0,0,0,0,0,0,12,31,52,31,12,0,0,0,0,0,0,0,0,20,52,52,68,60,31,0,20,60,60,0,0,52,60,23,20,0,44,84,92,31,0,0,7,60,103,116,148,164,140,87,68,76,76,63,23,0,0,0,0,7,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,28,7,0,0,0,0,0,0,0,0,0,36,47,52,60,52,0,0,36,55,52,0,0,52,52,12,12,0,20,68,84,28,0,0,0,28,76,108,111,148,156,108,68,60,68,71,60,23,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,39,23,0,0,0,0,0,0,0,0,0,0,20,44,39,52,55,36,0,0,52,52,36,0,0,52,52,0,0,0,0,55,76,28,0,0,0,0,47,92,92,116,140,132,76,52,52,68,68,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,36,20,0,0,0,0,0,0,0,0,0,0,0,36,44,36,52,52,12,0,0,52,52,12,0,0,52,52,0,0,0,0,52,68,44,7,0,0,0,28,68,92,84,119,132,100,60,44,44,63,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,0,0,0,0,0,0,0,0,0,0,0,20,39,28,44,52,36,0,0,12,52,52,0,0,0,52,52,0,0,0,0,44,60,52,0,0,0,0,0,44,76,76,92,116,111,68,36,28,36,44,28,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,20,12,0,0,0,0,0,0,0,0,0,0,0,7,36,36,28,52,52,12,0,0,36,47,44,0,0,0,47,47,0,0,0,0,28,52,52,0,0,0,0,0,20,52,79,68,87,108,87,44,28,28,36,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,20,31,47,36,0,0,0,44,47,28,0,0,0,44,44,0,0,0,0,7,47,47,0,0,0,0,0,0,36,63,68,68,84,92,63,36,20,20,36,52,44,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,31,15,44,44,15,0,0,0,44,44,12,0,0,0,44,44,0,0,0,0,0,44,44,12,0,0,0,0,0,15,44,68,52,63,76,76,39,20,20,28,31,44,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,31,15,23,44,36,0,0,0,12,44,44,0,0,0,0,44,44,0,0,0,0,0,44,44,28,0,0,0,0,0,0,36,52,60,52,60,71,55,28,20,12,20,28,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,7,39,44,20,0,0,0,28,39,36,0,0,0,0,44,44,0,0,0,0,0,28,44,39,0,0,0,0,0,0,12,36,60,44,52,60,68,44,20,12,12,15,15,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,20,39,36,0,0,0,0,36,39,28,0,0,0,0,39,39,0,0,0,0,0,12,39,39,0,0,0,0,0,0,0,28,44,52,36,44,52,52,20,7,0,0,0,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,31,36,20,0,0,0,0,36,36,12,0,0,0,0,36,36,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,12,36,52,39,36,39,44,31,12,0,0,0,15,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,12,36,31,0,0,0,0,12,36,36,0,0,0,0,0,28,28,0,0,0,0,0,0,36,36,20,0,0,0,0,0,0,0,20,36,44,28,36,36,36,15,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,28,36,20,0,0,0,0,15,28,28,0,0,0,0,0,12,12,0,0,0,0,0,0,28,36,28,0,0,0,0,0,0,0,12,28,44,36,31,31,36,28,7,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,12,31,31,0,0,0,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,31,0,0,0,0,0,0,0,0,20,28,36,23,28,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,20,28,20,0,0,0,0,0,23,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,23,31,28,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,12,23,28,15,15,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,20,0,0,0,0,0,12,20,20,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,20,20,20,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,12,20,20,15,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,12,15,12,7,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,15,20,20,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_2[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,7,7,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,7,23,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,7,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,12,12,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,12,12,0,0,0,0,20,23,20,0,0,0,0,12,12,0,0,7,7,0,0,0,0,0,0,0,15,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,12,15,12,0,0,0,15,23,23,0,0,0,0,28,28,0,0,20,20,0,0,0,0,0,0,0,28,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,20,20,0,0,0,12,23,23,0,0,0,0,36,36,0,20,28,28,0,0,0,0,12,12,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,7,0,0,0,0,28,28,12,0,0,0,28,28,0,0,0,0,36,36,0,20,20,20,0,0,0,7,12,12,28,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,20,0,0,0,0,20,28,23,0,0,0,28,28,12,0,0,0,36,36,0,23,28,20,0,0,0,20,20,20,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,36,12,0,0,0,0,28,28,0,0,0,36,36,28,0,0,0,36,36,0,36,36,23,0,0,0,15,15,28,39,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,28,36,20,0,0,28,44,44,0,0,0,36,36,0,36,36,12,0,0,0,12,12,36,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,28,39,20,0,0,0,20,36,31,0,0,20,44,52,12,0,0,36,36,0,36,36,0,0,0,12,20,28,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,0,0,12,44,39,12,0,0,0,36,36,12,0,0,44,52,12,0,0,36,36,0,39,39,0,0,0,20,20,39,44,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,28,44,28,0,0,0,36,39,28,0,0,44,60,28,0,0,36,36,7,44,44,0,0,7,31,36,52,47,20,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,12,44,44,20,0,0,20,44,39,0,0,44,71,55,12,0,44,44,20,44,44,0,0,20,36,55,52,47,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,20,36,20,0,0,0,28,52,39,0,0,0,44,44,15,0,39,68,68,15,0,52,52,31,44,44,0,0,36,36,68,52,31,0,0,12,12,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,12,0,0,0,0,0,0,0,0,0,28,39,20,0,0,0,44,52,28,0,0,31,44,36,0,28,68,76,20,0,60,60,44,52,52,0,0,36,52,60,52,12,0,12,20,12,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,7,31,39,20,0,0,20,52,47,12,0,12,52,47,0,12,76,92,44,0,60,60,47,52,47,0,23,44,76,52,44,0,0,28,28,7,0,0,0,0,0,0,0,0,20,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,23,12,0,0,0,0,0,0,0,12,36,44,20,0,0,36,55,36,0,0,47,52,23,0,68,100,60,0,60,60,52,60,36,7,44,52,84,55,23,0,20,28,20,0,0,0,0,0,0,0,7,28,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,31,20,0,0,0,0,0,0,0,20,44,44,15,0,15,52,55,20,0,31,52,44,0,60,108,84,0,60,60,52,68,36,20,52,76,71,55,0,12,36,31,0,0,0,0,0,0,0,12,28,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,28,7,0,0,0,0,0,0,31,52,39,12,0,36,60,44,0,12,55,55,12,52,116,108,23,60,63,55,76,31,39,60,100,60,44,0,28,36,20,0,0,0,0,0,0,12,36,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,36,15,0,0,0,0,12,28,52,60,36,7,12,52,60,28,0,52,60,36,36,124,127,44,60,76,60,84,36,60,79,108,60,15,20,44,36,0,0,0,0,0,0,20,39,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,44,28,0,0,0,12,23,44,55,60,36,0,28,68,55,12,28,60,55,20,116,140,68,60,87,68,92,52,79,103,92,55,12,39,44,15,0,0,0,0,0,20,44,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,52,36,12,0,0,12,28,52,68,60,31,7,52,68,39,12,60,60,28,100,135,84,68,108,87,108,87,100,124,76,36,36,52,31,0,0,0,0,0,28,52,47,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,44,23,0,0,12,36,63,76,60,28,23,68,68,20,52,63,47,84,135,100,79,124,108,132,116,124,124,68,39,60,52,12,0,0,0,0,28,55,52,20,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,60,36,12,0,15,44,76,87,60,28,44,76,52,31,68,63,76,132,116,92,132,116,148,135,156,108,63,60,76,36,0,0,0,0,36,60,52,20,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,60,47,20,0,20,52,87,100,60,36,68,76,39,68,68,76,132,124,108,143,124,164,143,164,87,68,84,60,7,0,0,12,39,68,52,20,0,7,12,20,12,0,7,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,63,60,31,7,20,60,100,108,52,52,76,63,60,71,87,124,127,124,156,135,188,175,156,95,84,84,36,0,0,12,44,71,52,20,0,20,31,28,15,12,12,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,28,20,20,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,60,68,44,20,28,76,111,108,60,71,79,68,76,84,124,124,140,172,167,212,204,140,111,108,76,12,0,15,52,76,52,20,12,28,36,36,28,23,23,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,23,36,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,28,55,76,60,36,36,87,124,111,76,84,79,100,84,140,124,156,188,196,236,199,140,124,108,44,0,20,55,79,60,28,28,44,44,39,36,31,28,23,12,0,0,0,7,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,36,39,44,36,15,0,0,0,0,0,0,0,0,0,0,15,47,76,71,44,47,100,140,116,100,92,124,103,156,132,172,199,223,244,188,156,132,92,20,28,60,100,68,52,47,52,52,52,44,36,31,20,0,0,12,23,28,23,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,0,7,20,36,39,44,44,44,47,39,20,0,0,0,0,0,0,0,0,0,36,68,84,63,68,119,156,132,116,132,148,172,172,204,220,236,228,188,164,140,60,36,76,108,100,68,63,68,68,60,44,36,28,12,12,28,36,36,31,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,20,20,20,28,28,28,36,44,47,52,52,52,47,28,7,0,0,0,0,0,0,28,60,84,79,92,140,159,148,135,172,196,220,236,244,247,220,204,172,116,68,92,124,124,100,92,92,87,63,47,36,28,31,44,44,36,36,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,28,28,36,44,52,52,47,39,44,52,60,60,55,55,60,60,55,36,12,0,0,0,0,12,52,84,92,111,156,172,164,183,215,244,252,252,252,228,212,156,108,119,159,156,124,124,124,100,68,55,52,52,52,47,44,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,12,20,20,15,28,44,55,60,68,68,84,79,84,84,92,92,79,68,63,68,60,44,20,0,0,0,36,76,103,132,172,188,204,228,252,252,252,252,236,196,148,148,196,196,172,156,132,116,103,92,68,52,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,7,20,20,20,28,52,52,52,60,76,92,92,100,108,108,111,124,132,132,119,100,84,76,68,52,28,7,28,63,108,156,196,223,239,252,252,252,252,231,191,180,212,236,212,180,156,148,124,84,63,60,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,7,20,20,15,20,36,28,28,36,52,76,84,108,127,148,156,156,140,132,132,151,167,164,143,124,108,92,68,52,68,108,172,228,247,252,252,252,252,228,215,228,252,252,228,204,172,124,84,76,55,36,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,44,44,44,47,52,63,84,108,132,156,172,180,188,196,204,212,212,196,167,135,111,116,156,207,244,252,252,252,252,244,244,252,252,244,215,180,159,132,84,55,36,28,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,28,44,52,44,20,20,44,60,60,60,60,60,68,84,95,100,100,100,108,116,132,156,180,196,204,223,244,247,236,204,180,180,212,244,252,252,252,252,252,252,252,252,239,207,156,111,68,47,44,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,28,44,52,44,20,20,44,60,60,68,68,60,68,68,71,68,68,76,76,92,103,116,132,159,196,231,244,252,252,252,252,244,244,247,252,252,252,252,252,252,252,252,236,204,172,140,103,76,68,60,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,68,76,100,111,132,140,140,143,156,180,204,215,236,252,252,252,252,252,252,252,252,252,252,252,252,252,252,239,215,188,159,148,132,116,100,87,68,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,44,55,76,79,95,103,116,140,159,172,172,172,199,228,239,239,244,252,252,252,252,252,252,252,252,244,236,231,223,196,156,127,100,92,87,84,84,84,76,63,47,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,44,68,84,84,92,92,87,84,100,132,164,183,172,180,207,239,252,252,252,252,252,252,252,252,244,231,212,196,188,188,188,172,156,140,111,92,84,84,84,84,84,79,79,76,71,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,23,28,36,44,52,63,84,111,132,140,127,116,116,132,156,196,236,252,252,252,252,252,252,252,252,247,236,207,183,164,156,159,156,148,116,100,95,95,92,79,76,79,79,79,79,79,79,76,76,76,71,55,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,20,23,28,36,36,47,71,95,108,108,108,100,100,100,116,164,220,247,252,252,252,252,252,239,239,244,252,252,239,196,143,124,116,111,124,135,140,124,95,71,63,60,47,36,28,36,52,68,76,76,76,71,60,60,55,36,28,31,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,12,12,0,0,20,52,79,100,108,100,79,60,60,76,111,140,188,223,247,239,239,252,252,252,228,215,220,236,236,239,228,196,148,100,84,79,71,76,92,116,124,108,84,63,60,55,47,28,12,0,0,12,23,36,47,52,36,28,31,20,12,20,12,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,47,63,76,84,84,60,28,31,60,79,108,124,156,196,236,228,220,228,252,252,252,228,188,172,199,204,204,220,204,188,156,108,79,60,44,47,60,63,71,92,108,92,68,55,52,52,47,36,20,0,0,0,0,0,0,12,12,12,20,12,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,52,60,60,52,28,7,12,44,68,79,100,108,132,172,220,231,196,196,223,244,252,252,244,180,143,143,156,164,172,196,183,164,140,116,84,68,47,23,23,44,55,55,60,68,84,76,60,52,44,44,44,39,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,47,47,36,15,0,0,28,52,68,71,84,92,108,148,204,244,204,172,180,220,220,239,252,244,188,124,100,132,127,140,140,164,164,148,124,108,92,71,63,36,12,0,28,44,52,52,47,52,60,60,52,44,44,39,36,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,36,44,39,20,0,0,0,12,39,60,63,60,68,84,95,116,180,236,228,156,156,180,191,172,220,244,236,196,116,84,100,116,108,116,124,140,135,127,108,95,84,71,68,55,31,0,0,7,28,44,44,44,39,39,39,39,36,36,36,36,36,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,31,36,36,23,12,0,0,0,0,23,52,60,52,47,60,84,84,92,140,204,228,175,127,164,183,156,132,199,231,212,188,116,71,60,95,95,92,100,108,116,108,108,100,84,71,63,63,60,52,23,0,0,0,12,28,39,36,36,36,31,23,20,28,31,31,28,28,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,28,28,28,12,0,0,0,0,0,12,36,52,55,36,36,52,84,60,60,100,172,212,196,124,116,183,159,119,116,196,212,180,172,116,60,39,68,87,84,76,92,92,100,84,84,76,84,63,52,52,60,60,44,20,0,0,0,0,12,28,36,31,28,28,20,7,7,15,23,20,20,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,23,15,0,0,0,0,0,0,0,23,44,52,44,23,28,55,76,52,31,60,124,175,196,140,76,127,188,124,84,108,188,204,172,172,116,63,44,28,68,76,76,63,84,84,84,68,60,60,84,68,44,39,52,55,52,36,12,0,0,0,0,0,12,28,28,20,12,15,12,7,0,0,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,12,28,44,44,28,12,28,60,76,44,20,39,92,135,180,164,87,68,156,172,84,63,103,172,188,164,180,108,79,44,20,36,63,68,60,52,71,68,76,63,44,47,71,76,52,28,31,52,52,44,28,0,0,0,0,0,0,0,0,12,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,36,15,0,31,63,68,36,12,31,79,108,156,175,116,39,84,172,143,52,55,100,156,175,164,172,103,87,36,15,12,36,63,63,47,52,60,63,68,60,36,31,60,76,60,28,15,36,44,44,36,20,0,0,0,0,0,0,0,0,12,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,20,0,0,36,68,60,31,0,28,60,84,124,172,148,60,28,116,175,116,28,52,100,151,164,164,156,108,84,36,20,0,0,36,68,52,36,52,52,52,60,60,31,20,44,68,60,28,0,12,36,44,39,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,23,12,0,12,36,68,55,28,0,20,52,68,87,143,164,92,12,44,140,159,76,20,52,100,148,156,156,148,119,60,44,28,0,0,0,44,60,36,28,52,44,44,52,60,31,12,28,52,52,28,12,0,15,36,36,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,12,39,63,47,20,0,12,44,60,63,103,156,116,36,0,79,164,140,44,31,47,100,148,148,148,143,132,44,60,28,0,0,0,15,52,55,28,23,44,36,39,47,60,36,7,15,36,44,31,12,0,0,20,31,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,7,0,0,0,15,44,60,39,12,0,12,36,52,52,76,140,132,60,0,20,108,164,100,15,39,44,92,143,140,132,140,127,47,60,23,15,0,0,0,28,52,44,15,20,44,36,28,44,60,36,7,0,20,36,28,15,0,0,0,20,28,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,20,44,55,36,7,0,0,28,52,36,44,108,140,87,20,0,55,132,148,60,0,44,44,79,140,140,111,135,119,60,44,20,15,0,0,0,0,31,52,31,7,23,44,28,23,36,55,36,12,0,12,28,28,20,0,0,0,0,20,28,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,20,44,52,28,0,0,0,23,44,31,36,79,132,108,44,0,0,84,148,116,36,0,44,44,68,140,140,100,132,119,76,36,20,7,0,0,0,0,12,39,47,20,0,20,36,20,20,36,52,36,12,0,0,20,28,20,0,0,0,0,7,20,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,47,44,23,0,0,0,20,39,31,15,39,103,124,63,7,0,20,100,143,76,15,0,28,28,52,132,135,92,119,124,84,28,28,0,0,0,0,0,0,20,44,39,12,0,20,36,20,12,28,47,36,12,0,0,12,15,12,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,39,20,0,0,0,12,36,31,15,20,71,108,84,23,0,0,52,108,124,44,0,0,28,28,39,124,132,84,100,124,79,20,20,0,0,0,0,0,0,0,23,44,28,0,0,20,23,7,0,28,44,36,12,0,0,0,7,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,36,12,0,0,0,0,20,28,15,12,44,92,92,44,0,0,0,71,116,92,28,0,12,36,36,36,116,124,68,76,116,68,20,20,0,0,0,0,0,0,0,0,28,39,20,0,0,12,7,0,0,20,39,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,28,12,0,0,0,0,12,23,12,0,20,68,100,68,12,0,0,20,84,116,55,12,0,15,23,23,36,116,119,52,60,111,60,20,12,0,0,0,0,0,0,0,0,12,36,36,12,0,0,0,0,0,0,20,36,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,20,0,0,0,0,0,15,20,7,0,0,39,84,79,28,0,0,0,44,84,100,36,0,0,20,20,20,36,108,116,44,47,108,63,36,12,12,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,7,0,0,15,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,20,0,0,0,0,0,0,20,12,0,0,12,63,84,52,0,0,0,0,60,92,68,23,0,0,20,20,12,20,84,103,39,44,95,68,36,7,7,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,12,7,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,44,84,68,15,0,0,0,15,60,84,39,12,0,0,20,20,0,0,52,92,39,44,76,68,36,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,0,0,0,0,0,0,0,0,0,0,0,20,68,79,36,0,0,0,0,31,55,68,20,0,0,0,0,0,0,0,39,79,36,31,52,60,28,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,44,76,52,0,0,0,0,0,39,55,44,12,0,0,0,0,0,0,0,36,76,36,28,36,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,63,20,0,0,0,0,7,36,52,15,0,0,0,0,7,7,0,0,36,68,28,20,36,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,63,36,0,0,0,0,0,20,36,39,7,0,0,0,0,0,0,0,12,47,68,28,7,36,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,44,0,0,0,0,0,0,31,39,28,7,0,0,0,0,0,0,0,15,52,68,28,0,20,36,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,47,52,20,0,0,0,0,0,12,31,36,0,0,0,0,0,0,0,0,0,12,52,63,28,0,15,28,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,47,28,0,0,0,0,0,0,20,28,23,0,0,0,0,0,0,0,0,0,12,47,47,12,0,20,23,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,36,7,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,44,36,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,12,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,15,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_3[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,28,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,20,7,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,20,20,15,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,31,28,28,20,20,12,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,31,44,28,23,15,7,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,36,36,44,36,31,20,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,12,12,0,0,0,0,0,0,0,0,0,7,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,52,39,52,44,39,28,12,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,12,12,20,12,12,12,0,0,0,0,0,0,12,0,0,0,39,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,52,55,52,52,44,36,20,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,12,20,20,20,20,12,0,0,0,0,0,12,12,0,0,39,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,55,60,52,44,28,7,12,23,15,0,0,0,0,0,0,0,7,12,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,12,0,0,0,0,0,0,0,0,0,0,7,7,0,0,28,36,20,15,28,28,20,20,0,0,0,0,12,15,20,12,0,44,44,23,28,23,0,0,0,0,0,0,0,0,0,0,0,44,68,71,63,60,55,36,12,15,28,20,0,0,0,0,0,0,0,7,20,15,20,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,15,0,0,0,0,0,0,0,0,0,7,12,12,0,15,36,36,20,28,28,31,23,12,0,0,0,0,12,28,12,0,44,44,36,44,44,0,0,0,0,0,0,0,0,0,0,20,60,87,71,71,60,47,28,20,36,36,12,0,0,0,0,0,0,0,12,20,23,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,20,36,39,23,0,0,0,0,0,0,0,0,0,7,20,12,7,20,44,31,23,31,36,28,28,0,0,0,0,20,36,15,0,44,44,44,47,44,0,0,0,0,0,0,0,0,0,0,47,79,92,79,76,60,36,28,44,44,20,0,0,0,0,0,0,15,15,15,23,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,0,0,15,36,44,28,12,0,0,0,0,0,0,0,0,15,28,28,12,36,44,31,31,36,44,28,12,0,0,0,20,44,31,12,44,47,52,52,39,0,0,0,0,0,0,0,0,0,28,68,100,84,84,68,52,36,44,52,23,0,0,0,0,0,0,20,31,28,31,36,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,12,31,47,36,20,0,0,0,0,0,0,0,12,36,44,31,28,44,44,36,36,47,36,28,0,0,0,20,44,44,23,44,52,60,52,36,0,0,0,0,0,0,0,0,0,60,100,108,92,87,60,44,44,60,31,0,0,0,0,0,0,20,28,39,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,15,0,0,0,0,0,28,47,44,23,0,0,0,0,0,0,0,15,47,60,36,36,52,47,47,52,55,36,12,0,0,12,44,60,31,36,52,68,47,28,0,0,0,0,0,0,0,0,28,92,124,108,100,79,52,55,60,44,12,0,0,0,0,12,23,36,36,44,36,20,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,12,0,0,0,0,23,47,52,31,7,0,0,0,0,0,0,23,60,60,36,47,60,60,52,60,44,31,0,0,7,39,71,36,36,52,71,47,28,0,0,0,0,0,0,0,0,68,116,132,116,100,76,68,68,52,20,0,0,0,0,20,36,47,47,44,31,15,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,15,28,28,23,12,0,0,0,20,44,55,39,20,0,0,0,0,0,0,36,68,60,44,55,68,68,60,68,44,15,0,0,36,76,47,36,52,76,52,28,0,0,0,0,0,0,0,31,100,148,132,116,92,76,79,68,28,0,0,0,0,23,44,60,60,47,28,12,0,0,7,15,12,7,12,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,20,7,0,0,0,12,20,31,36,20,7,0,0,12,36,60,52,23,0,0,0,0,0,12,44,76,63,52,60,79,76,84,55,36,0,0,39,84,68,47,60,84,60,28,0,0,0,0,0,0,0,71,132,151,132,108,87,92,84,36,0,0,0,7,28,52,63,63,47,28,0,0,0,15,20,20,20,20,23,28,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,20,12,0,0,0,15,31,36,36,20,0,0,0,31,60,60,36,0,0,0,0,0,15,60,87,68,63,79,95,84,79,47,12,0,39,92,84,52,60,92,60,28,0,0,0,0,0,0,36,108,167,159,132,108,103,92,52,7,0,0,12,36,63,68,68,44,20,0,0,20,28,28,28,28,28,36,39,31,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,28,28,15,0,0,7,23,36,44,36,15,0,0,28,52,68,44,23,20,15,0,0,23,76,95,84,79,103,103,100,68,36,0,28,87,95,60,60,92,60,28,0,0,0,7,12,15,76,148,180,156,124,116,108,63,15,0,0,15,39,76,76,68,44,20,0,12,28,36,36,36,36,39,47,44,28,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,20,0,0,12,31,44,44,28,12,0,20,47,68,60,44,28,20,7,0,36,92,100,87,92,119,108,100,55,12,20,79,108,68,63,100,63,28,0,0,0,12,15,39,119,191,188,148,135,124,84,23,0,0,20,52,84,84,68,36,12,7,28,44,44,52,44,44,55,52,36,20,12,7,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,36,36,20,0,0,20,44,47,44,23,0,12,44,68,68,52,31,20,0,0,52,108,111,103,119,132,124,79,36,20,84,124,84,76,108,63,20,0,0,12,20,31,84,172,220,188,156,148,108,36,0,0,28,63,92,92,68,31,12,20,39,47,60,55,60,63,63,44,28,20,12,20,20,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,39,28,7,12,31,47,52,44,20,7,36,68,76,60,44,23,15,12,68,119,124,116,148,148,124,60,28,76,148,108,95,108,60,20,0,0,28,28,60,140,220,215,183,159,124,55,0,0,36,76,100,100,60,28,20,36,52,60,68,71,71,76,55,36,23,20,23,23,20,20,12,0,0,7,12,15,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,44,28,12,20,44,52,52,36,15,28,60,76,71,60,39,20,20,84,132,132,143,172,164,92,44,68,156,132,116,116,63,28,7,12,31,44,100,191,239,212,180,140,71,12,12,44,92,111,100,52,28,28,52,68,76,84,84,87,68,44,31,31,31,28,28,23,12,0,12,20,20,20,15,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,52,36,23,28,52,60,52,31,28,52,84,87,76,52,23,36,95,140,148,188,199,148,68,60,148,148,140,124,68,36,20,31,36,79,143,228,239,212,164,87,20,12,52,108,119,95,47,36,44,68,84,100,100,100,76,60,44,44,36,36,31,28,12,12,23,28,28,23,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,12,36,52,52,52,39,36,44,60,63,52,36,47,76,100,92,63,36,52,108,148,180,204,196,108,76,132,172,159,140,84,39,20,44,55,119,196,244,236,188,108,31,20,68,124,124,92,52,47,68,92,111,116,108,92,71,60,52,39,36,36,28,23,28,36,36,28,28,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,23,20,0,0,0,12,36,52,52,60,52,52,55,68,63,52,52,71,103,103,84,44,68,119,167,204,215,167,95,124,172,180,164,108,44,44,47,95,156,236,244,212,124,47,31,92,140,132,87,60,63,92,124,135,132,116,100,76,60,44,44,39,36,36,36,36,36,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,20,28,28,28,28,20,7,0,12,36,55,60,60,60,63,68,68,68,68,76,108,124,108,63,84,140,196,223,220,132,124,167,196,196,140,60,76,68,140,196,252,228,156,68,47,108,156,140,92,76,92,132,159,159,140,132,108,84,55,47,52,55,52,44,44,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,36,39,44,39,28,12,12,36,60,60,63,76,84,79,76,76,84,119,148,135,92,100,172,220,239,183,148,164,212,215,156,63,100,108,180,236,239,180,87,63,119,164,148,108,100,132,172,188,188,172,140,100,68,68,71,68,52,52,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,47,55,60,52,47,31,20,36,60,68,76,95,100,87,87,100,132,164,156,116,132,196,239,228,167,172,212,228,159,84,116,164,212,244,196,116,84,132,172,164,132,140,175,196,207,204,172,119,92,92,87,68,52,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,60,76,79,84,60,44,52,68,71,84,111,116,100,116,148,175,164,140,164,215,247,196,188,199,236,172,124,140,204,236,212,140,108,140,180,175,172,188,212,231,220,188,148,124,116,92,68,55,52,47,28,0,0,0,0,0,12,12,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,52,76,95,95,100,100,84,79,84,92,111,132,132,132,156,188,172,164,191,231,223,212,212,247,196,172,188,236,223,172,135,159,196,196,196,220,244,239,220,188,156,124,92,68,60,52,36,12,0,15,28,39,44,39,39,36,36,28,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,7,7,0,0,12,12,12,20,44,63,84,100,108,108,108,108,124,132,127,143,159,164,175,196,196,196,228,247,231,231,252,228,223,228,236,199,172,188,220,215,220,236,252,244,228,188,132,92,68,60,44,36,36,55,71,84,87,84,76,68,52,44,36,28,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,12,20,20,20,44,39,36,39,36,28,39,60,92,124,132,124,119,132,156,180,196,204,207,212,228,228,236,252,247,247,252,244,244,247,231,204,212,236,239,239,252,247,228,188,140,103,84,84,76,84,92,100,100,100,95,92,92,84,68,52,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,20,31,28,28,47,60,68,84,87,92,92,95,111,135,156,167,175,199,220,236,236,244,247,252,252,252,252,252,252,252,252,236,236,244,252,252,236,212,188,164,148,132,116,103,100,100,100,100,100,100,87,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,28,36,44,44,44,52,71,92,103,108,116,140,175,204,220,236,244,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,239,220,196,164,132,108,100,100,100,100,87,71,52,31,12,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,12,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,15,15,15,15,15,15,15,15,15,15,15,12,0,0,0,0,0,0,0,7,20,36,52,60,60,68,79,108,132,148,156,188,228,252,252,252,252,252,252,252,252,252,252,252,252,252,252,236,212,172,143,132,135,132,116,100,84,68,60,60,63,68,63,68,68,63,63,63,60,31,28,36,36,36,36,36,28,28,20,12,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,23,28,36,36,36,36,36,44,44,44,36,36,39,44,47,47,47,52,55,60,60,60,63,71,84,100,116,132,156,183,212,231,236,244,252,252,252,252,252,252,252,252,252,252,252,236,220,204,188,164,151,148,132,124,124,119,100,84,76,68,68,68,68,63,63,63,60,31,28,36,36,36,36,36,28,28,20,12,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,15,15,20,23,28,28,28,28,36,39,44,44,44,44,52,52,52,52,60,68,84,100,116,132,156,175,196,212,228,244,252,252,252,252,252,252,252,252,252,236,223,220,228,244,228,191,156,148,132,124,116,116,100,76,68,63,60,52,52,52,44,44,44,36,15,12,28,36,28,28,28,28,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,52,60,76,92,111,127,148,164,175,180,180,199,231,252,252,252,252,252,252,252,252,247,231,199,183,180,172,159,140,116,95,100,100,92,84,76,60,52,55,60,52,52,52,52,44,44,44,36,15,12,28,36,28,28,28,28,23,20,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,47,52,52,68,87,108,124,156,183,204,207,199,183,175,183,204,220,244,252,244,239,239,252,252,252,252,247,231,196,140,108,103,116,116,92,68,60,52,52,47,44,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,12,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,36,36,36,39,44,52,71,92,108,111,124,143,159,159,164,159,143,132,132,148,156,172,196,228,247,244,207,204,228,236,236,252,252,252,247,220,172,132,100,76,71,68,63,52,44,39,44,44,44,36,28,23,20,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,12,20,20,20,20,44,60,76,87,92,92,92,95,100,100,103,108,103,92,84,84,92,100,100,124,164,196,220,244,236,188,156,180,220,204,204,247,244,244,252,252,231,180,116,68,60,60,63,60,60,52,28,0,0,0,12,20,20,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,15,12,20,36,52,52,52,60,47,47,52,68,68,76,76,76,60,47,44,44,47,60,68,76,100,140,156,164,188,215,220,172,116,140,204,212,172,180,244,220,212,228,231,239,236,196,135,68,28,28,47,60,55,52,52,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,28,28,23,28,36,36,44,52,55,60,47,39,20,23,28,31,20,12,36,55,63,68,84,108,116,108,124,156,196,199,156,87,84,164,223,167,140,172,236,188,172,180,196,215,228,236,196,148,92,44,0,7,28,47,52,44,44,39,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,20,20,20,20,23,28,36,31,20,15,12,20,12,20,7,0,0,20,44,60,60,63,76,84,84,76,95,116,132,164,172,132,63,47,116,196,204,116,108,180,204,156,135,132,167,172,204,228,223,183,148,103,60,15,0,0,12,31,44,44,36,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,20,20,12,12,0,0,0,0,0,12,0,0,0,0,0,28,44,52,55,60,60,63,60,60,76,84,100,116,148,140,100,44,28,76,156,220,164,63,92,196,180,140,103,108,140,140,156,196,228,212,164,132,100,68,28,0,0,0,0,15,31,36,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,47,52,52,52,44,44,52,55,63,68,68,84,108,127,116,76,28,7,36,108,191,212,119,28,100,196,156,124,84,108,100,127,124,148,196,231,188,132,100,92,68,36,12,0,0,0,0,0,15,28,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,47,44,28,28,39,47,52,55,52,52,76,100,108,100,60,20,0,12,60,148,220,175,76,15,108,196,140,92,79,92,71,108,108,116,135,188,199,132,79,68,68,60,44,20,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,44,44,36,15,15,31,44,44,44,36,28,52,68,92,92,84,44,12,0,0,28,92,172,212,127,31,20,116,180,108,60,76,68,63,76,100,100,103,124,164,156,100,60,44,47,52,44,20,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,36,36,20,0,12,28,36,36,39,28,20,20,52,63,79,76,68,28,7,0,0,7,52,119,183,164,84,0,31,116,180,84,28,63,55,55,60,79,87,100,87,108,140,132,84,44,20,28,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,28,31,36,28,12,0,7,20,31,36,36,20,12,0,20,39,60,68,63,47,23,0,0,0,0,20,76,140,172,119,44,0,44,119,172,71,20,52,52,47,52,60,76,92,87,71,108,132,124,76,36,0,7,20,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,15,0,0,0,15,28,28,31,20,0,0,0,20,36,47,55,52,36,15,0,0,0,0,0,47,108,148,143,84,12,0,52,116,164,60,7,28,52,47,28,60,60,68,100,76,60,108,124,116,60,20,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,23,20,7,0,0,0,12,20,23,23,15,0,0,0,0,20,36,47,36,28,15,12,0,0,0,0,0,28,76,116,143,116,52,0,0,60,100,140,60,0,0,44,44,15,52,55,44,79,92,55,55,108,116,100,52,12,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,0,0,0,0,0,7,12,15,20,15,0,0,0,0,0,20,36,44,36,20,0,0,0,0,0,0,0,7,52,92,108,124,84,15,0,0,63,76,100,55,0,0,44,44,23,28,52,44,44,92,76,39,60,108,108,92,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,20,36,31,20,12,12,0,0,0,0,0,0,0,36,68,84,103,100,60,0,0,0,60,60,68,52,0,0,28,39,36,0,44,44,28,60,92,60,28,63,103,100,84,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,7,20,31,23,7,0,0,0,0,0,0,0,0,0,15,52,76,68,100,84,23,0,0,0,60,60,52,47,0,0,12,36,36,0,28,44,36,20,76,87,39,28,60,92,84,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,0,0,0,36,60,52,68,87,63,0,0,0,7,60,60,44,47,0,0,0,31,31,7,0,39,39,12,39,84,71,20,23,60,84,68,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,12,0,0,0,0,0,0,0,0,0,0,0,20,52,47,28,76,79,36,0,0,0,20,60,60,44,44,0,0,0,28,28,20,0,23,36,28,0,52,76,47,7,28,60,68,52,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,39,52,23,36,76,68,0,0,0,0,28,55,60,36,39,0,0,0,15,20,20,0,7,36,36,7,15,60,68,31,0,23,52,55,47,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,36,7,63,76,44,0,0,0,0,39,52,52,28,36,0,0,0,0,20,20,0,0,20,28,20,0,28,60,52,15,0,20,44,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,44,15,28,76,68,12,0,0,0,0,44,52,44,28,36,0,0,0,0,12,12,0,0,0,28,28,0,0,28,52,36,0,0,20,44,39,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,55,76,47,0,0,0,0,0,47,47,31,28,36,0,0,0,0,12,12,12,0,0,15,20,12,0,0,36,44,20,0,0,20,39,36,28,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,7,20,68,68,20,0,0,0,0,0,44,44,20,23,28,0,0,0,0,0,0,0,0,0,0,20,20,0,0,12,39,39,12,0,0,20,36,28,28,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,0,44,68,52,0,0,0,0,0,0,44,44,7,20,23,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,20,44,28,0,0,0,20,36,28,23,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,0,12,68,68,28,0,0,0,0,0,0,44,44,0,15,20,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,28,36,20,0,0,0,20,23,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,36,68,60,0,0,0,0,0,0,0,39,39,0,15,20,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,12,31,31,12,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,20,0,0,60,68,31,0,0,0,0,0,0,15,36,36,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,20,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,28,63,60,0,0,0,0,0,0,0,28,36,36,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,44,60,36,0,0,0,0,0,0,0,28,28,28,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,7,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,12,47,47,12,0,0,0,0,0,0,0,28,28,20,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,31,44,28,0,0,0,0,0,0,0,0,31,31,20,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,7,36,36,7,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,23,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,0,0,0,7,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_4[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,20,23,12,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,15,0,31,31,7,0,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,36,36,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,20,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,12,23,36,36,0,0,0,28,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,28,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,36,36,28,0,0,7,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,28,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,0,39,39,12,0,0,23,36,28,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,44,44,0,0,0,36,36,12,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,39,31,28,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,12,36,36,28,44,44,0,0,20,44,36,0,0,0,0,7,12,12,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,20,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,44,44,36,20,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,20,28,28,44,44,31,0,0,39,44,20,0,0,0,0,20,20,7,0,0,7,20,20,12,0,0,0,0,0,0,0,0,12,28,36,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,52,47,36,7,0,0,0,0,0,0,15,20,20,12,12,0,0,0,0,28,31,28,47,47,12,0,20,44,44,0,0,0,0,20,28,12,0,0,0,15,20,15,12,0,0,0,0,0,0,0,20,36,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,52,60,44,28,0,0,0,0,0,0,7,20,28,12,12,0,0,0,0,36,36,36,52,52,0,0,36,44,28,0,0,0,12,28,23,0,0,0,12,15,20,15,12,0,0,0,0,0,7,28,44,47,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,63,60,44,15,0,0,0,0,0,0,28,28,12,7,0,0,0,0,44,44,52,52,47,0,12,52,52,12,0,0,7,28,36,12,0,0,20,20,12,20,15,0,0,0,0,0,15,36,60,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,60,71,60,36,0,0,0,0,0,0,31,31,28,15,0,0,0,0,44,44,55,52,36,0,36,52,36,0,0,0,28,36,20,0,0,28,44,31,23,15,0,0,0,0,0,23,52,63,55,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,52,68,76,52,23,0,0,0,0,0,36,36,60,28,12,0,0,0,47,52,55,55,20,0,52,52,20,0,0,20,39,36,7,0,28,44,44,28,20,0,0,0,0,12,36,63,68,52,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,68,79,76,47,12,0,0,0,0,28,36,76,36,28,0,0,20,52,68,60,60,0,28,55,47,0,0,12,36,39,20,0,28,47,44,36,23,12,0,0,0,20,52,76,68,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,60,76,87,68,36,0,0,0,0,12,44,76,36,36,0,0,52,68,92,60,55,0,52,60,28,0,0,36,52,28,12,28,52,52,44,28,12,0,0,7,36,68,84,68,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,68,92,95,60,20,0,0,0,0,44,71,47,39,0,0,68,71,100,60,44,28,60,55,0,0,28,52,52,23,31,52,60,52,28,12,0,0,20,52,84,87,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,60,84,100,92,52,12,0,0,0,44,63,68,44,0,0,68,76,100,60,23,52,60,36,0,20,52,60,39,39,60,68,60,36,12,0,0,31,76,100,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,76,100,116,87,44,12,0,0,44,55,92,44,0,0,68,84,92,68,28,63,63,12,7,44,76,52,44,68,76,68,36,12,0,12,55,100,111,79,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,52,92,124,124,92,44,7,0,28,52,100,52,7,28,84,124,79,63,47,68,52,0,36,76,76,68,76,87,76,36,12,0,28,79,124,111,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,111,140,124,76,28,0,7,52,108,60,20,60,108,156,71,63,68,68,23,23,71,87,84,84,92,84,44,15,12,52,100,127,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,20,12,0,0,12,7,0,0,0,0,0,0,0,0,31,95,140,156,127,60,12,0,60,116,76,36,71,111,156,71,68,71,60,20,60,95,100,92,108,92,44,20,28,76,124,132,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,31,28,20,12,15,12,0,0,0,0,0,0,12,52,127,175,172,116,39,0,52,116,100,52,100,140,143,84,76,76,44,47,100,119,108,124,103,52,23,44,100,140,124,76,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,15,0,0,0,12,20,31,36,39,44,31,28,28,23,12,0,0,0,0,0,20,84,164,207,172,87,20,44,108,124,63,132,180,135,108,76,79,52,100,132,132,135,111,60,36,68,119,140,108,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,36,28,31,28,12,7,7,20,47,68,60,60,44,36,36,23,7,0,0,0,0,36,124,207,220,148,60,28,100,135,84,148,212,140,132,84,92,108,148,164,159,124,68,52,87,132,127,84,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,44,63,68,55,36,12,20,47,68,79,76,76,60,47,39,20,0,0,0,0,68,164,228,212,116,36,92,143,108,164,228,164,135,111,124,172,191,188,148,87,76,108,132,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,15,20,36,60,68,71,76,76,63,47,44,60,84,92,100,92,76,60,36,15,0,0,20,103,199,244,175,76,87,148,140,172,231,191,140,151,183,220,220,175,124,103,124,127,92,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,20,20,20,15,12,12,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,28,36,60,84,84,84,84,84,79,76,71,76,92,108,124,124,92,63,36,12,0,44,140,223,223,132,95,140,164,188,231,199,164,188,236,244,204,151,127,132,116,68,20,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,36,31,28,28,39,52,52,44,31,31,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,20,28,31,44,47,63,103,124,124,108,92,84,92,100,108,116,132,148,140,100,63,28,12,68,164,228,188,124,143,191,212,239,212,204,223,244,220,180,151,132,95,44,0,0,0,0,0,0,0,0,0,20,36,44,44,44,44,52,63,84,92,92,84,79,68,60,47,36,31,23,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,44,52,76,76,87,116,143,148,132,108,108,124,148,148,156,164,148,108,60,36,84,180,220,159,164,204,236,252,236,236,244,228,196,164,119,71,20,0,0,0,0,0,0,20,39,52,52,55,68,84,100,116,124,116,95,87,84,79,79,79,63,47,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,71,79,79,92,119,151,164,156,148,164,183,183,188,188,156,108,76,116,196,196,196,212,252,252,252,252,247,220,172,108,52,12,0,0,0,28,44,68,76,92,100,116,135,140,140,119,100,92,92,92,84,79,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,79,84,100,124,164,188,196,204,212,228,228,204,148,124,156,196,228,228,252,252,252,252,228,180,100,39,12,28,52,76,100,124,143,159,164,156,143,124,108,92,92,87,79,68,44,28,12,0,0,0,0,0,12,20,15,7,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,7,0,12,23,31,36,47,60,76,111,143,164,183,191,204,220,236,252,231,191,180,207,239,247,252,252,244,212,164,116,87,84,108,132,148,156,164,167,164,148,132,124,116,111,100,87,71,60,52,52,60,68,76,76,52,39,47,60,52,39,20,12,0,15,31,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,7,0,12,23,31,36,44,52,52,76,100,116,143,172,204,228,239,252,252,247,228,228,244,252,252,252,236,204,164,148,159,183,207,223,228,207,196,183,172,164,148,140,132,135,140,148,151,148,148,140,148,135,119,108,76,60,68,103,108,76,44,36,20,28,44,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,47,63,84,92,100,100,116,140,164,196,220,239,252,252,252,252,252,252,236,220,215,236,247,252,252,244,228,207,199,196,204,204,204,204,204,207,204,199,196,191,175,156,156,135,108,84,60,44,44,71,76,44,20,20,20,20,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,63,76,84,92,92,92,108,127,143,156,172,180,196,220,244,252,252,252,252,252,252,252,252,252,252,252,239,236,236,236,228,212,207,204,204,191,172,156,140,127,124,108,92,84,76,68,52,36,28,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,39,52,60,71,84,87,92,92,92,92,92,92,92,95,108,132,148,167,188,191,188,172,164,180,204,228,244,252,252,252,252,252,252,252,252,252,252,252,236,215,196,172,156,140,143,148,148,132,116,92,84,79,76,76,71,76,76,63,63,60,52,44,36,44,36,28,28,15,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,12,44,60,52,36,55,84,92,92,92,92,92,92,92,92,92,92,92,103,124,140,148,143,135,124,116,108,108,103,108,119,148,175,204,228,247,252,252,252,252,247,247,252,252,252,252,252,228,196,164,140,116,100,87,76,60,44,44,52,52,52,60,60,60,60,52,44,44,44,31,23,20,36,36,28,28,15,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,28,20,28,60,79,60,39,55,84,92,92,87,84,76,68,68,71,84,92,87,79,76,76,76,76,76,76,68,52,52,68,100,132,172,196,215,236,252,244,236,236,252,228,228,231,252,252,252,252,244,220,188,148,116,92,76,55,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,28,28,28,20,23,47,60,44,28,23,28,20,12,20,36,52,60,68,68,68,68,68,71,71,68,52,31,12,0,20,60,103,132,159,172,172,172,204,236,252,212,204,212,236,220,191,196,236,252,252,247,231,207,191,167,127,100,87,84,71,52,28,20,15,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,12,7,0,0,0,0,0,12,28,36,36,44,44,52,60,60,68,68,63,52,31,12,0,0,0,0,28,60,92,124,148,156,148,124,132,167,212,244,244,172,167,199,220,204,172,148,188,244,247,236,228,220,196,164,148,132,92,60,44,44,44,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,23,28,36,36,36,44,44,52,44,28,12,0,0,0,0,0,0,0,28,60,84,108,124,132,124,100,84,108,143,180,215,244,212,132,140,212,196,180,180,116,124,199,244,231,212,204,196,188,159,132,108,87,60,44,28,20,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,20,20,20,23,28,36,28,12,0,0,0,0,0,0,0,0,0,0,7,31,55,76,100,108,100,92,84,68,63,95,140,164,175,212,236,164,95,132,220,175,156,188,108,92,124,212,236,204,183,188,188,180,156,124,95,76,55,31,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,20,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,68,84,92,76,68,63,55,47,52,87,143,156,148,180,220,204,116,60,132,212,148,148,180,132,84,63,143,220,220,188,151,164,180,172,135,108,84,68,52,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,47,60,71,76,60,52,47,47,44,36,39,87,148,151,132,143,183,212,156,63,31,124,180,103,127,156,140,84,52,63,164,220,204,143,108,116,156,167,148,108,76,52,39,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,60,39,28,31,36,36,36,20,31,92,156,148,116,119,156,180,172,108,23,28,127,156,60,95,140,127,92,68,20,79,172,207,164,111,71,76,124,156,156,124,76,36,23,28,28,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,39,44,44,31,20,15,12,20,23,28,20,12,31,95,156,140,95,100,140,151,172,140,63,0,28,116,140,44,68,132,108,100,84,31,20,100,180,196,140,92,60,55,92,140,156,140,103,52,20,12,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,36,36,20,0,0,0,7,7,15,20,12,0,36,100,148,135,76,84,124,132,148,156,100,20,0,31,100,127,31,52,119,108,100,79,60,0,31,116,183,180,124,84,52,39,68,108,140,143,116,76,28,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,28,31,28,15,0,0,0,0,0,0,7,0,0,0,39,103,148,132,68,68,108,127,116,148,124,60,0,0,36,87,116,28,44,95,116,84,76,76,23,0,44,132,180,156,103,79,39,28,44,79,116,132,124,92,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,28,20,12,0,0,0,0,0,0,0,0,0,0,0,44,108,148,124,55,52,95,119,108,124,135,92,20,0,0,44,84,108,20,28,63,116,71,68,76,55,0,0,60,140,164,124,92,76,36,20,28,60,84,108,116,100,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,47,108,140,116,52,36,84,108,103,92,132,116,60,0,0,0,52,84,92,15,12,44,108,68,52,76,71,20,0,12,68,148,156,108,68,68,39,12,20,39,60,84,100,100,76,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,111,132,108,44,20,60,100,100,79,108,124,92,20,0,0,0,60,84,79,12,0,36,92,76,55,55,76,47,0,0,20,84,148,132,76,55,68,39,12,12,28,44,60,76,84,76,60,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,55,108,124,100,36,7,31,79,87,76,79,124,116,60,0,0,0,0,60,84,68,0,0,28,60,76,63,28,71,68,12,0,0,28,92,132,95,52,44,60,36,12,0,20,36,39,52,76,79,63,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,111,87,36,0,15,55,68,68,60,100,119,95,20,0,0,0,0,60,87,55,0,0,20,31,84,63,20,60,68,39,0,0,0,28,92,111,76,39,36,60,36,12,0,12,20,28,36,55,68,68,52,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,108,76,28,0,7,44,63,60,60,68,111,116,60,0,0,0,0,0,55,76,31,0,0,12,20,76,60,36,28,68,60,7,0,0,0,36,92,103,63,31,36,55,36,12,0,0,12,20,28,36,52,63,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,92,68,28,0,0,31,60,52,52,52,84,116,92,20,0,0,0,0,0,52,60,7,0,0,0,12,52,60,52,0,60,68,31,0,0,0,7,44,92,95,52,23,31,52,36,12,0,0,0,12,12,20,39,52,52,39,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,79,76,60,20,0,0,20,52,52,44,52,60,100,108,55,0,0,0,0,0,12,52,52,0,0,0,0,12,28,60,60,0,31,63,55,0,0,0,0,12,52,92,92,44,20,28,47,31,12,0,0,0,0,0,12,20,36,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,63,60,52,20,0,0,12,44,52,39,44,47,71,108,92,20,0,0,0,0,0,23,52,52,0,0,0,0,0,12,60,60,23,0,52,60,23,0,0,0,0,20,55,87,79,36,12,23,44,36,12,0,0,0,0,0,0,7,20,28,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,47,36,20,0,0,0,36,52,36,36,44,44,84,100,52,0,0,0,0,0,0,36,52,52,0,0,0,0,0,0,52,55,44,0,28,52,39,0,0,0,0,0,20,60,79,68,28,7,20,44,31,12,0,0,0,0,0,0,0,0,20,15,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,36,20,0,0,0,28,52,36,28,39,36,60,95,76,15,0,0,0,0,0,0,44,47,44,0,0,0,0,0,0,28,52,52,0,0,39,44,15,0,0,0,0,0,28,63,76,60,23,0,20,36,28,12,0,0,0,0,0,0,0,0,0,12,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,20,20,15,0,0,0,20,44,44,20,31,36,36,76,92,44,0,0,0,0,0,0,0,44,44,36,0,0,0,0,0,0,7,52,52,12,0,20,36,28,0,0,0,0,0,0,28,63,68,47,20,0,15,28,28,12,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,12,36,44,20,20,36,28,44,84,68,15,0,0,0,0,0,0,0,44,44,28,0,0,0,0,0,0,0,47,52,28,0,0,36,36,12,0,0,0,0,0,12,31,60,63,39,15,0,12,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,28,44,23,12,28,28,28,68,79,39,0,0,0,0,0,0,0,0,36,36,12,0,0,0,0,0,0,0,31,47,44,0,0,20,31,23,0,0,0,0,0,0,12,36,60,55,36,12,0,12,28,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,20,39,28,7,20,28,20,36,76,60,12,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,12,44,44,0,0,0,28,28,7,0,0,0,0,0,0,15,28,44,47,28,7,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,12,0,0,0,0,0,0,0,12,36,31,12,12,28,20,15,52,68,36,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,44,44,15,0,0,20,28,20,0,0,0,0,0,0,0,12,28,44,44,23,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,7,28,36,12,0,15,20,12,31,68,52,12,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,36,44,36,0,0,0,23,23,0,0,0,0,0,0,0,0,20,31,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,20,0,0,12,0,12,52,60,31,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,20,44,44,0,0,0,15,20,12,0,0,0,0,0,0,0,0,12,28,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,0,12,12,0,28,60,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,39,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,12,23,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,12,12,0,12,44,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,20,0,0,0,12,15,7,0,0,0,0,0,0,0,0,7,12,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,7,0,0,23,47,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,31,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,7,15,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,7,31,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,36,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,15,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_5[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,15,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,20,20,20,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,20,20,0,0,0,0,23,23,7,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,15,12,7,0,0,0,0,0,0,7,36,36,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,28,28,0,0,0,23,36,36,0,12,12,0,0,0,0,0,20,20,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,44,44,0,0,0,36,36,28,0,12,12,0,0,0,0,15,28,20,0,0,0,0,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,12,23,15,15,0,39,39,0,0,0,39,39,20,12,12,12,0,0,0,0,28,28,7,0,0,0,20,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,15,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,7,20,44,28,28,0,44,44,0,0,0,44,44,0,12,12,0,0,0,0,20,28,20,0,0,0,15,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,28,44,36,12,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,12,28,31,31,0,44,44,0,0,12,44,47,0,12,12,0,0,0,7,31,36,7,0,0,12,36,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,47,31,12,0,0,12,28,20,0,0,0,0,0,0,0,0,0,15,20,36,36,0,52,52,0,0,31,52,52,20,20,15,0,0,0,23,36,23,0,0,0,28,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,52,28,0,0,0,23,28,12,0,0,0,0,0,0,0,0,23,28,39,28,0,52,52,0,0,44,60,47,28,23,0,0,0,12,36,36,12,0,0,23,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,52,20,0,0,12,28,23,0,0,0,0,0,0,0,0,23,23,47,28,0,52,52,0,0,60,76,55,31,31,0,0,0,28,44,28,0,0,20,44,39,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,20,52,60,52,20,0,0,28,36,15,0,0,0,0,0,0,0,23,28,68,39,0,52,52,0,0,76,84,63,36,31,0,0,12,44,44,12,0,12,39,52,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,0,7,23,60,68,44,12,0,15,36,31,0,0,0,0,0,0,0,20,28,76,44,12,55,55,0,20,92,92,60,36,20,0,0,36,44,28,0,0,36,52,44,31,28,12,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,0,0,0,0,0,0,15,20,15,31,68,71,36,7,0,28,36,20,0,0,0,0,0,0,12,36,84,44,23,60,60,0,44,92,92,52,39,0,0,15,52,47,12,0,28,60,60,47,36,12,12,20,12,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,12,23,28,20,0,0,0,0,15,31,23,23,44,79,76,28,0,15,44,39,7,0,0,0,0,0,0,39,92,47,36,55,52,0,76,108,100,44,39,0,0,36,52,31,0,20,52,71,63,47,20,15,31,31,12,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,12,31,44,31,12,0,0,0,20,39,28,28,60,87,68,23,0,31,44,28,0,0,0,0,0,0,44,92,55,44,55,52,20,108,119,100,44,28,0,20,52,52,12,7,44,76,79,60,36,20,36,44,20,0,0,0,0,0,7,20,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,15,0,0,0,12,36,55,44,20,0,0,0,28,44,31,36,76,95,60,15,12,44,44,12,0,0,0,0,0,44,92,71,52,60,52,36,124,132,95,44,12,0,44,60,36,0,36,76,92,76,39,28,44,47,20,0,0,0,0,0,15,28,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,23,12,0,0,12,36,60,60,31,0,0,0,28,44,36,52,92,100,47,7,36,52,36,0,0,0,0,0,44,87,87,63,63,52,60,135,148,76,47,0,20,60,55,12,28,76,108,100,60,39,52,63,31,0,0,0,0,7,23,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,12,0,0,31,60,68,44,12,0,7,28,52,52,68,108,95,36,20,52,55,36,12,0,0,0,44,84,103,71,63,47,79,140,148,60,39,0,47,60,36,15,60,111,119,84,60,63,84,47,12,0,0,0,15,36,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,31,36,23,12,0,23,52,71,52,20,0,12,39,68,68,87,116,92,28,36,55,63,28,12,0,0,36,76,108,76,60,52,100,140,140,55,20,23,68,60,20,52,108,132,108,84,84,92,60,20,0,0,0,28,44,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,20,0,15,47,76,60,28,0,12,47,76,84,111,132,87,31,52,71,52,28,0,0,20,76,116,84,68,63,116,156,119,55,7,52,68,47,44,108,143,132,100,92,92,60,20,0,0,20,36,52,44,20,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,36,20,12,44,71,71,44,12,15,55,92,100,135,132,68,44,63,84,47,28,0,7,84,132,108,71,84,127,172,100,52,28,68,68,60,111,164,159,124,100,100,52,12,0,0,28,52,52,36,12,0,0,0,0,0,0,0,12,20,12,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,36,28,36,68,76,52,20,20,63,100,119,148,124,60,60,84,79,44,12,0,76,140,124,68,100,132,180,84,36,52,68,68,100,172,188,156,124,116,71,20,0,15,44,60,52,28,0,0,0,0,0,12,20,28,36,28,23,23,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,52,52,39,44,68,84,63,28,28,68,108,140,156,108,68,76,108,68,31,0,68,140,164,92,116,148,164,68,44,68,84,100,180,212,180,156,140,95,36,12,28,52,60,44,20,0,0,0,12,20,28,44,44,36,39,44,36,23,20,28,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,55,63,60,60,68,92,76,44,36,71,119,156,148,100,79,100,108,60,12,60,140,199,116,132,172,148,68,60,84,108,164,223,212,180,156,108,44,23,44,63,60,36,12,0,0,15,28,44,55,52,47,52,55,44,36,44,44,28,20,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,63,76,76,92,95,87,52,52,76,132,164,148,103,100,140,108,47,52,140,228,143,148,196,132,79,76,116,156,223,244,220,172,116,52,39,60,68,52,28,0,7,20,39,60,71,68,68,68,63,52,55,60,52,36,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,84,100,108,111,103,68,60,84,148,180,140,111,135,148,84,52,140,236,164,167,196,124,92,108,151,207,252,244,204,124,68,60,68,68,44,15,7,23,52,71,84,84,84,84,76,71,76,68,52,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,103,124,132,124,87,79,108,180,196,151,140,175,127,68,127,228,180,183,196,140,116,156,196,244,247,212,143,92,79,84,68,36,20,36,68,84,100,103,108,100,95,92,84,71,52,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,63,100,140,159,148,111,95,135,196,196,164,183,164,92,119,220,196,191,204,167,164,196,231,247,212,156,108,100,92,60,39,44,84,108,124,132,132,124,124,116,100,76,47,36,20,0,0,0,0,0,0,0,0,12,15,20,20,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,39,92,132,172,175,148,124,164,204,196,188,196,127,127,204,228,220,228,204,212,223,247,212,164,124,103,84,68,68,100,132,156,167,180,167,159,140,116,84,60,36,7,0,0,0,0,15,28,36,36,39,44,47,39,31,28,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,12,20,23,28,44,76,116,164,196,180,159,183,204,212,212,159,156,191,244,239,244,236,239,239,220,180,140,108,95,92,111,151,188,204,212,188,172,143,119,87,60,28,7,0,20,36,60,68,79,84,76,60,52,52,47,47,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,15,12,20,12,12,15,23,36,47,68,92,119,156,196,199,188,204,220,236,204,183,196,252,252,252,252,247,228,191,148,124,124,132,164,207,236,223,196,164,140,108,71,52,36,44,60,79,92,100,100,100,103,100,95,84,60,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,15,12,20,23,36,36,44,52,55,60,76,100,127,164,191,204,212,228,244,236,220,220,252,252,252,252,244,212,175,156,159,172,212,231,215,180,148,124,108,92,79,84,92,116,124,132,140,148,140,119,108,92,60,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,36,36,44,44,52,76,108,132,140,156,180,212,223,236,247,252,244,244,252,252,252,252,244,220,196,196,212,212,196,180,164,148,132,124,127,143,164,175,180,183,175,159,135,116,84,39,23,28,20,7,0,0,0,0,0,0,0,12,12,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,52,63,92,143,188,204,215,236,247,252,252,252,252,252,252,252,252,247,236,228,236,228,207,196,180,167,172,188,204,215,228,236,223,199,172,132,116,116,108,84,52,44,52,44,44,36,28,12,0,20,28,28,23,20,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,55,76,108,140,172,196,223,244,252,252,252,252,252,252,252,252,252,252,244,228,212,212,228,244,247,244,236,215,204,196,180,159,124,87,68,79,76,60,52,44,47,44,39,36,28,12,0,20,28,28,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,132,167,212,244,252,252,252,252,252,252,252,252,252,252,252,244,239,231,228,220,204,196,183,172,156,148,135,116,100,92,92,87,84,79,68,52,36,28,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,39,60,76,92,116,143,172,180,196,220,244,252,252,252,252,252,239,228,223,239,252,244,220,183,151,132,108,92,76,68,60,52,39,36,36,36,36,36,36,36,31,28,20,12,12,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,76,92,108,124,140,159,175,191,212,236,252,252,252,252,252,252,252,252,252,252,239,215,188,164,164,180,172,156,132,108,87,84,84,76,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,79,92,100,116,132,151,164,180,191,220,236,252,252,247,236,231,236,244,252,252,252,252,252,252,252,252,244,212,172,148,127,103,92,103,116,116,116,111,100,87,84,76,71,47,44,44,28,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,23,52,60,68,92,100,100,108,132,148,156,172,180,188,196,212,212,231,244,236,212,199,188,188,204,231,239,236,236,252,252,252,252,252,247,236,204,164,132,108,71,44,36,36,36,36,36,47,60,63,68,47,44,44,28,20,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,36,47,55,63,84,84,92,127,148,143,140,124,124,132,140,140,140,148,172,191,199,180,172,159,140,132,156,188,204,204,204,228,252,252,244,236,236,247,223,196,180,164,140,119,84,36,7,0,12,12,15,12,0,0,0,0,12,12,15,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,28,36,36,39,44,55,76,92,108,103,87,79,71,76,92,95,100,92,84,100,127,148,148,132,127,124,108,92,100,124,151,180,172,156,188,228,244,236,236,212,212,236,228,196,172,156,140,124,111,95,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,15,20,28,36,44,60,60,55,52,44,36,52,68,76,68,60,52,47,63,84,100,103,95,87,87,84,76,60,68,76,95,124,148,148,124,151,212,223,223,220,228,196,188,207,239,207,172,156,132,108,92,92,92,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,23,20,20,28,36,44,52,44,28,28,31,36,39,52,60,68,68,68,68,68,60,52,44,52,44,52,76,108,124,124,100,116,180,220,204,204,196,204,188,148,159,228,228,188,143,127,119,92,71,68,76,76,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,20,12,15,15,23,20,20,28,23,28,44,55,55,60,55,47,36,36,36,39,28,20,28,63,84,100,111,84,76,127,212,196,180,196,188,180,196,119,111,196,223,196,156,100,87,92,84,52,47,60,76,76,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,12,36,47,52,52,52,44,28,20,20,28,31,23,12,0,28,52,68,79,100,84,55,84,172,220,164,164,204,175,164,212,124,76,148,199,188,164,132,68,55,76,92,60,31,36,60,71,68,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,47,44,28,12,0,12,20,23,20,7,0,0,23,44,47,55,76,84,44,52,124,196,204,140,148,223,164,124,196,124,60,100,180,180,156,143,108,52,36,68,84,63,28,12,36,60,68,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,44,44,36,15,0,0,0,0,12,12,0,0,0,0,28,44,39,36,52,68,44,36,84,148,199,172,124,140,231,156,84,164,116,68,52,148,188,148,140,132,92,44,20,47,76,68,36,7,12,36,60,63,60,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,31,36,36,36,20,0,0,0,0,0,0,0,0,0,0,0,7,23,39,28,28,36,52,28,12,60,108,156,188,132,103,143,228,143,55,119,108,87,20,100,172,164,119,124,124,76,28,0,31,63,71,44,15,0,12,39,60,60,55,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,28,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,20,20,31,47,28,0,36,84,124,159,164,95,92,151,212,140,52,92,111,100,12,47,132,167,132,100,111,111,68,23,0,20,52,68,52,20,0,0,15,44,60,55,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,23,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,15,12,28,44,28,0,20,68,100,116,172,140,68,95,164,188,132,44,68,116,100,31,12,84,148,132,100,92,103,100,60,20,0,12,44,68,60,28,0,0,0,20,44,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,12,0,20,39,28,0,0,44,76,100,124,156,108,52,100,172,172,124,44,47,108,100,52,0,36,95,132,95,84,84,95,87,52,12,0,0,31,60,60,36,12,0,0,0,20,44,52,44,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,15,31,20,0,0,28,68,84,92,148,135,68,52,100,180,164,116,36,36,92,84,55,0,12,63,108,103,79,68,84,84,76,44,0,0,0,20,47,60,44,15,0,0,0,0,20,39,39,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,12,52,71,76,100,140,108,36,68,100,180,159,111,20,20,60,76,68,0,0,36,76,108,76,68,63,76,68,63,31,0,0,0,12,36,55,44,20,0,0,0,0,0,20,31,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,36,60,71,68,116,124,76,12,84,108,151,148,92,12,12,39,68,68,12,0,12,52,84,84,68,55,60,60,52,52,23,0,0,0,0,28,52,52,28,0,0,0,0,0,0,20,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,60,60,79,116,100,44,12,92,111,127,140,76,12,15,28,52,52,12,0,0,28,52,79,68,55,47,60,44,39,44,20,0,0,0,0,20,44,52,28,12,0,0,0,0,0,0,20,23,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,55,52,47,92,108,71,20,15,79,108,108,127,68,15,28,28,44,47,15,0,0,7,44,63,76,60,44,52,52,36,36,36,12,0,0,0,0,12,31,44,36,12,0,0,0,0,0,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,52,44,60,92,92,44,0,31,76,108,100,124,68,0,20,20,28,31,20,0,0,0,28,44,68,60,47,36,52,39,28,31,28,7,0,0,0,0,0,28,44,36,20,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,52,36,36,76,87,71,28,0,44,68,108,95,116,68,0,0,0,20,28,28,0,0,0,7,44,52,60,55,36,31,47,28,20,20,7,0,0,0,0,0,0,20,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,36,28,44,71,87,44,7,0,52,63,100,100,108,63,0,0,0,7,20,20,0,0,0,0,28,39,52,52,52,23,36,44,20,0,12,7,0,0,0,0,0,0,12,28,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,44,28,28,60,71,68,28,0,0,44,47,84,108,92,60,0,0,0,0,20,20,0,0,0,0,7,36,39,52,52,36,15,36,36,12,7,20,12,0,0,0,0,0,0,0,20,31,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,44,28,20,36,60,76,44,15,0,12,47,44,63,108,76,52,0,0,0,0,20,20,0,0,0,0,0,20,36,39,44,47,20,20,36,28,12,12,15,0,0,0,0,0,0,0,0,12,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,28,15,20,44,52,60,20,0,0,7,31,31,52,108,68,44,0,0,0,0,12,12,0,0,0,0,0,0,31,31,36,47,36,7,20,36,20,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,15,20,23,52,55,36,12,0,0,12,28,36,44,108,60,36,0,0,0,0,0,12,12,0,0,0,0,0,20,28,28,36,44,20,0,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,7,12,31,44,52,15,0,0,0,7,20,36,44,103,60,28,0,0,0,0,0,7,7,0,0,0,0,0,0,28,28,28,44,36,7,12,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,28,0,12,12,39,44,36,12,0,0,0,12,12,39,39,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,20,28,39,28,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,20,36,44,12,0,0,0,0,12,12,44,36,95,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,36,36,12,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,20,0,0,0,28,36,28,0,0,0,0,0,0,0,39,36,92,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,20,36,28,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,23,0,0,0,7,31,36,12,0,0,0,0,0,0,0,36,44,76,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,12,28,36,12,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,20,28,28,0,0,0,0,0,0,0,0,28,39,68,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,12,28,28,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,15,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,15,36,55,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,12,39,52,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,7,28,60,52,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,12,20,60,47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,7,52,47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,52,47,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,12,12,55,44,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,12,12,52,44,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_6[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,23,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,44,0,0,0,0,0,0,0,7,12,7,0,7,7,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,44,0,0,0,0,0,0,0,12,12,0,0,7,7,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,36,0,0,0,0,0,0,0,12,12,0,12,12,7,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,0,0,12,12,0,0,0,12,12,0,12,12,0,0,0,0,20,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,47,20,0,28,28,0,0,12,20,20,0,20,20,0,0,0,12,23,20,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,76,44,0,44,39,7,0,20,20,20,20,28,23,0,0,0,23,28,12,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,68,84,60,0,39,36,0,0,23,23,15,20,20,12,0,0,12,28,28,0,0,0,12,12,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,60,76,63,0,36,28,0,0,28,28,20,28,28,0,0,0,28,31,15,0,0,15,20,7,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,52,76,68,12,44,28,0,0,28,28,28,36,28,0,0,12,36,36,0,0,12,23,15,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,7,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,44,84,76,20,52,36,0,12,31,28,44,44,28,0,0,28,36,20,0,7,28,28,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,28,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,39,92,92,20,68,44,12,31,44,44,47,47,12,0,12,36,36,0,0,23,31,15,0,0,0,0,0,0,0,20,28,12,0,0,0,0,7,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,36,95,95,28,79,60,20,44,47,55,52,52,0,0,31,44,28,0,20,36,28,0,0,0,0,0,0,0,20,31,15,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,44,23,0,0,0,0,0,0,0,0,0,0,31,31,12,0,28,100,100,44,84,60,20,60,60,63,52,44,0,12,44,44,12,12,36,36,12,0,0,0,0,0,12,28,36,20,0,0,0,0,20,23,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,44,20,0,0,0,0,0,0,0,0,0,28,36,28,0,15,100,100,60,87,60,23,60,63,60,52,23,0,36,47,36,0,28,39,20,0,0,0,0,0,12,31,39,20,0,0,0,12,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,44,20,0,0,0,0,0,0,0,0,12,36,36,0,7,100,100,68,84,52,36,68,79,60,55,0,12,47,47,12,20,44,36,0,0,0,0,0,12,36,44,23,0,0,0,20,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,23,52,44,20,0,0,0,0,0,0,0,0,39,39,12,0,95,100,84,84,52,52,68,100,60,55,0,36,52,36,12,39,44,20,0,0,0,0,12,36,44,23,0,0,12,28,39,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,0,0,0,0,0,28,60,44,15,0,0,0,0,0,0,0,36,44,28,0,87,100,95,95,60,68,76,111,71,44,12,52,55,20,31,52,28,0,0,0,0,15,36,44,20,0,0,20,36,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,36,68,44,20,0,0,0,0,0,0,23,44,44,0,79,100,111,111,68,68,92,116,84,36,36,60,44,28,52,44,12,0,0,0,20,44,44,20,0,7,28,44,52,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,12,0,0,0,0,0,0,12,44,68,55,28,7,0,0,0,0,7,52,52,0,68,100,124,132,100,76,119,124,92,28,55,60,36,47,55,23,0,0,0,28,47,52,28,0,15,36,60,52,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,20,31,36,20,7,0,0,0,0,0,20,52,79,63,28,0,0,0,0,0,52,55,28,60,100,132,124,108,84,143,124,87,52,60,52,44,60,39,0,0,0,28,52,52,28,0,28,52,68,60,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,12,0,0,0,0,0,12,28,36,36,15,0,0,0,0,0,23,68,87,68,23,0,0,0,0,47,63,52,47,100,143,124,124,108,188,135,84,63,68,52,60,55,20,12,12,28,55,60,28,12,36,68,76,63,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,23,15,0,0,0,0,7,28,44,44,28,7,0,0,0,0,31,76,92,68,20,0,0,0,36,76,71,44,100,151,124,135,135,204,132,84,68,71,60,63,31,12,28,52,68,60,31,23,52,84,84,60,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,31,20,7,0,0,0,28,52,55,36,20,7,0,0,0,39,92,100,60,12,0,0,15,84,87,60,100,156,124,148,175,212,127,84,71,76,71,52,28,36,68,79,68,36,36,68,92,84,55,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,31,36,36,28,12,0,0,28,52,68,55,31,7,0,12,20,52,108,108,52,7,0,0,79,100,84,108,156,124,164,199,188,132,79,92,76,76,47,52,76,84,63,52,52,92,108,84,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,39,31,20,12,23,52,76,76,44,28,20,28,31,68,124,111,47,0,0,60,100,108,116,159,140,180,220,172,127,92,100,87,76,60,92,95,71,60,76,116,116,76,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,39,44,47,39,28,20,52,84,92,71,52,44,36,44,87,140,111,36,0,28,95,124,140,175,167,196,220,164,116,116,108,108,87,108,108,84,76,103,132,116,68,23,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,52,52,47,44,47,76,100,92,76,60,52,63,116,148,100,23,0,84,140,180,199,196,212,204,164,116,135,124,124,135,132,108,100,127,143,108,55,20,12,15,7,0,12,12,12,12,0,0,0,0,7,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,52,60,60,60,76,103,119,108,79,68,84,140,148,79,12,63,140,212,228,228,223,204,164,151,151,164,164,167,148,135,140,140,92,44,23,20,20,28,31,31,23,20,12,12,20,28,20,20,15,7,12,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,60,68,76,92,116,135,132,108,92,116,164,140,60,44,127,220,244,244,236,212,180,191,196,207,196,188,172,151,124,84,47,36,36,47,52,44,36,28,36,39,39,36,28,28,20,20,20,15,20,12,20,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,15,20,7,0,0,0,0,0,0,31,60,76,84,108,132,143,148,140,140,164,191,132,60,108,207,252,252,244,231,220,228,244,239,223,188,151,116,76,55,60,76,79,68,60,68,71,60,44,36,36,39,52,55,60,60,55,44,44,36,31,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,23,28,36,44,52,52,44,28,12,0,0,12,44,76,100,116,148,164,167,172,196,220,204,116,119,188,252,252,252,247,244,244,252,236,196,156,124,92,87,111,124,116,116,116,92,68,60,68,84,95,100,95,92,84,84,79,60,44,39,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,60,63,76,79,92,84,68,44,28,28,60,92,124,159,191,204,212,236,244,191,172,196,252,252,252,252,252,252,236,212,175,148,140,156,172,175,172,151,140,127,132,132,132,119,103,100,95,95,92,84,76,55,31,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,0,12,20,20,12,0,0,0,0,0,12,28,44,68,76,92,92,95,95,95,92,87,87,108,124,148,188,228,247,252,236,220,223,252,252,252,252,252,247,231,204,188,196,207,220,228,228,212,188,172,148,124,108,100,100,95,84,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,20,0,0,12,28,44,44,28,31,44,52,44,44,36,36,44,44,47,47,47,52,52,68,84,100,103,103,116,116,116,127,148,164,183,204,231,247,252,244,244,252,252,252,252,252,247,236,231,236,244,244,231,212,180,143,119,108,103,92,68,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,15,0,0,0,12,36,44,39,47,68,76,79,84,79,92,124,140,135,132,140,143,140,132,124,119,119,132,164,175,196,212,212,196,191,207,231,247,252,252,252,252,252,252,252,252,252,252,236,220,188,164,140,116,100,84,68,47,28,20,15,15,15,15,15,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,20,31,36,36,36,39,39,44,44,63,92,116,124,132,151,164,164,164,156,156,151,148,151,164,204,231,252,252,252,244,244,247,252,252,252,252,252,252,252,252,252,252,228,191,156,124,92,71,60,60,60,52,47,44,44,36,36,28,23,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,20,44,76,87,71,76,100,119,132,156,172,180,183,199,220,236,244,247,247,252,252,252,252,252,252,252,252,252,236,212,164,124,84,60,52,47,44,36,28,28,20,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,20,47,60,39,44,60,84,108,132,148,164,180,199,204,196,191,207,236,252,252,252,252,252,252,252,252,252,252,236,196,156,108,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,12,20,31,44,60,79,100,124,148,167,180,172,164,148,148,164,204,228,244,244,252,252,252,247,228,223,236,252,252,239,220,183,148,108,76,60,52,47,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,71,92,108,140,172,191,204,191,167,135,108,92,92,116,164,220,220,220,236,252,244,244,247,220,188,180,212,236,228,215,204,204,188,164,135,100,71,52,44,44,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,60,68,84,108,140,180,204,204,188,156,132,100,68,44,47,68,108,164,212,199,180,196,244,252,228,228,252,231,175,124,132,167,191,188,188,188,188,175,151,116,103,103,92,68,44,36,36,23,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,28,60,100,132,164,175,172,156,143,116,92,60,28,7,20,47,76,108,156,204,196,148,151,207,252,252,196,199,244,236,196,119,71,76,116,140,143,140,148,148,148,143,132,100,68,60,68,71,60,36,20,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,84,108,124,116,116,116,108,84,55,23,0,0,0,31,60,76,108,148,196,204,140,108,164,236,247,236,164,172,212,231,196,156,79,36,36,76,108,124,111,100,108,103,87,92,108,103,76,52,47,44,44,36,23,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,71,84,87,92,87,76,60,36,12,0,0,0,0,20,44,60,71,92,143,204,212,148,76,108,188,231,228,220,148,148,172,220,196,172,124,60,12,15,47,76,100,103,84,68,84,87,76,68,76,92,84,60,44,39,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,36,55,68,71,76,68,55,39,23,0,0,0,0,0,0,12,28,52,55,60,79,140,212,220,148,60,68,127,188,212,204,204,148,119,148,196,191,172,148,100,52,7,0,28,60,76,84,84,60,52,60,68,68,60,60,68,68,60,44,36,36,31,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,39,36,44,60,47,36,28,15,0,0,0,0,0,0,0,0,20,39,47,47,44,63,132,204,223,156,63,36,95,148,156,196,183,188,156,95,116,180,172,164,159,116,87,44,0,0,7,36,60,68,76,63,44,36,44,52,60,55,52,52,52,47,39,31,28,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,28,28,36,20,20,20,12,0,0,0,0,0,0,0,0,0,12,28,39,44,31,36,60,124,188,212,164,68,15,60,116,140,124,188,175,172,167,87,79,148,156,156,148,132,95,76,36,0,0,0,20,44,60,60,55,44,36,31,28,28,39,47,47,44,44,36,28,23,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,15,31,36,36,20,23,60,111,164,196,164,76,12,28,92,111,100,119,183,172,159,172,92,47,111,148,124,132,135,95,84,71,28,0,0,0,0,28,52,55,52,44,31,28,23,20,20,28,39,44,44,44,36,23,12,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,31,20,12,20,63,100,143,172,156,79,20,0,60,92,84,60,124,188,164,140,180,100,20,84,148,108,116,127,108,76,76,63,23,0,0,0,0,12,36,52,52,36,28,20,20,20,12,0,12,28,39,39,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,20,12,0,20,60,92,132,156,143,79,20,0,28,76,76,44,44,132,188,140,124,183,108,12,68,116,116,100,100,124,79,60,76,55,20,0,0,0,0,0,20,36,47,44,28,15,12,12,12,0,0,0,15,31,36,36,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,0,0,20,60,84,116,140,140,84,23,0,0,60,76,44,28,52,127,183,111,103,188,116,12,44,84,132,84,79,108,103,52,52,76,47,12,0,0,0,0,0,0,20,39,44,31,15,0,7,0,0,0,0,0,0,20,31,31,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,7,12,44,68,95,124,132,84,28,0,0,28,68,60,12,20,68,127,183,92,87,183,116,20,15,68,124,84,76,76,108,76,39,47,71,44,7,0,0,0,0,0,0,12,28,36,36,23,7,0,0,0,0,0,0,0,0,12,20,28,28,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,55,79,116,119,84,28,0,0,0,55,68,36,0,12,79,132,167,76,76,180,108,31,0,60,87,108,68,55,84,95,52,31,47,68,36,0,0,0,0,0,0,0,0,15,28,36,28,12,0,0,0,0,0,0,0,0,0,0,12,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,55,71,100,108,84,31,0,0,0,28,63,55,0,0,7,92,135,140,60,68,167,100,39,0,39,68,108,68,52,60,92,76,36,28,52,60,28,0,0,0,0,0,0,0,0,0,20,28,28,20,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,60,92,103,84,36,0,0,0,7,52,60,28,0,0,15,92,135,108,60,68,159,92,47,0,12,60,92,76,60,36,68,84,52,20,20,52,55,23,0,0,0,0,0,0,0,0,0,7,20,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,63,92,87,36,0,0,0,0,31,60,52,0,0,0,28,95,140,84,55,68,156,92,52,0,0,55,68,92,63,36,44,76,71,36,12,23,52,52,20,0,0,0,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,31,68,84,36,0,0,0,0,12,52,60,23,0,0,0,52,84,132,63,44,60,140,95,55,0,0,36,60,87,60,52,20,55,76,52,23,0,28,52,44,12,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,20,52,76,39,0,0,0,0,0,36,55,44,0,0,0,0,60,76,108,52,28,44,103,84,55,0,0,12,55,68,68,60,20,36,60,60,28,12,0,28,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,15,15,28,52,36,0,0,0,0,0,12,52,52,20,0,0,0,0,68,68,68,44,12,36,68,60,52,0,0,0,52,55,68,55,44,12,47,60,36,12,0,0,28,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,15,36,47,20,7,0,0,0,0,0,36,52,36,0,0,0,0,20,63,68,52,39,0,36,47,52,52,0,0,0,36,52,60,55,52,12,28,52,52,23,12,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,36,0,0,0,0,0,0,12,47,47,12,0,0,0,0,36,60,71,44,36,0,36,39,52,52,0,0,0,12,47,52,52,52,31,0,39,52,36,7,0,0,7,28,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,28,7,0,0,0,0,0,0,31,44,28,0,0,0,0,0,52,60,68,36,36,0,36,44,52,47,0,0,0,0,44,47,47,52,47,0,20,44,47,20,7,0,0,12,28,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,28,0,0,0,0,0,0,0,12,44,44,12,0,0,0,0,0,52,55,44,28,23,0,36,52,60,44,12,0,0,0,31,44,44,44,52,23,0,28,44,36,0,0,0,0,12,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,0,31,44,28,0,0,0,0,0,7,52,52,28,20,20,0,28,52,71,44,20,0,0,0,12,44,44,31,47,44,0,12,39,44,15,0,0,0,0,12,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,36,0,0,0,0,0,0,28,52,52,28,28,15,0,12,36,68,44,28,0,0,0,0,39,44,28,44,44,15,0,20,39,31,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,0,0,0,0,0,0,44,52,44,20,20,0,0,0,15,52,31,28,0,0,0,0,28,39,36,28,44,31,0,0,28,36,20,0,0,0,0,0,0,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,28,0,0,0,0,0,0,0,47,52,28,12,12,0,0,0,12,44,31,28,0,0,0,0,7,36,36,12,44,39,7,0,12,36,31,0,0,0,0,0,0,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,12,0,0,0,0,0,0,0,47,47,12,12,12,0,0,0,7,31,28,28,0,0,0,0,0,36,36,15,31,36,23,0,0,20,31,20,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,12,47,47,0,12,12,0,0,0,0,28,36,36,0,0,0,0,0,23,36,28,12,36,36,0,0,7,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,0,31,44,44,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,7,31,31,0,31,36,15,0,0,15,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,44,44,31,0,0,0,0,0,0,0,0,23,23,0,0,0,0,0,0,28,28,12,15,36,28,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,7,0,0,0,0,0,0,0,0,44,44,12,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,20,28,23,0,31,31,12,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,28,28,0,20,28,20,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,20,39,39,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,23,23,12,0,28,28,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,31,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,15,20,20,0,20,28,15,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,15,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,20,20,0,7,23,23,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,31,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,20,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_7[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,12,12,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,7,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,12,15,7,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,12,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,7,15,15,0,0,0,0,0,20,20,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,47,28,0,0,0,0,0,0,0,0,0,0,36,36,20,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,12,28,20,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,44,12,0,0,0,0,0,0,0,0,0,36,36,36,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,31,28,12,0,0,0,0,12,23,20,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,60,31,0,0,0,0,0,0,0,0,0,31,39,39,0,0,0,0,0,0,0,0,20,20,12,0,0,0,20,36,28,0,0,0,0,0,23,28,12,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,52,15,0,0,0,0,0,0,0,0,20,44,44,0,0,0,0,0,0,0,0,28,23,0,0,0,12,36,36,20,0,0,0,0,20,28,20,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,68,36,0,0,0,0,0,0,0,0,7,44,44,0,0,0,0,0,0,0,15,28,28,7,7,0,20,47,36,7,0,0,0,12,31,28,12,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,28,68,60,15,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,23,31,28,7,7,12,36,52,31,0,0,0,0,28,36,20,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,15,12,0,0,0,0,0,0,12,55,76,44,0,0,0,0,0,0,0,0,47,47,12,0,0,0,0,0,0,44,44,36,12,12,12,52,44,20,0,0,0,20,36,28,20,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,7,12,7,0,0,0,0,0,0,31,76,68,20,0,0,0,0,0,0,0,47,47,28,0,0,0,0,0,7,60,60,28,12,12,36,60,44,0,0,0,12,36,36,28,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,7,0,0,15,20,0,0,0,0,0,12,63,92,55,0,0,0,0,0,0,0,47,52,44,0,0,0,0,0,23,63,68,20,15,23,60,63,28,0,0,0,28,44,36,28,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,20,36,20,0,0,0,0,0,36,92,84,23,0,0,0,0,0,0,39,52,52,0,0,0,0,0,52,76,84,20,23,36,76,55,12,0,0,20,44,44,36,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,7,20,28,12,0,0,0,0,12,68,100,60,0,0,0,0,0,0,28,52,52,0,0,0,0,0,68,84,84,28,39,60,79,44,0,0,7,39,44,44,39,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,7,20,28,20,7,0,0,0,36,92,92,28,0,0,0,0,0,12,55,55,0,0,0,0,0,79,84,71,31,44,84,71,23,0,0,28,52,52,44,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,15,15,36,39,28,12,0,0,12,76,111,76,0,0,0,0,0,0,60,60,0,0,0,0,12,84,100,60,44,60,92,60,0,0,20,52,60,52,52,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,20,20,44,39,28,15,7,0,36,108,108,36,0,0,0,0,0,60,60,20,0,0,0,31,84,119,52,60,84,92,36,0,0,44,60,60,52,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,39,23,28,47,44,28,12,0,7,84,119,76,0,0,0,0,0,60,60,36,0,0,0,52,92,132,52,79,100,79,20,0,31,60,68,60,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,44,28,36,52,44,36,20,0,36,108,108,36,0,0,0,0,55,60,47,0,0,0,68,108,127,76,92,108,60,12,28,60,76,71,76,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,44,36,44,60,60,39,20,7,76,119,84,12,12,12,0,47,63,60,0,0,0,84,132,116,108,111,108,44,23,60,71,84,87,76,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,23,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,44,52,68,63,39,15,31,108,111,39,15,15,12,36,68,63,0,0,12,87,156,108,132,124,92,31,52,76,92,100,100,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,31,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,60,52,60,76,71,36,20,76,116,84,28,28,20,20,68,68,0,0,28,95,164,111,140,124,76,44,79,100,124,124,84,28,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,47,68,63,71,84,76,31,36,103,108,52,28,28,12,68,68,12,0,44,116,164,140,132,116,60,76,100,124,140,124,44,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,44,44,28,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,52,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,76,76,84,92,71,36,71,116,87,44,36,20,68,68,23,0,68,148,167,164,124,103,68,103,132,156,148,76,12,0,0,0,0,0,0,0,0,0,0,0,28,44,47,44,28,12,0,0,0,0,0,7,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,63,68,60,36,12,0,0,0,0,0,0,0,0,0,12,15,36,60,84,84,100,100,68,52,103,111,71,36,36,68,71,39,0,84,172,180,164,132,92,108,132,172,156,92,23,0,0,0,0,0,0,0,7,7,12,28,47,52,52,36,15,0,0,0,0,7,20,28,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,60,71,76,76,52,20,0,0,0,0,0,0,0,7,12,20,36,68,87,92,116,108,63,84,116,100,60,44,76,76,52,0,103,180,196,148,132,103,140,172,180,124,39,0,0,0,0,0,0,12,20,20,36,52,60,52,39,20,0,0,0,0,20,28,28,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,63,84,92,87,68,28,0,0,0,0,0,0,0,12,28,52,76,100,111,135,116,84,108,108,92,52,92,84,68,20,124,191,199,148,140,143,180,196,156,71,7,0,0,0,0,12,28,39,60,68,63,60,47,23,0,0,0,20,36,36,36,28,28,20,7,0,0,0,0,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,71,92,95,92,76,44,12,0,0,0,0,0,20,39,63,84,116,135,156,124,108,116,124,71,100,92,76,44,140,215,196,164,156,188,212,180,108,28,0,0,0,12,28,52,76,87,84,68,52,28,0,0,20,36,44,39,36,36,28,12,0,0,0,12,20,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,92,95,100,84,52,20,0,0,0,0,20,44,76,100,132,164,172,132,132,124,108,116,119,92,60,164,236,199,191,204,228,207,140,44,0,0,0,28,60,95,116,108,79,60,31,7,12,36,47,44,44,44,36,20,0,0,20,36,36,31,23,20,20,20,20,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,84,100,100,92,68,28,0,0,0,20,44,84,108,148,180,172,148,132,148,135,159,108,79,180,236,212,220,244,231,164,68,7,0,20,60,116,148,140,100,71,36,23,36,52,52,52,47,44,31,20,20,36,44,39,36,36,36,36,36,23,23,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,95,100,95,76,39,12,0,15,44,92,127,180,204,180,164,164,164,183,124,100,204,239,236,236,236,180,84,15,12,47,108,156,164,140,92,55,44,55,68,71,63,52,52,44,44,44,44,44,44,44,52,63,63,47,36,28,15,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,92,100,100,84,52,23,28,60,100,148,212,212,199,180,196,212,140,124,220,244,244,236,188,92,28,36,87,140,172,156,116,84,79,87,100,92,92,92,84,63,55,52,52,63,76,84,79,60,44,36,36,36,31,28,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,28,60,92,100,100,95,84,76,84,124,180,231,228,220,223,236,159,151,236,252,244,196,108,52,68,124,167,172,156,127,111,108,116,132,148,132,100,84,84,92,103,108,95,76,55,44,44,44,39,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,20,23,36,36,36,36,39,36,23,12,0,0,0,0,0,0,15,52,84,100,116,132,132,135,164,204,236,244,244,252,188,188,247,247,207,135,87,108,164,204,212,183,156,148,156,172,175,159,140,132,124,124,111,92,68,52,52,47,44,36,20,0,0,0,0,0,0,12,12,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,36,36,36,36,39,44,44,47,52,52,52,52,36,20,7,0,12,44,84,116,140,164,183,204,228,244,252,252,220,220,252,223,172,135,151,204,236,231,220,212,220,220,212,180,156,140,124,108,79,63,60,55,47,36,28,28,36,39,39,36,36,28,12,12,20,28,20,7,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,47,52,52,55,60,60,60,60,68,68,68,63,84,119,164,196,215,231,244,252,252,244,244,247,220,188,196,231,252,252,244,236,220,196,175,164,151,132,124,116,108,92,68,60,52,52,52,47,44,44,44,39,36,36,28,12,12,20,28,20,7,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,60,60,60,68,68,68,76,87,108,140,188,228,252,252,252,252,252,252,247,236,236,247,252,252,252,244,228,196,175,156,127,108,84,68,60,60,60,55,52,52,52,52,47,44,44,39,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,63,71,76,100,132,175,215,239,252,252,252,252,252,252,252,244,228,207,188,159,127,100,84,71,68,68,68,60,60,52,39,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,44,52,63,76,92,100,111,124,124,124,119,116,132,183,228,252,252,252,252,252,252,252,244,223,196,156,116,68,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,47,52,52,55,60,68,84,100,124,140,140,140,140,135,132,132,124,124,132,151,180,220,244,252,252,252,252,252,252,252,247,236,199,156,127,108,95,92,87,76,52,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,28,36,36,39,44,44,44,47,60,71,87,100,108,111,116,119,124,132,135,124,108,100,84,68,60,68,92,124,156,196,236,252,252,252,252,252,252,252,236,220,212,199,175,148,119,100,92,92,92,92,92,87,79,63,44,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,7,12,20,28,31,28,28,36,44,60,76,84,84,92,92,92,84,76,68,63,55,55,55,52,44,28,12,0,0,36,76,119,164,204,236,239,239,247,252,252,252,252,252,252,236,212,180,172,180,167,132,100,76,68,71,84,92,87,87,87,84,84,84,76,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,15,20,7,12,28,36,44,44,44,52,44,44,36,36,36,39,44,44,44,36,28,12,0,0,0,0,0,0,12,44,84,127,159,191,207,220,212,212,228,247,252,252,252,244,244,247,244,228,188,148,140,172,196,180,132,87,52,23,15,31,52,68,84,84,84,84,60,60,44,44,36,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,12,12,0,0,12,12,12,20,20,20,23,36,36,28,15,0,0,0,0,0,0,0,0,0,0,0,20,52,84,124,156,180,183,180,172,164,172,204,236,252,252,244,244,220,220,236,231,236,228,180,116,100,127,180,196,172,124,84,55,28,0,0,0,12,28,47,44,52,44,44,39,36,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,84,116,148,156,156,148,140,132,124,132,172,220,244,247,252,220,220,196,196,228,207,212,236,223,180,108,68,84,124,164,180,156,111,76,60,36,12,0,0,0,0,0,0,7,20,23,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,68,84,108,132,132,116,116,108,108,103,100,100,156,204,228,231,247,252,188,188,172,172,220,196,180,196,220,212,188,108,52,44,84,124,148,156,140,100,71,55,39,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,68,84,100,124,116,84,84,84,79,84,84,71,84,140,204,220,212,220,244,244,167,167,156,148,199,207,164,156,183,196,199,180,119,52,20,39,84,116,132,127,116,87,68,52,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,68,76,95,108,95,68,60,63,63,68,71,68,52,68,124,199,215,188,188,204,220,223,148,148,156,119,167,228,164,135,143,156,156,180,180,132,60,12,12,44,84,108,111,100,92,76,60,52,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,55,68,84,92,76,52,44,44,52,52,60,52,47,36,52,116,196,220,180,159,172,180,188,196,119,124,159,92,124,215,196,124,108,124,116,132,167,175,140,68,12,0,15,44,76,92,92,76,68,63,52,44,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,68,71,60,44,36,36,36,44,47,39,31,28,28,44,100,180,204,164,132,148,156,156,167,164,92,111,164,68,76,175,228,143,92,92,100,87,124,156,172,148,79,20,0,0,20,44,68,76,71,52,44,44,44,39,36,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,28,36,47,52,44,36,31,23,28,36,44,39,28,15,20,12,31,100,167,196,156,116,116,148,132,140,156,135,71,108,172,71,36,132,220,180,100,71,87,76,71,116,148,172,156,92,28,0,0,0,15,36,52,60,52,28,12,28,36,36,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,36,31,28,28,20,15,23,36,39,28,12,0,12,0,20,92,164,180,140,84,84,119,132,108,124,156,108,60,108,180,76,12,100,183,204,132,60,71,71,52,68,108,132,164,156,92,36,0,0,0,0,12,28,36,36,28,12,0,15,28,28,28,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,7,12,23,15,0,12,28,36,31,15,0,0,0,0,20,76,151,180,135,79,63,87,132,108,92,111,148,76,36,108,183,84,0,68,140,212,159,79,44,76,60,44,68,100,116,148,148,100,39,0,0,0,0,0,12,28,28,28,20,7,0,7,20,28,23,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,20,0,0,0,0,0,12,63,135,164,132,84,44,60,108,108,79,84,103,135,60,20,108,164,60,0,36,108,191,180,124,36,52,71,44,36,71,87,95,127,140,100,44,0,0,0,0,0,0,12,28,23,20,12,0,0,0,12,15,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,12,60,119,140,116,84,36,44,76,116,79,47,87,108,108,55,0,108,143,44,0,12,92,156,183,148,63,28,63,68,28,36,71,84,79,108,132,100,44,7,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,12,52,108,124,103,84,44,28,60,100,92,63,31,92,124,76,52,0,108,140,36,0,0,71,119,172,156,100,20,36,68,52,15,36,76,71,68,100,116,92,39,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,44,100,108,92,71,44,20,44,68,100,68,36,44,84,124,60,44,0,108,148,47,0,0,44,100,156,148,127,55,7,47,63,36,0,36,71,68,60,84,100,79,39,12,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,92,100,79,68,47,20,20,60,84,84,60,12,68,84,108,52,28,0,108,148,44,7,0,12,92,132,132,143,84,15,20,55,55,20,0,44,68,60,47,76,87,76,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,84,92,76,55,47,28,0,44,63,84,60,36,12,84,87,79,47,7,0,108,140,39,12,0,0,76,108,132,127,108,44,0,28,60,44,7,12,44,68,52,36,60,76,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,84,68,52,44,28,0,23,55,71,68,52,7,31,84,95,55,44,0,0,108,132,28,0,0,0,44,100,132,100,119,68,12,0,39,60,31,0,12,44,68,44,31,52,68,55,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,76,63,44,44,31,12,0,44,55,68,52,31,0,60,84,95,44,44,0,0,92,108,20,0,0,0,15,92,116,95,111,84,36,0,15,47,52,20,0,12,44,60,36,28,44,52,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,76,63,28,28,28,12,0,28,52,52,44,39,12,0,76,84,79,39,36,0,0,76,92,15,0,0,0,0,76,100,108,84,95,55,0,0,28,52,44,7,0,15,44,60,31,20,36,47,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,60,31,23,28,12,0,12,44,47,39,31,23,0,20,84,84,52,36,20,0,0,68,84,15,0,0,0,0,44,100,116,63,92,60,28,0,0,36,52,28,0,0,20,44,55,28,15,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,52,44,23,20,20,12,0,0,28,47,36,28,23,7,0,47,84,76,36,36,0,0,0,68,87,20,0,0,0,0,15,92,100,71,68,68,44,0,0,12,44,44,15,0,0,20,47,52,20,12,20,23,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,47,39,12,20,20,12,0,0,15,44,44,20,15,12,0,0,68,84,60,36,36,0,0,0,68,87,20,0,0,0,0,0,71,87,84,44,76,44,20,0,0,20,44,36,0,0,0,20,52,44,20,7,20,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,36,12,0,12,12,0,0,0,31,44,23,0,0,0,0,12,79,84,44,31,31,0,0,0,68,87,20,0,0,0,0,0,44,84,84,44,60,52,36,0,0,0,28,39,20,0,0,0,23,47,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,39,20,12,0,12,0,0,0,15,39,36,0,0,0,0,0,36,79,76,36,28,23,0,0,0,68,84,15,0,0,0,0,0,15,76,76,47,36,60,44,20,0,0,12,36,36,12,0,0,0,23,47,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,15,7,0,0,0,0,0,0,31,36,15,0,0,0,0,0,60,76,60,20,20,12,0,0,0,68,84,15,0,0,0,0,0,0,60,76,60,28,52,44,36,0,0,0,15,36,28,0,0,0,0,23,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,0,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,0,0,71,76,28,12,12,0,0,0,0,68,92,20,0,0,0,0,0,0,39,76,68,36,36,52,36,12,0,0,0,20,36,20,0,0,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,7,31,31,12,0,0,0,0,0,20,68,68,12,12,12,0,0,0,0,60,87,28,0,0,0,0,0,0,15,60,60,36,20,39,36,28,0,0,0,7,28,28,12,0,0,0,0,28,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,23,12,0,0,0,0,0,0,0,0,20,28,20,0,0,0,0,0,0,44,68,52,0,12,12,0,0,0,0,44,60,15,0,0,0,0,0,0,0,44,55,36,20,28,39,36,12,0,0,0,12,28,20,0,0,0,0,0,23,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,12,7,0,0,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,60,68,36,7,7,0,0,0,0,0,23,28,0,0,0,0,0,0,0,0,20,36,36,15,15,36,28,20,0,0,0,0,15,23,12,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,12,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,12,52,52,12,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,7,28,28,15,12,20,28,28,0,0,0,0,0,20,20,7,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,20,15,0,0,0,0,0,0,0,28,47,44,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,23,28,12,12,12,28,28,15,0,0,0,0,7,20,15,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,28,31,20,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,12,28,20,12,12,20,23,23,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,12,0,0,0,0,0,0,0,0,36,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,15,20,12,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,7,20,20,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,20,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_8[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,12,23,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,12,39,39,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,7,0,0,0,0,7,44,44,7,0,0,0,15,20,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,7,0,0,0,7,7,44,44,20,0,0,0,15,20,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,23,12,7,0,0,7,7,47,47,36,0,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,12,0,0,12,12,60,63,60,0,0,0,15,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,20,12,0,0,0,12,44,68,68,0,0,0,15,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,20,12,0,0,20,31,68,68,0,0,0,15,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,12,31,36,23,20,0,0,20,23,84,71,20,0,0,12,28,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,28,36,47,28,12,0,20,20,84,71,36,0,0,0,28,23,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,7,7,0,0,0,0,0,0,0,23,36,55,28,23,0,12,20,84,71,55,0,0,0,20,28,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,15,12,0,0,0,0,0,12,15,44,47,44,31,0,7,31,84,76,68,0,0,0,28,39,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,7,12,12,0,0,0,0,12,12,39,36,63,36,15,0,31,68,84,76,0,0,0,28,52,28,28,0,0,0,0,0,0,0,0,0,0,0,0,7,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,20,20,12,0,0,0,0,20,36,44,68,44,31,0,36,52,100,76,12,0,0,36,52,28,28,0,7,7,0,0,0,0,0,0,0,0,0,28,39,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,12,28,23,0,0,0,0,20,20,52,52,63,36,0,28,44,111,76,28,0,0,36,44,12,12,0,12,12,0,0,0,0,0,0,0,0,12,39,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,12,0,20,31,20,0,0,0,12,23,47,47,84,44,20,20,36,116,76,44,0,0,36,44,12,12,0,12,12,0,0,0,0,0,0,0,0,31,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,28,36,15,0,0,0,20,36,60,76,60,36,0,39,108,84,60,0,0,36,63,28,28,12,12,12,0,0,0,0,0,0,0,15,44,44,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,28,12,12,36,31,7,0,0,12,28,63,60,84,44,7,44,92,95,71,0,0,44,79,44,28,20,20,12,0,0,0,0,0,0,0,36,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,28,12,23,44,28,0,0,0,28,52,68,95,55,28,39,76,116,76,0,0,44,84,44,23,20,20,0,0,0,0,0,0,0,20,52,44,0,0,0,0,0,0,0,0,0,0,12,20,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,28,15,36,44,20,0,0,15,36,76,84,76,44,28,60,124,76,12,0,47,92,44,23,28,28,0,0,0,0,0,0,0,44,52,23,0,0,0,0,0,0,0,0,0,7,28,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,28,20,44,44,12,0,0,36,68,84,100,52,23,52,132,84,31,0,47,92,47,28,36,36,0,0,0,0,0,0,28,55,44,0,0,0,0,0,0,0,0,0,12,39,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,47,28,31,52,36,0,0,23,52,92,108,71,36,52,127,95,47,0,47,92,47,39,36,36,0,0,0,0,0,12,52,55,23,0,0,0,0,0,0,0,0,20,52,63,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,47,36,44,55,28,0,0,44,87,103,100,52,52,116,116,68,0,52,100,52,44,36,31,0,0,0,0,0,36,60,44,0,0,0,0,0,0,0,0,20,60,76,60,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,44,44,52,52,20,0,28,68,108,119,68,60,100,132,76,0,55,108,52,44,44,20,0,0,0,0,15,60,60,20,0,0,0,0,0,0,0,28,63,76,60,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,47,52,60,44,7,12,52,108,132,95,63,92,148,87,12,60,111,60,44,44,12,0,0,0,0,44,68,44,0,0,0,0,0,0,0,36,87,108,68,20,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,63,52,60,63,36,0,36,87,135,124,71,92,156,108,23,60,116,68,47,47,15,15,12,0,20,68,63,20,0,0,0,0,0,0,36,92,116,84,31,0,0,0,0,0,0,0,0,0,0,12,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,68,60,68,60,23,15,68,132,156,95,100,159,127,44,60,116,84,52,52,12,12,0,0,52,68,44,0,0,0,0,0,7,47,100,108,79,36,7,0,0,0,0,0,0,0,0,15,28,28,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,52,68,71,76,52,12,44,124,183,132,108,148,140,60,60,119,103,52,60,20,20,0,28,71,68,12,0,0,0,0,12,60,116,127,84,31,0,0,0,0,0,0,0,0,15,31,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,76,84,76,44,28,103,196,183,132,151,156,76,68,124,116,55,68,31,28,0,60,76,44,0,0,0,0,12,68,135,148,100,36,0,0,0,0,0,0,0,20,36,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,7,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,28,68,84,92,68,36,68,172,220,156,164,156,95,79,140,124,60,63,36,15,36,76,68,15,0,0,0,20,76,156,164,108,36,0,0,0,0,0,0,20,39,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,20,7,0,0,0,12,12,0,0,12,7,12,12,12,7,0,0,0,0,0,36,76,100,95,60,47,124,220,196,188,164,116,103,156,124,71,52,39,15,68,84,47,7,0,0,23,79,156,172,116,44,7,0,7,0,0,20,44,52,47,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,28,28,15,0,0,0,0,0,20,28,28,15,20,15,20,20,0,0,0,0,44,92,108,95,55,87,180,228,207,188,132,132,180,124,92,52,44,44,92,92,36,12,0,23,87,159,164,100,39,15,15,12,12,28,52,63,60,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,31,31,31,36,28,12,0,0,20,28,39,39,36,28,36,36,28,15,0,0,12,68,119,132,92,76,140,228,220,212,143,148,191,124,116,52,44,84,111,84,44,28,39,95,164,159,92,36,23,28,20,31,60,79,84,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,39,44,39,39,39,28,12,12,28,36,52,60,55,55,55,44,28,7,0,31,92,148,135,87,116,191,236,236,164,167,204,132,116,55,68,116,124,71,52,68,116,164,151,87,44,36,36,44,68,92,100,84,60,28,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,44,55,52,52,44,39,28,28,36,52,68,71,76,71,63,39,20,0,52,116,159,132,108,156,231,247,180,183,212,148,108,76,103,148,116,76,92,135,167,143,87,52,44,55,76,92,100,100,71,31,0,0,0,0,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,44,71,79,71,60,52,44,44,44,60,84,95,100,87,68,31,20,60,132,172,140,148,204,252,207,207,220,172,103,111,148,159,116,116,148,167,140,92,63,68,92,108,100,95,76,39,7,0,12,28,31,23,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,68,92,95,84,68,63,60,68,84,111,124,124,92,52,36,71,156,180,167,188,239,236,236,236,191,124,143,180,172,156,172,172,148,100,84,100,116,111,100,79,39,12,20,36,39,36,36,31,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,68,92,111,116,95,92,92,100,116,151,159,135,92,60,95,172,188,196,223,252,252,244,196,164,180,215,204,196,196,151,124,119,127,116,100,84,52,36,44,47,44,44,39,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,68,108,140,148,140,140,140,148,167,188,188,132,100,124,180,220,228,252,252,247,204,199,220,236,228,212,180,164,151,140,108,92,76,63,55,52,52,47,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,47,79,116,148,164,172,175,188,204,223,212,172,140,156,207,244,252,252,247,228,228,244,244,231,212,191,164,140,124,116,103,92,76,68,52,36,15,12,12,20,20,12,0,0,0,0,0,0,0,0,0,7,20,20,15,15,28,28,15,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,68,100,132,156,167,188,228,244,239,204,180,199,236,252,252,252,247,247,252,247,228,212,191,172,156,140,124,124,108,92,68,47,44,36,36,28,23,28,31,36,44,52,47,47,44,44,36,31,36,36,28,20,15,28,28,15,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,15,23,20,12,12,20,20,12,7,0,12,36,68,100,140,180,228,244,247,228,220,236,252,252,252,252,252,252,252,239,220,196,180,175,188,183,167,140,116,103,100,100,103,100,87,79,68,63,52,52,52,47,44,44,44,36,31,36,36,28,20,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,23,28,28,28,15,0,15,31,52,60,76,68,60,76,103,119,116,108,100,92,87,79,84,108,148,188,212,236,247,247,247,252,252,252,252,252,252,252,239,236,236,236,220,204,196,196,180,159,132,108,84,68,60,60,60,55,55,52,52,47,39,31,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,23,28,28,28,12,0,15,31,44,52,63,68,60,76,103,124,119,116,116,116,116,116,124,132,156,183,212,236,252,252,252,252,252,252,252,252,252,247,244,244,244,244,236,215,188,164,132,100,76,60,52,39,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,44,52,60,68,76,84,84,92,92,100,100,108,116,132,156,191,228,244,252,252,252,252,252,252,252,252,252,252,252,239,220,188,151,116,100,63,31,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,20,44,60,71,76,76,76,76,84,84,84,84,84,84,84,84,84,84,84,87,95,116,132,156,164,167,180,207,236,252,252,252,252,252,252,252,252,252,252,252,247,239,212,164,108,71,68,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,23,47,47,23,0,20,52,76,84,79,76,76,76,84,84,84,84,84,76,76,68,76,92,100,100,92,92,87,100,124,151,183,212,236,252,252,252,252,252,252,236,236,252,252,252,247,228,204,191,172,132,87,63,52,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,23,47,47,23,0,20,44,60,55,47,36,31,20,20,12,7,20,36,52,55,60,60,60,63,68,92,116,132,135,127,140,180,212,220,231,239,244,252,252,228,204,204,252,244,244,244,228,204,172,151,140,116,92,71,60,44,44,36,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,52,52,52,55,60,60,68,84,100,92,76,68,68,95,132,151,167,183,196,204,220,239,252,244,183,159,188,244,223,223,228,228,212,180,148,132,124,108,71,31,20,31,36,36,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,44,44,44,44,47,52,52,52,52,55,55,52,52,55,60,60,76,84,92,95,124,148,148,156,188,220,239,247,220,127,127,188,228,188,196,191,204,220,220,172,124,100,92,95,84,52,12,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,23,28,36,36,36,44,44,44,36,20,20,28,44,44,47,52,52,52,44,44,60,68,76,100,116,108,92,116,156,196,223,244,236,167,79,103,172,188,172,172,164,172,172,212,231,188,119,76,68,76,79,71,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,20,20,23,23,28,36,28,15,0,0,12,28,36,36,44,44,44,44,36,20,28,52,68,71,84,92,92,76,63,84,124,180,196,212,223,204,108,52,95,143,140,172,156,143,151,135,148,215,244,204,132,68,44,60,76,76,68,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,20,20,15,12,0,0,0,0,12,23,23,28,36,36,36,36,23,0,0,28,52,63,68,71,76,71,63,60,44,55,108,164,188,172,191,212,156,52,44,95,108,84,164,164,116,132,127,100,148,220,244,212,156,84,31,31,60,76,71,68,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,15,20,28,28,23,28,28,15,0,0,0,28,52,60,63,60,60,52,52,55,44,28,44,103,143,164,148,156,199,188,95,12,55,87,84,60,148,180,108,84,124,84,76,148,191,207,199,159,92,36,7,28,55,68,68,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,23,20,12,0,0,0,0,28,52,60,60,55,44,36,44,52,44,23,20,47,103,124,140,124,132,172,204,140,44,0,60,71,44,31,124,196,116,44,76,87,60,63,124,156,180,188,151,108,52,12,0,23,52,63,60,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,7,0,0,0,0,0,12,28,47,52,55,52,31,28,36,44,44,28,7,15,52,100,116,116,103,108,148,204,180,84,7,0,55,55,12,12,100,188,140,52,28,71,68,39,52,108,132,148,164,148,116,60,20,0,0,20,44,60,60,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,52,44,20,12,23,36,36,28,12,0,20,52,100,100,100,92,92,116,180,204,124,28,0,12,52,52,0,0,79,167,156,76,0,36,68,52,23,52,95,116,124,143,140,124,76,31,0,0,0,20,44,60,55,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,44,36,15,0,12,28,31,28,15,0,0,28,60,92,92,84,79,84,92,148,204,156,68,0,0,28,44,44,0,0,60,132,164,103,12,7,52,68,31,15,47,87,100,108,124,127,124,84,44,7,0,0,0,20,44,52,47,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,44,31,12,0,7,20,28,28,15,0,0,0,28,60,84,76,68,68,76,76,116,180,180,100,20,0,0,36,44,44,0,0,47,100,175,119,36,0,23,60,60,15,20,44,76,84,92,103,116,119,95,60,20,0,0,0,0,15,36,47,47,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,36,28,7,0,0,7,20,20,20,0,0,0,0,31,60,76,68,52,60,68,60,84,140,172,119,44,0,0,0,39,39,28,0,0,28,71,164,124,68,0,0,36,60,39,0,20,44,68,68,76,87,103,111,103,68,28,0,0,0,0,0,15,36,47,44,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,31,31,20,0,0,0,0,0,7,15,7,0,0,0,7,36,60,68,60,44,52,60,52,68,116,156,135,76,12,0,0,0,36,36,12,0,0,12,60,132,124,84,0,0,12,52,60,23,0,20,44,60,55,68,76,92,100,103,76,39,0,0,0,0,0,0,15,36,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,15,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,60,44,31,44,55,52,52,92,135,140,92,36,0,0,0,0,36,36,0,0,0,0,52,103,127,100,23,0,0,28,52,44,7,0,20,39,52,44,60,68,79,92,100,84,52,12,0,0,0,0,0,0,12,28,36,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,44,36,20,31,47,52,36,68,116,132,103,60,7,0,0,0,12,28,28,0,0,0,0,52,76,124,103,44,0,0,0,36,52,28,0,0,20,36,36,36,52,60,68,76,92,87,60,23,0,0,0,0,0,0,0,12,28,36,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,15,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,52,36,20,12,23,39,52,28,47,100,119,111,76,28,0,0,0,0,15,20,20,0,0,0,0,44,55,103,92,52,0,0,0,12,44,44,15,0,0,12,20,20,28,44,52,60,68,84,87,68,36,0,0,0,0,0,0,0,0,12,23,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,44,28,12,7,12,36,52,28,36,84,108,108,84,44,0,0,0,0,0,15,15,12,0,0,0,0,28,44,87,84,68,15,0,0,0,28,44,36,0,0,0,0,15,28,28,36,39,52,60,71,84,68,36,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,39,20,0,0,12,28,47,28,20,63,100,100,87,63,20,0,0,0,0,0,15,15,0,0,0,0,0,12,44,76,76,76,36,0,0,0,0,36,44,20,0,0,0,15,28,20,20,20,31,44,52,60,68,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,36,15,0,0,0,20,44,28,12,44,92,92,84,68,36,0,0,0,0,0,0,7,7,0,0,0,0,0,0,36,55,60,76,39,0,0,0,0,15,36,36,7,0,0,0,12,23,20,12,12,23,36,44,44,52,60,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,28,12,0,0,0,20,36,28,12,31,76,92,71,71,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,44,55,71,44,12,0,0,0,0,23,36,20,0,0,0,0,12,12,0,0,0,15,28,39,36,44,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,23,7,0,0,0,12,36,28,12,15,63,92,68,63,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,60,63,55,23,0,0,0,0,7,28,31,12,0,0,0,0,0,0,0,0,0,7,23,28,23,28,44,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,23,20,0,0,0,0,12,28,28,12,0,47,84,68,52,60,44,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,52,47,60,31,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,12,23,20,28,28,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,7,0,0,0,0,0,12,20,12,0,36,76,71,39,52,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,36,23,52,28,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,12,20,23,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,7,12,0,0,20,63,76,44,31,52,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,36,28,7,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,7,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,12,20,7,0,0,47,76,52,20,44,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,28,28,20,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,15,12,0,0,36,71,60,15,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,36,20,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,20,60,68,28,12,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,68,44,0,28,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,52,12,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,52,20,0,28,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,31,12,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,15,0,0,23,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,12,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t SHINE_TEXTURE_9[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,0,0,7,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,0,0,0,28,28,20,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,36,36,28,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,15,0,0,36,31,23,0,0,0,0,0,0,0,0,20,20,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,0,12,23,20,12,0,0,0,0,0,0,0,0,36,36,0,0,0,7,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,0,12,20,36,28,0,0,0,0,0,0,0,12,52,52,7,0,12,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,39,20,0,20,71,60,12,0,0,0,0,0,0,20,52,52,7,0,12,12,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,52,28,0,23,84,68,12,0,0,0,0,0,0,36,60,52,0,0,20,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,47,12,23,55,31,7,0,0,0,0,0,0,63,79,60,7,15,12,28,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,71,12,15,52,36,20,0,0,0,0,0,0,60,68,44,12,28,28,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,20,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,15,76,79,28,20,76,68,44,0,0,0,0,0,0,68,68,36,15,36,39,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,7,28,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,76,84,52,31,100,100,68,0,0,0,0,0,20,92,92,39,28,36,60,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,15,20,0,0,0,12,36,31,12,0,0,0,0,0,0,0,0,0,0,0,0,60,92,68,28,84,108,76,0,0,0,0,0,36,92,92,36,39,36,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,36,23,0,0,0,20,44,28,0,0,0,0,0,0,0,0,0,7,7,0,39,92,87,36,68,111,79,0,0,0,0,0,55,108,103,31,52,44,52,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,23,31,36,20,0,0,0,28,44,20,0,0,0,0,0,0,0,0,12,12,7,20,92,95,52,68,124,84,0,0,0,0,0,76,116,108,28,60,68,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,28,31,39,28,0,0,12,39,44,15,0,0,0,0,0,0,0,12,20,15,0,92,100,63,60,127,84,12,0,0,0,0,92,124,108,44,60,76,39,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,39,44,23,0,0,20,44,36,12,0,0,0,0,0,0,0,23,23,0,68,100,79,60,140,100,23,0,0,0,12,108,132,103,68,76,76,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,36,44,23,0,0,28,52,31,0,0,0,0,0,0,0,20,20,7,44,100,92,68,140,108,36,0,0,0,23,124,140,92,79,84,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,23,36,44,28,0,7,39,52,28,0,0,0,0,0,0,12,23,20,20,100,100,76,132,116,47,0,0,0,39,127,156,84,92,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,28,39,52,47,23,0,20,52,52,20,0,0,0,0,0,0,31,31,12,92,100,95,132,140,60,0,0,0,60,127,156,92,108,92,44,0,0,0,0,0,0,0,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,44,52,52,55,52,23,0,28,60,44,12,0,0,0,0,0,28,36,23,76,100,111,132,151,71,0,0,0,76,127,148,95,116,84,36,0,0,0,0,0,0,7,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,60,63,60,68,52,20,0,36,60,36,7,15,15,0,0,15,39,39,52,100,116,124,151,79,0,0,12,100,143,140,103,108,68,20,0,0,0,0,0,12,23,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,63,71,71,71,52,28,12,52,60,28,20,28,15,0,0,44,44,44,100,108,124,148,92,0,0,28,127,164,140,127,108,60,0,0,0,0,0,15,28,28,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,76,84,84,76,52,20,23,60,60,28,28,28,12,0,44,55,52,92,100,140,151,108,0,0,39,140,188,148,148,108,47,0,0,0,0,12,28,44,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,76,92,92,84,52,23,36,68,52,31,36,28,0,28,63,60,84,100,156,151,119,20,0,44,132,180,151,148,103,36,7,0,0,7,28,52,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,84,100,108,92,52,28,44,71,52,44,44,20,0,68,68,84,100,156,156,132,28,0,71,156,188,164,140,92,23,0,0,0,28,52,60,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,12,36,87,111,116,100,55,39,60,68,60,52,44,7,52,76,87,100,151,164,140,39,0,100,183,204,191,148,76,23,0,0,20,52,71,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,20,15,12,12,0,0,0,36,92,124,127,108,60,52,68,76,76,60,36,23,76,84,108,140,180,140,52,20,119,204,220,196,148,60,12,0,12,44,76,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,36,36,28,12,0,0,36,92,132,135,111,60,60,76,84,84,68,20,68,79,124,124,196,140,63,31,132,228,236,199,132,44,0,0,36,76,84,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,55,52,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,52,60,47,28,7,0,36,92,132,148,116,71,76,87,108,92,52,47,79,127,116,199,140,76,44,148,244,244,196,108,28,0,28,76,95,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,60,60,52,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,63,76,76,52,23,0,31,87,148,180,148,92,84,108,116,84,44,76,116,127,196,156,87,60,164,252,244,188,87,12,15,68,103,92,44,12,0,0,0,0,0,0,0,0,0,0,0,0,28,52,68,68,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,92,100,84,44,20,28,95,175,204,156,108,103,132,116,68,76,92,151,183,180,100,76,180,252,244,164,68,7,55,111,116,68,28,7,0,0,0,0,0,0,0,0,0,0,36,68,84,76,68,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,116,116,84,36,36,100,180,207,164,124,132,143,100,79,84,164,188,204,111,87,188,252,228,132,36,36,108,140,92,39,12,0,0,0,0,0,0,0,0,7,39,76,92,92,79,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,76,124,148,124,68,55,100,180,204,172,140,156,143,95,100,148,196,220,124,100,204,252,199,100,36,100,159,132,60,12,0,0,0,0,0,0,0,12,44,84,100,100,87,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,20,60,116,156,151,108,76,108,180,196,180,164,172,132,116,132,212,228,132,116,220,244,164,71,76,156,156,92,28,0,0,0,0,0,0,12,47,84,103,108,92,63,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,15,12,0,36,92,140,164,135,116,132,180,204,196,196,191,148,140,204,231,148,132,231,223,127,76,140,180,124,39,0,0,0,0,0,12,52,87,103,103,92,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,20,31,36,31,44,76,124,151,159,151,156,196,212,223,236,188,172,196,244,159,156,244,188,116,119,188,156,60,12,0,0,0,20,55,92,103,103,92,55,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,36,39,36,44,60,71,84,116,148,164,172,196,228,244,252,228,196,199,239,180,180,236,164,135,172,172,84,20,0,0,20,60,92,103,103,87,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,20,12,12,12,0,0,0,0,0,0,0,0,0,12,12,12,20,23,47,68,76,76,84,100,127,159,180,196,228,244,252,252,228,228,244,204,204,220,172,167,172,100,23,0,23,63,92,108,108,87,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,20,12,15,28,28,28,28,36,39,36,28,12,0,0,0,0,12,20,31,36,52,76,103,124,124,140,172,207,228,244,252,252,244,244,244,228,228,212,199,172,116,39,28,68,100,124,124,100,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,28,28,28,28,36,39,44,44,44,47,52,52,52,47,36,31,36,44,44,52,76,108,151,175,196,220,244,252,252,252,252,252,244,244,231,196,132,76,79,119,140,140,116,63,28,0,0,0,0,0,0,0,7,20,20,28,28,31,23,15,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,7,20,36,44,44,44,47,52,52,52,55,60,60,68,76,84,95,108,103,111,132,164,204,231,252,252,252,252,252,252,252,231,188,140,132,148,148,124,76,44,31,28,31,44,52,52,52,52,52,52,52,47,52,52,52,28,15,20,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,28,15,0,0,0,20,36,44,44,55,71,92,103,108,116,124,127,124,132,127,127,143,164,180,204,228,244,252,252,252,252,252,252,236,207,188,188,180,156,124,108,103,116,124,132,132,124,116,108,103,100,92,87,76,68,60,39,12,0,7,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,23,28,39,36,20,15,28,47,68,71,76,84,87,95,95,100,124,159,180,188,207,220,223,223,220,212,212,228,244,252,252,252,252,252,252,244,244,236,212,188,175,180,196,204,215,220,228,223,196,167,148,132,124,108,100,95,92,92,76,60,36,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,28,28,36,36,44,52,60,68,76,84,100,108,124,127,140,172,207,228,228,236,244,239,244,236,236,247,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,236,212,175,156,124,100,87,84,84,84,84,84,84,84,84,68,44,36,23,0,0,0,0,0,0,0,0,12,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,60,31,47,84,100,100,92,92,92,92,92,92,100,108,124,143,164,164,172,172,172,196,207,220,223,236,244,244,252,252,252,252,252,252,252,252,252,236,212,204,215,236,252,236,215,180,159,140,116,87,76,76,71,60,44,36,28,28,28,28,31,20,0,0,0,0,0,0,0,0,12,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,28,60,76,44,12,28,60,84,84,84,84,84,87,84,76,76,68,63,60,68,92,127,148,143,140,148,172,188,196,215,244,252,252,252,252,252,252,252,252,252,236,212,183,164,156,164,188,212,223,223,191,156,119,103,92,79,60,52,52,47,44,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,20,44,52,31,7,12,20,20,12,0,0,0,7,7,12,20,28,52,68,79,79,84,95,119,140,140,124,140,167,204,236,247,236,236,231,236,252,252,247,247,244,228,191,156,140,119,108,116,135,148,151,143,124,111,100,92,76,76,71,68,60,52,44,39,36,28,28,31,23,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,52,60,60,63,68,79,100,108,92,79,100,124,140,159,204,228,231,207,212,207,212,244,244,236,220,212,220,212,196,180,148,111,76,60,60,60,63,60,68,76,76,60,44,28,28,39,52,47,44,39,28,28,31,23,15,12,23,12,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,52,52,52,55,60,60,60,68,68,63,68,76,92,95,116,140,167,188,228,196,172,196,188,180,223,228,220,191,156,167,172,172,180,188,180,156,116,68,28,15,28,39,39,36,36,36,39,36,31,20,12,0,0,0,0,12,12,12,12,23,12,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,44,47,52,52,47,36,31,44,52,60,60,60,60,68,84,108,124,140,156,212,215,148,148,204,172,148,204,196,188,180,124,100,132,140,140,148,164,180,188,159,111,68,31,0,0,12,28,31,28,20,15,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,39,44,44,44,36,20,7,20,39,52,52,55,47,36,44,68,84,100,108,116,132,180,215,172,108,143,228,156,124,188,164,156,167,124,76,68,111,116,111,111,132,148,175,180,148,100,68,36,7,0,0,0,0,12,12,12,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,28,36,36,36,36,23,0,0,0,20,39,44,47,52,36,15,23,52,76,79,84,92,100,116,159,204,188,108,92,164,244,143,100,156,140,124,124,143,84,44,55,95,103,100,87,95,111,127,156,156,132,92,68,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,20,20,23,23,12,0,0,0,7,20,36,39,44,44,28,0,0,36,68,76,68,68,79,84,95,140,188,191,132,60,92,188,215,116,76,119,143,92,95,132,116,60,20,52,84,92,84,76,76,76,87,108,132,140,116,84,60,39,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,15,20,20,12,0,0,0,0,0,12,20,28,36,36,36,20,0,0,20,52,68,68,52,60,76,76,76,124,175,188,143,76,36,108,196,180,84,44,100,143,68,84,92,124,84,31,7,44,76,76,71,68,68,60,60,76,95,116,119,108,76,55,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,15,23,28,28,23,12,0,0,0,36,60,68,52,39,47,76,68,63,103,164,180,148,92,28,52,124,180,151,55,20,92,124,76,68,68,100,92,60,12,0,36,68,68,60,55,63,52,44,44,63,84,95,100,87,63,44,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,20,23,15,0,0,0,0,20,44,63,60,36,28,47,76,60,47,76,148,164,148,108,52,0,68,140,148,116,23,0,87,100,92,52,52,68,92,68,36,0,0,28,60,68,52,44,60,60,36,28,36,60,68,71,76,68,52,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,31,52,60,47,20,20,52,76,52,36,60,132,143,132,116,76,12,15,76,156,124,92,12,0,79,92,100,47,44,52,76,76,60,23,0,0,23,52,68,44,36,44,52,44,23,15,28,44,55,52,52,52,44,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,20,44,55,52,31,7,20,52,71,47,28,47,116,132,124,116,92,36,0,44,79,164,116,63,7,0,63,92,100,44,39,31,52,68,60,47,12,0,0,20,47,63,39,28,31,52,47,28,12,12,28,28,36,36,44,44,28,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,52,44,20,0,23,52,68,39,12,36,95,124,108,108,100,60,0,0,60,92,151,111,39,0,0,44,92,92,44,39,20,44,55,60,55,36,0,0,0,12,39,60,44,20,20,44,44,31,12,0,0,12,20,36,28,28,28,23,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,52,44,28,0,0,28,55,60,36,0,20,68,116,108,92,100,76,20,0,12,68,111,127,108,12,0,0,23,87,87,44,36,20,23,44,52,47,52,20,0,0,0,12,36,60,44,15,12,28,44,36,20,0,0,0,12,15,20,20,20,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,44,36,12,0,0,28,60,55,28,0,12,44,92,100,76,92,92,44,0,0,36,68,124,108,92,0,0,0,7,87,87,47,31,28,0,36,39,39,47,39,12,0,0,0,0,28,52,44,20,0,20,36,36,23,7,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,39,20,0,0,0,31,55,52,23,0,0,28,76,92,68,79,92,63,7,0,0,52,63,119,100,76,0,0,0,0,84,87,52,28,28,0,20,36,36,31,44,28,0,0,0,0,0,28,44,44,20,0,12,28,36,28,12,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,39,28,12,0,0,12,36,55,44,20,0,0,20,60,84,68,60,84,79,28,0,0,0,60,63,100,87,52,0,0,0,0,68,87,68,20,23,12,0,28,36,28,36,44,20,0,0,0,0,0,20,39,39,20,0,0,15,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,31,20,0,0,0,12,36,52,36,12,0,0,12,36,68,71,47,68,84,44,0,0,0,28,60,63,84,79,36,0,0,0,0,47,87,79,12,15,15,0,12,28,28,20,36,31,7,0,0,0,0,0,12,36,39,20,0,0,0,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,31,20,7,0,0,0,12,36,52,31,12,0,0,12,28,52,68,39,44,76,63,12,0,0,0,44,60,52,71,71,15,0,0,0,0,28,84,84,12,12,12,0,0,20,23,12,20,36,20,0,0,0,0,0,0,12,28,36,20,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,23,12,0,0,0,0,15,36,44,28,0,0,0,7,23,52,63,44,28,55,63,28,0,0,0,0,52,55,36,60,60,0,0,0,0,0,12,84,84,20,0,0,0,0,7,20,20,12,28,31,12,0,0,0,0,0,0,7,23,36,20,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,15,0,0,0,0,0,15,36,44,20,0,0,0,0,7,31,60,47,20,31,55,39,0,0,0,0,20,52,52,20,44,44,0,0,0,0,0,0,84,84,44,0,0,0,0,0,12,20,12,12,28,28,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,7,0,0,0,0,0,12,31,36,20,0,0,0,0,0,15,44,52,28,15,44,44,12,0,0,0,0,36,52,44,20,36,31,0,0,0,0,0,0,68,84,60,0,0,0,0,0,0,12,12,0,12,20,12,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,12,28,20,12,0,0,0,0,0,12,31,47,28,0,28,44,28,0,0,0,0,0,47,52,20,23,28,20,0,0,0,0,0,0,52,84,76,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,20,28,20,0,0,0,0,0,0,7,28,47,36,12,15,39,36,0,0,0,0,0,12,47,47,0,20,20,7,0,0,0,0,0,0,31,84,79,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,20,7,0,0,0,0,0,0,15,39,36,12,0,31,36,15,0,0,0,0,0,28,44,44,0,12,12,0,0,0,0,0,0,0,12,76,76,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,28,36,20,0,20,36,23,0,0,0,0,0,0,44,44,23,0,12,12,0,0,0,0,0,0,0,0,60,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,20,36,20,0,7,28,28,7,0,0,0,0,0,0,44,44,0,0,7,7,0,0,0,0,0,0,0,0,44,55,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,12,31,23,0,0,20,28,12,0,0,0,0,0,0,20,39,36,0,0,0,0,0,0,0,0,0,0,0,0,28,44,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,12,28,28,7,0,12,28,20,0,0,0,0,0,0,0,36,36,23,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,20,23,7,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,12,20,12,0,0,0,0,0,0,0,15,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,12,0,0,0,12,12,0,0,0,0,0,0,0,0,28,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,7,12,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,15,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
|
|
const uint8_t * SHINE_TEXTURES[10] = {
|
|
SHINE_TEXTURE_0,
|
|
SHINE_TEXTURE_1,
|
|
SHINE_TEXTURE_2,
|
|
SHINE_TEXTURE_3,
|
|
SHINE_TEXTURE_4,
|
|
SHINE_TEXTURE_5,
|
|
SHINE_TEXTURE_6,
|
|
SHINE_TEXTURE_7,
|
|
SHINE_TEXTURE_8,
|
|
SHINE_TEXTURE_9,
|
|
};
|
|
const int SHINE_TEXTURE_WIDTHS[10] = {
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
};
|
|
const int SHINE_TEXTURE_HEIGHTS[10] = {
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
128,
|
|
};
|
|
}
|
|
}
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_sort_triangles = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_SORT_TRIANGLES_H
|
|
#define IGL_OPENGL2_SORT_TRIANGLES_H
|
|
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedFF,
|
|
typename DerivedI>
|
|
IGL_INLINE void sort_triangles(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedI> & I);
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedFF,
|
|
typename DerivedI>
|
|
IGL_INLINE void sort_triangles_slow(
|
|
const Eigen::PlainObjectBase<DerivedV> & V,
|
|
const Eigen::PlainObjectBase<DerivedF> & F,
|
|
Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
Eigen::PlainObjectBase<DerivedI> & I);
|
|
//template <
|
|
// typename DerivedV,
|
|
// typename DerivedF,
|
|
// typename DerivedMV,
|
|
// typename DerivedP,
|
|
// typename DerivedFF,
|
|
// typename DerivedI>
|
|
//IGL_INLINE void sort_triangles_robust(
|
|
// const Eigen::PlainObjectBase<DerivedV> & V,
|
|
// const Eigen::PlainObjectBase<DerivedF> & F,
|
|
// const Eigen::PlainObjectBase<DerivedMV> & MV,
|
|
// const Eigen::PlainObjectBase<DerivedP> & P,
|
|
// Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
// Eigen::PlainObjectBase<DerivedI> & I);
|
|
//template <
|
|
// typename DerivedV,
|
|
// typename DerivedF,
|
|
// typename DerivedFF,
|
|
// typename DerivedI>
|
|
//IGL_INLINE void sort_triangles_robust(
|
|
// const Eigen::PlainObjectBase<DerivedV> & V,
|
|
// const Eigen::PlainObjectBase<DerivedF> & F,
|
|
// Eigen::PlainObjectBase<DerivedFF> & FF,
|
|
// Eigen::PlainObjectBase<DerivedI> & I);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "sort_triangles.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_unproject = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_UNPROJECT_H
|
|
#define IGL_OPENGL2_UNPROJECT_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Wrapper for gluUnproject that uses the current GL_MODELVIEW_MATRIX,
|
|
// GL_PROJECTION_MATRIX, and GL_VIEWPORT
|
|
// Inputs:
|
|
// win* screen space x, y, and z coordinates respectively
|
|
// Outputs:
|
|
// obj* pointers to 3D objects' x, y, and z coordinates respectively
|
|
// Returns return value of gluUnProject call
|
|
IGL_INLINE void unproject(
|
|
const double winX,
|
|
const double winY,
|
|
const double winZ,
|
|
double* objX,
|
|
double* objY,
|
|
double* objZ);
|
|
template <typename Derivedwin, typename Derivedobj>
|
|
IGL_INLINE void unproject(
|
|
const Eigen::PlainObjectBase<Derivedwin> & win,
|
|
Eigen::PlainObjectBase<Derivedobj> & obj);
|
|
template <typename Derivedwin>
|
|
IGL_INLINE Eigen::PlainObjectBase<Derivedwin> unproject(
|
|
const Eigen::PlainObjectBase<Derivedwin> & win);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unproject.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_unproject_to_zero_plane = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_UNPROJECT_TO_ZERO_PLANE_H
|
|
#define IGL_OPENGL2_UNPROJECT_TO_ZERO_PLANE_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Wrapper for gluUnproject that uses the current GL_MODELVIEW_MATRIX,
|
|
// GL_PROJECTION_MATRIX, and GL_VIEWPORT to unproject a screen postion
|
|
// (winX,winY) to a 3d location at same depth as the current origin.
|
|
// Inputs:
|
|
// win* screen space x, y, and z coordinates respectively
|
|
// Outputs:
|
|
// obj* pointers to 3D objects' x, y, and z coordinates respectively
|
|
// Returns return value of gluUnProject call
|
|
IGL_INLINE void unproject_to_zero_plane(
|
|
const double winX,
|
|
const double winY,
|
|
double* objX,
|
|
double* objY,
|
|
double* objZ);
|
|
template <typename Derivedwin, typename Derivedobj>
|
|
IGL_INLINE void unproject_to_zero_plane(
|
|
const Eigen::PlainObjectBase<Derivedwin> & win,
|
|
Eigen::PlainObjectBase<Derivedobj> & obj);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "unproject_to_zero_plane.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_up_axis = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_UP_AXIS_H
|
|
#define IGL_OPENGL2_UP_AXIS_H
|
|
#include "../igl_inline.h"
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Determines the up axis or depth axis of the current gl matrix
|
|
// Outputs:
|
|
// x pointer to x-coordinate in scene coordinates of the un-normalized
|
|
// up axis
|
|
// y pointer to y-coordinate in scene coordinates of the un-normalized
|
|
// up axis
|
|
// z pointer to z-coordinate in scene coordinates of the un-normalized
|
|
// up axis
|
|
// mv pointer to modelview matrix
|
|
//
|
|
// Note: Up axis is returned *UN-normalized*
|
|
IGL_INLINE void up_axis(double * x, double * y, double * z);
|
|
IGL_INLINE void up_axis(const double * mv, double * x, double * y, double * z);
|
|
}
|
|
};
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "up_axis.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_opengl2_view_axis = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_OPENGL2_VIEW_AXIS_H
|
|
#define IGL_OPENGL2_VIEW_AXIS_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace opengl2
|
|
{
|
|
// Determines the view axis or depth axis of the current gl matrix
|
|
// Inputs:
|
|
// mv pointer to modelview matrix
|
|
// Outputs:
|
|
// x pointer to x-coordinate in scene coordinates of the un-normalized
|
|
// viewing axis
|
|
// y pointer to y-coordinate in scene coordinates of the un-normalized
|
|
// viewing axis
|
|
// z pointer to z-coordinate in scene coordinates of the un-normalized
|
|
// viewing axis
|
|
//
|
|
// Note: View axis is returned *UN-normalized*
|
|
IGL_INLINE void view_axis(const double * mv, double * x, double * y, double * z);
|
|
// Extract mv from current GL state.
|
|
IGL_INLINE void view_axis(double * x, double * y, double * z);
|
|
template <typename DerivedV>
|
|
IGL_INLINE void view_axis(Eigen::PlainObjectBase<DerivedV> & V);
|
|
}
|
|
};
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "view_axis.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_png_render_to_png = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PNG_RENDER_TO_PNG_H
|
|
#define IGL_PNG_RENDER_TO_PNG_H
|
|
#include <igl/igl_inline.h>
|
|
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
namespace png
|
|
{
|
|
//
|
|
// Render current open GL image to .png file
|
|
// Inputs:
|
|
// png_file path to output .png file
|
|
// width width of scene and resulting image
|
|
// height height of scene and resulting image
|
|
// alpha whether to include alpha channel
|
|
// fast sacrifice compression ratio for speed
|
|
// Returns true only if no errors occured
|
|
//
|
|
// See also: igl/render_to_tga which is faster but writes .tga files
|
|
IGL_INLINE bool render_to_png(
|
|
const std::string png_file,
|
|
const int width,
|
|
const int height,
|
|
const bool alpha = true,
|
|
const bool fast = false);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "render_to_png.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_png_render_to_png_async = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PNG_RENDER_TO_PNG_ASYNC_H
|
|
#define IGL_PNG_RENDER_TO_PNG_ASYNC_H
|
|
#include <igl/igl_inline.h>
|
|
#include <thread>
|
|
//#include <boost/thread/thread.hpp>
|
|
|
|
#include <string>
|
|
namespace igl
|
|
{
|
|
namespace png
|
|
{
|
|
// History:
|
|
// added multithreaded parameter and support, Alec Sept 3, 2012
|
|
//
|
|
// Render current open GL image to .png file
|
|
// Inputs:
|
|
// png_file path to output .png file
|
|
// width width of scene and resulting image
|
|
// height height of scene and resulting image
|
|
// alpha whether to include alpha channel
|
|
// fast sacrifice compression ratio for speed
|
|
// Returns true only if no errors occured
|
|
//
|
|
// See also: igl/render_to_tga which is faster but writes .tga files
|
|
IGL_INLINE std::thread render_to_png_async(
|
|
const std::string png_file,
|
|
const int width,
|
|
const int height,
|
|
const bool alpha = true,
|
|
const bool fast = false);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "render_to_png_async.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_png_texture_from_file = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PNG_TEXTURE_FROM_FILE_H
|
|
#define IGL_PNG_TEXTURE_FROM_FILE_H
|
|
#include "../igl_inline.h"
|
|
#include "../opengl/OpenGL_convenience.h"
|
|
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
namespace png
|
|
{
|
|
// Read an image from an image file and use it as a texture. Officially,
|
|
// only .tga and .png are supported. Any filetype read by ImageMagick's
|
|
// `convert` will work via an unsafe system call.
|
|
//
|
|
// Input:
|
|
// filename path to image file
|
|
// Output:
|
|
// id of generated openGL texture
|
|
// Returns true on success, false on failure
|
|
IGL_INLINE bool texture_from_file(const std::string filename, GLuint & id);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "texture_from_file.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_png_texture_from_png = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_PNG_TEXTURE_FROM_PNG_H
|
|
#define IGL_PNG_TEXTURE_FROM_PNG_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
#include <Eigen/Core>
|
|
|
|
#include "../opengl/OpenGL_convenience.h"
|
|
|
|
namespace igl
|
|
{
|
|
namespace png
|
|
{
|
|
// Read an image from a .png file and use it as a texture
|
|
//
|
|
// Input:
|
|
// png_file path to .png file
|
|
// Output:
|
|
// id of generated openGL texture
|
|
// Returns true on success, false on failure
|
|
IGL_INLINE bool texture_from_png(const std::string png_file, GLuint & id);
|
|
}
|
|
}
|
|
|
|
namespace igl
|
|
{
|
|
namespace png
|
|
{
|
|
// Read an image from a .png file and use it as a texture
|
|
//
|
|
// Input:
|
|
// png_file path to .png file
|
|
// Output:
|
|
// R,G,B,A texture channels
|
|
// Returns true on success, false on failure
|
|
IGL_INLINE bool texture_from_png(const std::string png_file,
|
|
Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
|
Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
|
Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B,
|
|
Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& A
|
|
);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "texture_from_png.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_tetgen_cdt = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TETGEN_CDT_H
|
|
#define IGL_TETGEN_CDT_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <Eigen/Core>
|
|
#include <string>
|
|
#ifndef TETLIBRARY
|
|
# define TETLIBRARY
|
|
#endif
|
|
#include "tetgen.h" // Defined REAL
|
|
|
|
namespace igl
|
|
{
|
|
namespace tetgen
|
|
{
|
|
struct CDTParam
|
|
{
|
|
// Tetgen can compute mesh of convex hull of input (i.e. "c") but often
|
|
// chokes. One workaround is to force it to mesh the entire bounding box.
|
|
// {false}
|
|
bool use_bounding_box = false;
|
|
// Scale the bounding box a bit so that vertices near it do not give tetgen
|
|
// problems. {1.01}
|
|
double bounding_box_scale = 1.01;
|
|
// Flags to tetgen. Do not include the "c" flag here! {"Y"}
|
|
std::string flags = "Y";
|
|
};
|
|
// Create a constrained delaunay tesselation containing convex hull of the
|
|
// given **non-selfintersecting** mesh.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of input mesh vertices
|
|
// F #F by 3 list of input mesh facets
|
|
// param see above
|
|
// TV #TV by 3 list of output mesh vertices (V come first)
|
|
// TT #TT by 3 list of tetrahedra indices into TV.
|
|
// TF #TF by 3 list of facets from F potentially subdivided.
|
|
//
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedTV,
|
|
typename DerivedTT,
|
|
typename DerivedTF>
|
|
IGL_INLINE bool cdt(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const CDTParam & param,
|
|
Eigen::PlainObjectBase<DerivedTV>& TV,
|
|
Eigen::PlainObjectBase<DerivedTT>& TT,
|
|
Eigen::PlainObjectBase<DerivedTF>& TF);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "cdt.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_tetgen_mesh_to_tetgenio = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TETGEN_MESH_TO_TETGENIO_H
|
|
#define IGL_TETGEN_MESH_TO_TETGENIO_H
|
|
#include "../igl_inline.h"
|
|
|
|
#ifndef TETLIBRARY
|
|
# define TETLIBRARY
|
|
#endif
|
|
#include "tetgen.h" // Defined tetgenio, REAL
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace tetgen
|
|
{
|
|
// Load a vertex list and face list into a tetgenio object
|
|
// Inputs:
|
|
// V #V by 3 vertex position list
|
|
// F #F list of polygon face indices into V (0-indexed)
|
|
// Outputs:
|
|
// in tetgenio input object
|
|
// Returns true on success, false on error
|
|
IGL_INLINE bool mesh_to_tetgenio(
|
|
const std::vector<std::vector<REAL > > & V,
|
|
const std::vector<std::vector<int> > & F,
|
|
tetgenio & in);
|
|
|
|
// Wrapper with Eigen types
|
|
// Templates:
|
|
// DerivedV real-value: i.e. from MatrixXd
|
|
// DerivedF integer-value: i.e. from MatrixXi
|
|
template <typename DerivedV, typename DerivedF>
|
|
IGL_INLINE bool mesh_to_tetgenio(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
tetgenio & in);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mesh_to_tetgenio.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_tetgen_mesh_with_skeleton = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TETGEN_MESH_WITH_SKELETON_H
|
|
#define IGL_TETGEN_MESH_WITH_SKELETON_H
|
|
#include "../igl_inline.h"
|
|
#include <Eigen/Dense>
|
|
#include <string>
|
|
|
|
namespace igl
|
|
{
|
|
namespace tetgen
|
|
{
|
|
// Mesh the interior of a given surface with tetrahedra which are graded
|
|
// (tend to be small near the surface and large inside) and conform to the
|
|
// given handles and samplings thereof.
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 list of mesh vertex positions
|
|
// F #F by 3 list of triangle indices
|
|
// C #C by 3 list of vertex positions
|
|
// P #P list of point handle indices
|
|
// BE #BE by 2 list of bone-edge indices
|
|
// CE #CE by 2 list of cage-edge indices
|
|
// samples_per_bone #samples to add per bone
|
|
// tetgen_flags flags to pass to tetgen {""-->"pq2Y"} otherwise you're on
|
|
// your own and it's your funeral if you pass nonsense flags
|
|
// Outputs:
|
|
// VV #VV by 3 list of tet-mesh vertex positions
|
|
// TT #TT by 4 list of tetrahedra indices
|
|
// FF #FF by 3 list of surface triangle indices
|
|
// Returns true only on success
|
|
IGL_INLINE bool mesh_with_skeleton(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::VectorXi & /*P*/,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::MatrixXi & CE,
|
|
const int samples_per_bone,
|
|
const std::string & tetgen_flags,
|
|
Eigen::MatrixXd & VV,
|
|
Eigen::MatrixXi & TT,
|
|
Eigen::MatrixXi & FF);
|
|
// Wrapper using default tetgen_flags
|
|
IGL_INLINE bool mesh_with_skeleton(
|
|
const Eigen::MatrixXd & V,
|
|
const Eigen::MatrixXi & F,
|
|
const Eigen::MatrixXd & C,
|
|
const Eigen::VectorXi & /*P*/,
|
|
const Eigen::MatrixXi & BE,
|
|
const Eigen::MatrixXi & CE,
|
|
const int samples_per_bone,
|
|
Eigen::MatrixXd & VV,
|
|
Eigen::MatrixXi & TT,
|
|
Eigen::MatrixXi & FF);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "mesh_with_skeleton.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_tetgen_read_into_tetgenio = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TETGEN_READ_INTO_TETGENIO_H
|
|
#define IGL_TETGEN_READ_INTO_TETGENIO_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <string>
|
|
#ifndef TETLIBRARY
|
|
#define TETLIBRARY
|
|
#endif
|
|
#include "tetgen.h" // Defined tetgenio, REAL
|
|
|
|
namespace igl
|
|
{
|
|
namespace tetgen
|
|
{
|
|
// Read a mesh or point set into tetgenio (input object for calling tetgen).
|
|
// Many file formats are already supported by tetgen:
|
|
// .off
|
|
// .ply
|
|
// .node
|
|
// .ply
|
|
// .medit
|
|
// .vtk
|
|
// etc.
|
|
// Noteably it does not support .obj which is loaded by hand here (also
|
|
// demonstrating how to load points/faces programatically)
|
|
//
|
|
// If the file extension is not recognized the filename is assumed to be the
|
|
// basename of a collection describe a tetmesh, (of which at least the .node
|
|
// file must exist):
|
|
// [filename].node
|
|
// [filename].ele
|
|
// [filename].face
|
|
// [filename].edge
|
|
// [filename].vol
|
|
//
|
|
// Inputs:
|
|
// path path to file or basename to files
|
|
// Outputs:
|
|
// in tetgenio input object
|
|
// Returns true on success, false on error
|
|
IGL_INLINE bool read_into_tetgenio(const std::string & path, tetgenio & in);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "read_into_tetgenio.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_tetgen_tetgenio_to_tetmesh = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TETGEN_TETGENIO_TO_TETMESH_H
|
|
#define IGL_TETGEN_TETGENIO_TO_TETMESH_H
|
|
#include "../igl_inline.h"
|
|
|
|
#ifndef TETLIBRARY
|
|
#define TETLIBRARY
|
|
#endif
|
|
#include "tetgen.h" // Defined tetgenio, REAL
|
|
#include <vector>
|
|
#include <Eigen/Core>
|
|
namespace igl
|
|
{
|
|
namespace tetgen
|
|
{
|
|
// Extract a tetrahedral mesh from a tetgenio object
|
|
// Inputs:
|
|
// out tetgenio output object
|
|
// Outputs:
|
|
// V #V by 3 vertex position list
|
|
// T #T by 4 list of tetrahedra indices into V
|
|
// F #F by 3 list of marked facets
|
|
// Returns true on success, false on error
|
|
IGL_INLINE bool tetgenio_to_tetmesh(
|
|
const tetgenio & out,
|
|
std::vector<std::vector<REAL > > & V,
|
|
std::vector<std::vector<int> > & T,
|
|
std::vector<std::vector<int> > & F);
|
|
IGL_INLINE bool tetgenio_to_tetmesh(
|
|
const tetgenio & out,
|
|
std::vector<std::vector<REAL > > & V,
|
|
std::vector<std::vector<int> > & T);
|
|
|
|
// Wrapper with Eigen types
|
|
// Templates:
|
|
// DerivedV real-value: i.e. from MatrixXd
|
|
// DerivedT integer-value: i.e. from MatrixXi
|
|
template <typename DerivedV, typename DerivedT, typename DerivedF>
|
|
IGL_INLINE bool tetgenio_to_tetmesh(
|
|
const tetgenio & out,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedT>& T,
|
|
Eigen::PlainObjectBase<DerivedF>& F);
|
|
template <typename DerivedV, typename DerivedT>
|
|
IGL_INLINE bool tetgenio_to_tetmesh(
|
|
const tetgenio & out,
|
|
Eigen::PlainObjectBase<DerivedV>& V,
|
|
Eigen::PlainObjectBase<DerivedT>& T);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "tetgenio_to_tetmesh.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_tetgen_tetrahedralize = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TETGEN_TETRAHEDRALIZE_H
|
|
#define IGL_TETGEN_TETRAHEDRALIZE_H
|
|
#include "../igl_inline.h"
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <Eigen/Core>
|
|
#ifndef TETLIBRARY
|
|
#define TETLIBRARY
|
|
#endif
|
|
#include "tetgen.h" // Defined REAL
|
|
|
|
namespace igl
|
|
{
|
|
namespace tetgen
|
|
{
|
|
// Mesh the interior of a surface mesh (V,F) using tetgen
|
|
//
|
|
// Inputs:
|
|
// V #V by 3 vertex position list
|
|
// F #F list of polygon face indices into V (0-indexed)
|
|
// switches string of tetgen options (See tetgen documentation) e.g.
|
|
// "pq1.414a0.01" tries to mesh the interior of a given surface with
|
|
// quality and area constraints
|
|
// "" will mesh the convex hull constrained to pass through V (ignores F)
|
|
// Outputs:
|
|
// TV #V by 3 vertex position list
|
|
// TT #T by 4 list of tet face indices
|
|
// TF #F by 3 list of trianlge face indices
|
|
// Returns status:
|
|
// 0 success
|
|
// 1 tetgen threw exception
|
|
// 2 tetgen did not crash but could not create any tets (probably there are
|
|
// holes, duplicate faces etc.)
|
|
// -1 other error
|
|
IGL_INLINE int tetrahedralize(
|
|
const std::vector<std::vector<REAL > > & V,
|
|
const std::vector<std::vector<int> > & F,
|
|
const std::string switches,
|
|
std::vector<std::vector<REAL > > & TV,
|
|
std::vector<std::vector<int > > & TT,
|
|
std::vector<std::vector<int> > & TF);
|
|
|
|
// Wrapper with Eigen types
|
|
// Templates:
|
|
// DerivedV real-value: i.e. from MatrixXd
|
|
// DerivedF integer-value: i.e. from MatrixXi
|
|
template <
|
|
typename DerivedV,
|
|
typename DerivedF,
|
|
typename DerivedTV,
|
|
typename DerivedTT,
|
|
typename DerivedTF>
|
|
IGL_INLINE int tetrahedralize(
|
|
const Eigen::PlainObjectBase<DerivedV>& V,
|
|
const Eigen::PlainObjectBase<DerivedF>& F,
|
|
const std::string switches,
|
|
Eigen::PlainObjectBase<DerivedTV>& TV,
|
|
Eigen::PlainObjectBase<DerivedTT>& TT,
|
|
Eigen::PlainObjectBase<DerivedTF>& TF);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "tetrahedralize.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_triangle_triangulate = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_TRIANGLE_TRIANGULATE_H
|
|
#define IGL_TRIANGLE_TRIANGULATE_H
|
|
#include <igl/igl_inline.h>
|
|
#include <string>
|
|
#include <Eigen/Core>
|
|
|
|
namespace igl
|
|
{
|
|
namespace triangle
|
|
{
|
|
// Triangulate the interior of a polygon using the triangle library.
|
|
//
|
|
// Inputs:
|
|
// V #V by 2 list of 2D vertex positions
|
|
// E #E by 2 list of vertex ids forming unoriented edges of the boundary of the polygon
|
|
// H #H by 2 coordinates of points contained inside holes of the polygon
|
|
// flags string of options pass to triangle (see triangle documentation)
|
|
// Outputs:
|
|
// V2 #V2 by 2 coordinates of the vertives of the generated triangulation
|
|
// F2 #F2 by 3 list of indices forming the faces of the generated triangulation
|
|
//
|
|
// TODO: expose the option to prevent Steiner points on the boundary
|
|
//
|
|
IGL_INLINE void triangulate(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& E,
|
|
const Eigen::MatrixXd& H,
|
|
const std::string flags,
|
|
Eigen::MatrixXd& V2,
|
|
Eigen::MatrixXi& F2);
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "triangulate.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_OpenGL_shader = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Wenzel Jacob <wenzel@inf.ethz.ch>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_VIEWER_OPENGL_SHADER_H
|
|
#define IGL_VIEWER_OPENGL_SHADER_H
|
|
|
|
#include <igl/igl_inline.h>
|
|
#include <string>
|
|
#include <Eigen/Core>
|
|
|
|
#ifdef _WIN32
|
|
# include <windows.h>
|
|
# undef max
|
|
# undef min
|
|
# undef DrawText
|
|
#endif
|
|
|
|
#ifndef __APPLE__
|
|
# define GLEW_STATIC
|
|
# include <GL/glew.h>
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
# include <OpenGL/gl3.h>
|
|
# define __gl_h_ /* Prevent inclusion of the old gl.h */
|
|
#else
|
|
# ifdef _WIN32
|
|
# include <windows.h>
|
|
# endif
|
|
# include <GL/gl.h>
|
|
#endif
|
|
|
|
namespace igl
|
|
{
|
|
namespace viewer
|
|
{
|
|
|
|
// This class wraps an OpenGL program composed of three shaders
|
|
// TODO: write documentation
|
|
|
|
class OpenGL_shader
|
|
{
|
|
public:
|
|
typedef unsigned int GLuint;
|
|
typedef int GLint;
|
|
|
|
GLuint vertex_shader;
|
|
GLuint fragment_shader;
|
|
GLuint geometry_shader;
|
|
GLuint program_shader;
|
|
|
|
IGL_INLINE OpenGL_shader() : vertex_shader(0), fragment_shader(0),
|
|
geometry_shader(0), program_shader(0) { }
|
|
|
|
// Create a new shader from the specified source strings
|
|
IGL_INLINE bool init(const std::string &vertex_shader_string,
|
|
const std::string &fragment_shader_string,
|
|
const std::string &fragment_data_name,
|
|
const std::string &geometry_shader_string = "",
|
|
int geometry_shader_max_vertices = 3);
|
|
|
|
// Create a new shader from the specified files on disk
|
|
IGL_INLINE bool init_from_files(const std::string &vertex_shader_filename,
|
|
const std::string &fragment_shader_filename,
|
|
const std::string &fragment_data_name,
|
|
const std::string &geometry_shader_filename = "",
|
|
int geometry_shader_max_vertices = 3);
|
|
|
|
// Select this shader for subsequent draw calls
|
|
IGL_INLINE void bind();
|
|
|
|
// Release all OpenGL objects
|
|
IGL_INLINE void free();
|
|
|
|
// Return the OpenGL handle of a named shader attribute (-1 if it does not exist)
|
|
IGL_INLINE GLint attrib(const std::string &name) const;
|
|
|
|
// Return the OpenGL handle of a uniform attribute (-1 if it does not exist)
|
|
IGL_INLINE GLint uniform(const std::string &name) const;
|
|
|
|
// Bind a per-vertex array attribute and refresh its contents from an Eigen amtrix
|
|
IGL_INLINE GLint bindVertexAttribArray(const std::string &name, GLuint bufferID,
|
|
const Eigen::MatrixXf &M, bool refresh) const;
|
|
|
|
IGL_INLINE GLuint create_shader_helper(GLint type, const std::string &shader_string);
|
|
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "OpenGL_shader.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_OpenGL_state = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VIEWER_OPENGL_STATE_H
|
|
#define IGL_VIEWER_OPENGL_STATE_H
|
|
|
|
// Coverts mesh data inside a igl::viewer::ViewerData class in an OpenGL compatible format
|
|
// The class includes a shader and the opengl calls to plot the data
|
|
|
|
#include <igl/igl_inline.h>
|
|
#include <igl/viewer/OpenGL_shader.h>
|
|
#include <igl/viewer/ViewerData.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace viewer
|
|
{
|
|
|
|
class OpenGL_state
|
|
{
|
|
public:
|
|
typedef unsigned int GLuint;
|
|
|
|
GLuint vao_mesh;
|
|
GLuint vao_overlay_lines;
|
|
GLuint vao_overlay_points;
|
|
OpenGL_shader shader_mesh;
|
|
OpenGL_shader shader_overlay_lines;
|
|
OpenGL_shader shader_overlay_points;
|
|
|
|
GLuint vbo_V; // Vertices of the current mesh (#V x 3)
|
|
GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
|
|
GLuint vbo_V_normals; // Vertices of the current mesh (#V x 3)
|
|
GLuint vbo_V_ambient; // Ambient material (#V x 3)
|
|
GLuint vbo_V_diffuse; // Diffuse material (#V x 3)
|
|
GLuint vbo_V_specular; // Specular material (#V x 3)
|
|
|
|
GLuint vbo_F; // Faces of the mesh (#F x 3)
|
|
GLuint vbo_tex; // Texture
|
|
|
|
GLuint vbo_lines_F; // Indices of the line overlay
|
|
GLuint vbo_lines_V; // Vertices of the line overlay
|
|
GLuint vbo_lines_V_colors; // Color values of the line overlay
|
|
GLuint vbo_points_F; // Indices of the point overlay
|
|
GLuint vbo_points_V; // Vertices of the point overlay
|
|
GLuint vbo_points_V_colors; // Color values of the point overlay
|
|
|
|
// Temporary copy of the content of each VBO
|
|
Eigen::MatrixXf V_vbo;
|
|
Eigen::MatrixXf V_normals_vbo;
|
|
Eigen::MatrixXf V_ambient_vbo;
|
|
Eigen::MatrixXf V_diffuse_vbo;
|
|
Eigen::MatrixXf V_specular_vbo;
|
|
Eigen::MatrixXf V_uv_vbo;
|
|
Eigen::MatrixXf lines_V_vbo;
|
|
Eigen::MatrixXf lines_V_colors_vbo;
|
|
Eigen::MatrixXf points_V_vbo;
|
|
Eigen::MatrixXf points_V_colors_vbo;
|
|
|
|
int tex_u;
|
|
int tex_v;
|
|
Eigen::Matrix<char,Eigen::Dynamic,1> tex;
|
|
|
|
Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> F_vbo;
|
|
Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> lines_F_vbo;
|
|
Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> points_F_vbo;
|
|
|
|
// Marks dirty buffers that need to be uploaded to OpenGL
|
|
uint32_t dirty;
|
|
|
|
// Initialize shaders and buffers
|
|
IGL_INLINE void init();
|
|
|
|
// Release all resources
|
|
IGL_INLINE void free();
|
|
|
|
// Create a new set of OpenGL buffer objects
|
|
IGL_INLINE void init_buffers();
|
|
|
|
// Update contents from a 'Data' instance
|
|
IGL_INLINE void set_data(const igl::viewer::ViewerData &data, bool invert_normals);
|
|
|
|
// Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
|
|
IGL_INLINE void bind_mesh();
|
|
|
|
/// Draw the currently buffered mesh (either solid or wireframe)
|
|
IGL_INLINE void draw_mesh(bool solid);
|
|
|
|
// Bind the underlying OpenGL buffer objects for subsequent line overlay draw calls
|
|
IGL_INLINE void bind_overlay_lines();
|
|
|
|
/// Draw the currently buffered line overlay
|
|
IGL_INLINE void draw_overlay_lines();
|
|
|
|
// Bind the underlying OpenGL buffer objects for subsequent point overlay draw calls
|
|
IGL_INLINE void bind_overlay_points();
|
|
|
|
/// Draw the currently buffered point overlay
|
|
IGL_INLINE void draw_overlay_points();
|
|
|
|
// Release the OpenGL buffer objects
|
|
IGL_INLINE void free_buffers();
|
|
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "OpenGL_state.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_TextRenderer = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Wenzel Jacob <wenzel@inf.ethz.ch>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VIEWER_TEXT_RENDERER_H
|
|
#define IGL_VIEWER_TEXT_RENDERER_H
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
#include <igl/igl_inline.h>
|
|
#include <map>
|
|
|
|
struct NVGcontext;
|
|
|
|
namespace igl
|
|
{
|
|
namespace viewer
|
|
{
|
|
|
|
class TextRenderer
|
|
{
|
|
public:
|
|
IGL_INLINE TextRenderer();
|
|
|
|
IGL_INLINE virtual int Init();
|
|
IGL_INLINE virtual int Shut();
|
|
|
|
IGL_INLINE void BeginDraw(const Eigen::Matrix4f &view,const Eigen::Matrix4f &proj,
|
|
const Eigen::Vector4f &_viewport,float _object_scale);
|
|
|
|
IGL_INLINE void EndDraw();
|
|
|
|
IGL_INLINE void DrawText(Eigen::Vector3d pos,Eigen::Vector3d normal,const std::string &text);
|
|
|
|
protected:
|
|
std::map<std::string,void *> m_textObjects;
|
|
Eigen::Matrix4f view_matrix,proj_matrix;
|
|
Eigen::Vector4f viewport;
|
|
float object_scale;
|
|
float mPixelRatio;
|
|
NVGcontext *ctx;
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "TextRenderer.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_TextRenderer_fonts = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Wenzel Jacob <wenzel@inf.ethz.ch>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#ifndef IGL_TEXT_RENDERER_FONTS_H
|
|
#define IGL_TEXT_RENDERER_FONTS_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
namespace
|
|
{
|
|
#endif
|
|
extern uint8_t igl_entypo_ttf[];
|
|
extern uint32_t igl_entypo_ttf_size;
|
|
|
|
extern uint8_t igl_roboto_bold_ttf[];
|
|
extern uint32_t igl_roboto_bold_ttf_size;
|
|
|
|
extern uint8_t igl_roboto_regular_ttf[];
|
|
extern uint32_t igl_roboto_regular_ttf_size;
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
}
|
|
#endif
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
namespace
|
|
{
|
|
#include "TextRenderer_fonts.cpp"
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_Viewer = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VIEWER_VIEWER_H
|
|
#define IGL_VIEWER_VIEWER_H
|
|
|
|
#ifndef IGL_OPENGL_4
|
|
#define IGL_OPENGL_4
|
|
#endif
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <cstdint>
|
|
|
|
#include <Eigen/Core>
|
|
#include <Eigen/Geometry>
|
|
|
|
#include <igl/igl_inline.h>
|
|
|
|
#include "OpenGL_shader.h"
|
|
#include "OpenGL_state.h"
|
|
#include "ViewerCore.h"
|
|
#include "ViewerData.h"
|
|
#include "ViewerPlugin.h"
|
|
|
|
#define IGL_MOD_SHIFT 0x0001
|
|
#define IGL_MOD_CONTROL 0x0002
|
|
#define IGL_MOD_ALT 0x0004
|
|
#define IGL_MOD_SUPER 0x0008
|
|
|
|
namespace nanogui { class FormScreen; }
|
|
|
|
namespace igl
|
|
{
|
|
namespace viewer
|
|
{
|
|
// GLFW-based mesh viewer
|
|
class Viewer
|
|
{
|
|
public:
|
|
|
|
IGL_INLINE int launch(bool resizable = true,bool fullscreen = false);
|
|
IGL_INLINE void init();
|
|
|
|
// Stores all the viewing options
|
|
ViewerCore core;
|
|
|
|
// Stores all the data that should be visualized
|
|
ViewerData data;
|
|
|
|
// Stores the vbos indices and opengl related settings
|
|
OpenGL_state opengl;
|
|
|
|
// List of registered plugins
|
|
std::vector<ViewerPlugin*> plugins;
|
|
IGL_INLINE void init_plugins();
|
|
IGL_INLINE void shutdown_plugins();
|
|
|
|
// Temporary data stored when the mouse button is pressed
|
|
Eigen::Quaternionf down_rotation;
|
|
int current_mouse_x;
|
|
int current_mouse_y;
|
|
int down_mouse_x;
|
|
int down_mouse_y;
|
|
float down_mouse_z;
|
|
Eigen::Vector3f down_translation;
|
|
bool down;
|
|
bool hack_never_moved;
|
|
|
|
nanogui::FormScreen* ngui;
|
|
|
|
// Keep track of the global position of the scrollwheel
|
|
float scroll_position;
|
|
|
|
// UI Enumerations
|
|
enum class MouseButton {Left, Middle, Right};
|
|
enum class MouseMode { None, Rotation, Zoom, Pan, Translation} mouse_mode;
|
|
|
|
Viewer();
|
|
~Viewer();
|
|
|
|
// Mesh IO
|
|
IGL_INLINE bool load_mesh_from_file(const char* mesh_file_name);
|
|
IGL_INLINE bool save_mesh_to_file(const char* mesh_file_name);
|
|
|
|
// Callbacks
|
|
IGL_INLINE bool key_pressed(unsigned int unicode_key,int modifier);
|
|
IGL_INLINE bool key_down(int key,int modifier);
|
|
IGL_INLINE bool key_up(int key,int modifier);
|
|
|
|
IGL_INLINE bool mouse_down(MouseButton button,int modifier);
|
|
IGL_INLINE bool mouse_up(MouseButton button,int modifier);
|
|
|
|
IGL_INLINE bool mouse_move(int mouse_x,int mouse_y);
|
|
IGL_INLINE bool mouse_scroll(float delta_y);
|
|
|
|
// Scene IO
|
|
IGL_INLINE bool load_scene();
|
|
IGL_INLINE bool load_scene(std::string fname);
|
|
IGL_INLINE bool save_scene();
|
|
|
|
// Draw everything
|
|
IGL_INLINE void draw();
|
|
|
|
// OpenGL context resize
|
|
IGL_INLINE void resize(int w,int h);
|
|
|
|
// Helper functions
|
|
IGL_INLINE void snap_to_canonical_quaternion();
|
|
IGL_INLINE void open_dialog_load_mesh();
|
|
IGL_INLINE void open_dialog_save_mesh();
|
|
|
|
// C++-style functions
|
|
std::function<bool(Viewer& viewer)> callback_init;
|
|
std::function<bool(Viewer& viewer)> callback_pre_draw;
|
|
std::function<bool(Viewer& viewer)> callback_post_draw;
|
|
std::function<bool(Viewer& viewer, int button, int modifier)> callback_mouse_down;
|
|
std::function<bool(Viewer& viewer, int button, int modifier)> callback_mouse_up;
|
|
std::function<bool(Viewer& viewer, int mouse_x, int mouse_y)> callback_mouse_move;
|
|
std::function<bool(Viewer& viewer, float delta_y)> callback_mouse_scroll;
|
|
std::function<bool(Viewer& viewer, unsigned int key, int modifiers)> callback_key_pressed;
|
|
// THESE SHOULD BE DEPRECATED:
|
|
std::function<bool(Viewer& viewer, unsigned char key, int modifiers)> callback_key_down;
|
|
std::function<bool(Viewer& viewer, unsigned char key, int modifiers)> callback_key_up;
|
|
|
|
// Pointers to per-callback data
|
|
void* callback_init_data;
|
|
void* callback_pre_draw_data;
|
|
void* callback_post_draw_data;
|
|
void* callback_mouse_down_data;
|
|
void* callback_mouse_up_data;
|
|
void* callback_mouse_move_data;
|
|
void* callback_mouse_scroll_data;
|
|
void* callback_key_pressed_data;
|
|
void* callback_key_down_data;
|
|
void* callback_key_up_data;
|
|
|
|
public:
|
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
|
};
|
|
|
|
} // end namespace
|
|
} // end namespace
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "Viewer.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_ViewerCore = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VIEWER_VIEWER_CORE_H
|
|
#define IGL_VIEWER_VIEWER_CORE_H
|
|
|
|
#include <igl/viewer/TextRenderer.h>
|
|
#include <igl/viewer/ViewerData.h>
|
|
#include <igl/viewer/OpenGL_state.h>
|
|
|
|
#include <igl/igl_inline.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace viewer
|
|
{
|
|
|
|
// Basic class of the 3D mesh viewer
|
|
// TODO: write documentation
|
|
|
|
class ViewerCore
|
|
{
|
|
public:
|
|
IGL_INLINE ViewerCore();
|
|
|
|
// Initialization
|
|
IGL_INLINE void init();
|
|
|
|
// Shutdown
|
|
IGL_INLINE void shut();
|
|
|
|
// Serialization code
|
|
IGL_INLINE void InitSerialization();
|
|
|
|
|
|
// ------------------- Camera control functions
|
|
|
|
// Adjust the view to see the entire model
|
|
IGL_INLINE void align_camera_center(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F);
|
|
|
|
// Determines how much to zoom and shift such that the mesh fills the unit
|
|
// box (centered at the origin)
|
|
IGL_INLINE void get_scale_and_shift_to_fit_mesh(
|
|
const Eigen::MatrixXd& V,
|
|
const Eigen::MatrixXi& F,
|
|
float & zoom,
|
|
Eigen::Vector3f& shift);
|
|
|
|
// Adjust the view to see the entire model
|
|
IGL_INLINE void align_camera_center(
|
|
const Eigen::MatrixXd& V);
|
|
|
|
// Determines how much to zoom and shift such that the mesh fills the unit
|
|
// box (centered at the origin)
|
|
IGL_INLINE void get_scale_and_shift_to_fit_mesh(
|
|
const Eigen::MatrixXd& V,
|
|
float & zoom,
|
|
Eigen::Vector3f& shift);
|
|
|
|
// ------------------- Drawing functions
|
|
|
|
// Clear the frame buffers
|
|
IGL_INLINE void clear_framebuffers();
|
|
|
|
// Draw everything
|
|
IGL_INLINE void draw(ViewerData& data, OpenGL_state& opengl, bool update_matrices = true);
|
|
IGL_INLINE void draw_buffer(ViewerData& data,
|
|
OpenGL_state& opengl,
|
|
bool update_matrices,
|
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
|
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A);
|
|
|
|
// ------------------- Properties
|
|
|
|
// Text rendering helper
|
|
TextRenderer textrenderer;
|
|
|
|
// Shape material
|
|
float shininess;
|
|
|
|
// Colors
|
|
Eigen::Vector3f background_color;
|
|
Eigen::Vector3f line_color;
|
|
|
|
// Lighting
|
|
Eigen::Vector3f light_position;
|
|
float lighting_factor;
|
|
|
|
// Trackball angle (quaternion)
|
|
enum RotationType
|
|
{
|
|
ROTATION_TYPE_TRACKBALL = 0,
|
|
ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
|
|
NUM_ROTATION_TYPES = 2
|
|
} rotation_type;
|
|
Eigen::Quaternionf trackball_angle;
|
|
|
|
// Model viewing parameters
|
|
float model_zoom;
|
|
Eigen::Vector3f model_translation;
|
|
|
|
// Model viewing paramters (uv coordinates)
|
|
float model_zoom_uv;
|
|
Eigen::Vector3f model_translation_uv;
|
|
|
|
// Camera parameters
|
|
float camera_zoom;
|
|
bool orthographic;
|
|
Eigen::Vector3f camera_eye;
|
|
Eigen::Vector3f camera_up;
|
|
Eigen::Vector3f camera_center;
|
|
float camera_view_angle;
|
|
float camera_dnear;
|
|
float camera_dfar;
|
|
|
|
// Visualization options
|
|
bool show_overlay;
|
|
bool show_overlay_depth;
|
|
bool show_texture;
|
|
bool show_faces;
|
|
bool show_lines;
|
|
bool show_vertid;
|
|
bool show_faceid;
|
|
bool invert_normals;
|
|
bool depth_test;
|
|
|
|
// Point size / line width
|
|
float point_size;
|
|
float line_width;
|
|
|
|
// Animation
|
|
bool is_animating;
|
|
double animation_max_fps;
|
|
|
|
// Caches the two-norm between the min/max point of the bounding box
|
|
float object_scale;
|
|
|
|
// Viewport size
|
|
Eigen::Vector4f viewport;
|
|
|
|
// Save the OpenGL transformation matrices used for the previous rendering pass
|
|
Eigen::Matrix4f view;
|
|
Eigen::Matrix4f model;
|
|
Eigen::Matrix4f proj;
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "ViewerCore.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_ViewerData = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VIEWER_VIEWER_DATA_H
|
|
#define IGL_VIEWER_VIEWER_DATA_H
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
#include <Eigen/Core>
|
|
|
|
#include <igl/igl_inline.h>
|
|
|
|
namespace igl
|
|
{
|
|
namespace viewer
|
|
{
|
|
|
|
// TODO: write documentation
|
|
|
|
class ViewerData
|
|
{
|
|
public:
|
|
ViewerData();
|
|
|
|
enum DirtyFlags
|
|
{
|
|
DIRTY_NONE = 0x0000,
|
|
DIRTY_POSITION = 0x0001,
|
|
DIRTY_UV = 0x0002,
|
|
DIRTY_NORMAL = 0x0004,
|
|
DIRTY_AMBIENT = 0x0008,
|
|
DIRTY_DIFFUSE = 0x0010,
|
|
DIRTY_SPECULAR = 0x0020,
|
|
DIRTY_TEXTURE = 0x0040,
|
|
DIRTY_FACE = 0x0080,
|
|
DIRTY_MESH = 0x00FF,
|
|
DIRTY_OVERLAY_LINES = 0x0100,
|
|
DIRTY_OVERLAY_POINTS = 0x0200,
|
|
DIRTY_ALL = 0x03FF
|
|
};
|
|
|
|
// Empy all fields
|
|
IGL_INLINE void clear();
|
|
|
|
// Change the visualization mode, invalidating the cache if necessary
|
|
IGL_INLINE void set_face_based(bool newvalue);
|
|
|
|
// Helpers that can draw the most common meshes
|
|
IGL_INLINE void set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
|
|
IGL_INLINE void set_vertices(const Eigen::MatrixXd& V);
|
|
IGL_INLINE void set_normals(const Eigen::MatrixXd& N);
|
|
|
|
// Set the color of the mesh
|
|
//
|
|
// Inputs:
|
|
// C #V|#F|1 by 3 list of colors
|
|
IGL_INLINE void set_colors(const Eigen::MatrixXd &C);
|
|
IGL_INLINE void set_uv(const Eigen::MatrixXd& UV);
|
|
IGL_INLINE void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
|
|
IGL_INLINE void set_texture(
|
|
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
|
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
|
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B);
|
|
|
|
// Sets points given a list of point vertices. In constrast to `set_points`
|
|
// this will (purposefully) clober existing points.
|
|
//
|
|
// Inputs:
|
|
// P #P by 3 list of vertex positions
|
|
// C #P|1 by 3 color(s)
|
|
IGL_INLINE void set_points(
|
|
const Eigen::MatrixXd& P,
|
|
const Eigen::MatrixXd& C);
|
|
IGL_INLINE void add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C);
|
|
// Sets edges given a list of edge vertices and edge indices. In constrast
|
|
// to `add_edges` this will (purposefully) clober existing edges.
|
|
//
|
|
// Inputs:
|
|
// P #P by 3 list of vertex positions
|
|
// E #E by 2 list of edge indices into P
|
|
// C #E|1 by 3 color(s)
|
|
IGL_INLINE void set_edges (const Eigen::MatrixXd& P, const Eigen::MatrixXi& E, const Eigen::MatrixXd& C);
|
|
IGL_INLINE void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
|
|
IGL_INLINE void add_label (const Eigen::VectorXd& P, const std::string& str);
|
|
|
|
// Computes the normals of the mesh
|
|
IGL_INLINE void compute_normals();
|
|
|
|
// Assigns uniform colors to all faces/vertices
|
|
IGL_INLINE void uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular);
|
|
|
|
// Generates a default grid texture
|
|
IGL_INLINE void grid_texture();
|
|
|
|
Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
|
|
Eigen::MatrixXi F; // Faces of the mesh (#F x 3)
|
|
|
|
// Per face attributes
|
|
Eigen::MatrixXd F_normals; // One normal per face
|
|
|
|
Eigen::MatrixXd F_material_ambient; // Per face ambient color
|
|
Eigen::MatrixXd F_material_diffuse; // Per face diffuse color
|
|
Eigen::MatrixXd F_material_specular; // Per face specular color
|
|
|
|
// Per vertex attributes
|
|
Eigen::MatrixXd V_normals; // One normal per vertex
|
|
|
|
Eigen::MatrixXd V_material_ambient; // Per vertex ambient color
|
|
Eigen::MatrixXd V_material_diffuse; // Per vertex diffuse color
|
|
Eigen::MatrixXd V_material_specular; // Per vertex specular color
|
|
|
|
// UV parametrization
|
|
Eigen::MatrixXd V_uv; // UV vertices
|
|
Eigen::MatrixXi F_uv; // optional faces for UVs
|
|
|
|
// Texture
|
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_R;
|
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_G;
|
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_B;
|
|
|
|
// Overlays
|
|
|
|
// Lines plotted over the scene
|
|
// (Every row contains 9 doubles in the following format S_x, S_y, S_z, T_x, T_y, T_z, C_r, C_g, C_b),
|
|
// with S and T the coordinates of the two vertices of the line in global coordinates, and C the color in floating point rgb format
|
|
Eigen::MatrixXd lines;
|
|
|
|
// Points plotted over the scene
|
|
// (Every row contains 6 doubles in the following format P_x, P_y, P_z, C_r, C_g, C_b),
|
|
// with P the position in global coordinates of the center of the point, and C the color in floating point rgb format
|
|
Eigen::MatrixXd points;
|
|
|
|
// Text labels plotted over the scene
|
|
// Textp contains, in the i-th row, the position in global coordinates where the i-th label should be anchored
|
|
// Texts contains in the i-th position the text of the i-th label
|
|
Eigen::MatrixXd labels_positions;
|
|
std::vector<std::string> labels_strings;
|
|
|
|
// Marks dirty buffers that need to be uploaded to OpenGL
|
|
uint32_t dirty;
|
|
|
|
// Enable per-face or per-vertex properties
|
|
bool face_based;
|
|
/*********************************/
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
# include "ViewerData.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_viewer_ViewerPlugin = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_VIEWER_VIEWER_PLUGIN_H
|
|
#define IGL_VIEWER_VIEWER_PLUGIN_H
|
|
|
|
// TODO:
|
|
// * create plugins/skeleton.h
|
|
// * pass time in draw function
|
|
// * remove Preview3D from comments
|
|
// * clean comments
|
|
#include <string>
|
|
#include <igl/igl_inline.h>
|
|
#include <vector>
|
|
|
|
namespace igl
|
|
{
|
|
namespace viewer
|
|
{
|
|
|
|
// Abstract class for plugins
|
|
// All plugins MUST have this class as their parent and may implement any/all
|
|
// the callbacks marked `virtual` here.
|
|
//
|
|
// /////For an example of a basic plugins see plugins/skeleton.h
|
|
//
|
|
// Return value of callbacks: returning true to any of the callbacks tells
|
|
// Viewer that the event has been handled and that it should not be passed to
|
|
// other plugins or to other internal functions of Viewer
|
|
|
|
// Forward declaration of the viewer
|
|
class Viewer;
|
|
|
|
class ViewerPlugin
|
|
{
|
|
public:
|
|
IGL_INLINE ViewerPlugin()
|
|
{plugin_name = "dummy";}
|
|
|
|
virtual ~ViewerPlugin(){}
|
|
|
|
// This function is called when the viewer is initialized (no mesh will be loaded at this stage)
|
|
IGL_INLINE virtual void init(Viewer *_viewer)
|
|
{
|
|
viewer = _viewer;
|
|
}
|
|
|
|
// This function is called before shutdown
|
|
IGL_INLINE virtual void shutdown()
|
|
{
|
|
}
|
|
|
|
// This function is called before a mesh is loaded
|
|
IGL_INLINE virtual bool load(std::string filename)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called before a mesh is saved
|
|
IGL_INLINE virtual bool save(std::string filename)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called when the scene is serialized
|
|
IGL_INLINE virtual bool serialize(std::vector<char>& buffer) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called when the scene is deserialized
|
|
IGL_INLINE virtual bool deserialize(const std::vector<char>& buffer)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Runs immediately after a new mesh has been loaded.
|
|
IGL_INLINE virtual bool post_load()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called before the draw procedure of Preview3D
|
|
IGL_INLINE virtual bool pre_draw()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called after the draw procedure of Preview3D
|
|
IGL_INLINE virtual bool post_draw()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called when the mouse button is pressed
|
|
// - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
|
|
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
|
IGL_INLINE virtual bool mouse_down(int button, int modifier)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called when the mouse button is released
|
|
// - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
|
|
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
|
IGL_INLINE virtual bool mouse_up(int button, int modifier)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called every time the mouse is moved
|
|
// - mouse_x and mouse_y are the new coordinates of the mouse pointer in screen coordinates
|
|
IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called every time the scroll wheel is moved
|
|
// Note: this callback is not working with every glut implementation
|
|
IGL_INLINE virtual bool mouse_scroll(float delta_y)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called when a keyboard key is pressed. Unlike key_down
|
|
// this will reveal the actual character being sent (not just the physical
|
|
// key)
|
|
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
|
IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called when a keyboard key is down
|
|
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
|
IGL_INLINE virtual bool key_down(int key, int modifiers)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// This function is called when a keyboard key is release
|
|
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
|
IGL_INLINE virtual bool key_up(int key, int modifiers)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::string plugin_name;
|
|
protected:
|
|
// Pointer to the main Viewer class
|
|
Viewer *viewer;
|
|
};
|
|
|
|
#ifdef ENABLE_SERIALIZATION
|
|
namespace serialization
|
|
{
|
|
IGL_INLINE void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
|
|
{
|
|
obj.serialize(buffer);
|
|
}
|
|
|
|
IGL_INLINE void deserialize(ViewerPlugin& obj,const std::vector<char>& buffer)
|
|
{
|
|
obj.deserialize(buffer);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_xml_ReAntTweakBarXMLSerialization = R"igl_Qu8mg5v7(// This file is part of libigl, a simple c++ geometry processing library.
|
|
//
|
|
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_XML_REANTTWEAKBAR_XML_SERIALIZATION_H
|
|
#define IGL_XML_REANTTWEAKBAR_XML_SERIALIZATION_H
|
|
#include "../igl_inline.h"
|
|
#include "serialize_xml.h"
|
|
|
|
#undef IGL_HEADER_ONLY
|
|
#include "../anttweakbar/ReAntTweakBar.h"
|
|
|
|
// Forward declarations
|
|
namespace igl
|
|
{
|
|
namespace anttweakbar
|
|
{
|
|
class ReTwBar;
|
|
}
|
|
};
|
|
namespace tinyxml2
|
|
{
|
|
class XMLDocument;
|
|
};
|
|
|
|
namespace igl
|
|
{
|
|
namespace xml
|
|
{
|
|
|
|
// namespace
|
|
// {
|
|
|
|
// IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char* file_name);
|
|
// IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc);
|
|
// IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char *file_name);
|
|
// IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc);
|
|
|
|
|
|
IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char* file_name)
|
|
{
|
|
const char * name_chars = TwGetBarName(bar->bar);
|
|
std::string name = std::string(name_chars) + "_AntTweakBar";
|
|
|
|
const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
|
|
{
|
|
std::string val = bar->get_value_as_string(it->var,it->type);
|
|
//::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
|
|
::igl::serialize_xml(val,it->name,file_name,false,false);
|
|
}
|
|
|
|
char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
|
|
// Print all CB variables
|
|
const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
|
|
{
|
|
TwType type = it->type;
|
|
//TwSetVarCallback setCallback = it->setCallback;
|
|
TwGetVarCallback getCallback = it->getCallback;
|
|
void * clientData = it->clientData;
|
|
// I'm not sure how to do what I want to do. getCallback needs to be sure
|
|
// that it can write to var. So var needs to point to a valid and big
|
|
// enough chunk of memory
|
|
getCallback(var,clientData);
|
|
|
|
std::string val = bar->get_value_as_string(var,type);
|
|
//::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
|
|
::igl::serialize_xml(val,it->name,file_name,false,false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc)
|
|
{
|
|
std::vector<char**> buffer;
|
|
|
|
const char * name_chars = TwGetBarName(bar->bar);
|
|
std::string name = std::string(name_chars) + "_AntTweakBar";
|
|
::igl::XMLSerializer* s = new ::igl::XMLSerializer(name);
|
|
|
|
const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
|
|
{
|
|
std::string val = bar->get_value_as_string(it->var,it->type);
|
|
char** cval = new char*; // create char* on heap
|
|
*cval = new char[val.size()+1];
|
|
buffer.push_back(cval);
|
|
strcpy(*cval,val.c_str());
|
|
s->Add(*cval,it->name);
|
|
}
|
|
|
|
char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
|
|
// Print all CB variables
|
|
const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
|
|
{
|
|
TwType type = it->type;
|
|
//TwSetVarCallback setCallback = it->setCallback;
|
|
TwGetVarCallback getCallback = it->getCallback;
|
|
void * clientData = it->clientData;
|
|
// I'm not sure how to do what I want to do. getCallback needs to be sure
|
|
// that it can write to var. So var needs to point to a valid and big
|
|
// enough chunk of memory
|
|
getCallback(var,clientData);
|
|
|
|
std::string val = bar->get_value_as_string(var,type);
|
|
char** cval = new char*; // create char* on heap
|
|
*cval = new char[val.size()+1];
|
|
buffer.push_back(cval);
|
|
strcpy(*cval,val.c_str());
|
|
s->Add(*cval,it->name);
|
|
}
|
|
|
|
s->SaveToXMLDoc(name,doc);
|
|
|
|
// delete pointer buffers
|
|
for(unsigned int i=0;i<buffer.size();i++)
|
|
{
|
|
delete[] *buffer[i];
|
|
delete buffer[i];
|
|
}
|
|
|
|
delete s;
|
|
|
|
return true;
|
|
}*/
|
|
|
|
IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char *file_name)
|
|
{
|
|
char type_str[REANTTWEAKBAR_MAX_WORD];
|
|
char value_str[REANTTWEAKBAR_MAX_WORD];
|
|
TwType type;
|
|
|
|
const char * name_chars = TwGetBarName(bar->bar);
|
|
std::string name = std::string(name_chars) + "_AntTweakBar";
|
|
|
|
const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
|
|
{
|
|
char* val;
|
|
//::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
|
|
::igl::deserialize_xml(val,it->name,file_name);
|
|
sscanf(val,"%s %[^\n]",type_str,value_str);
|
|
|
|
if(!bar->type_from_string(type_str,type))
|
|
{
|
|
printf("ERROR: %s type not found... Skipping...\n",type_str);
|
|
continue;
|
|
}
|
|
|
|
bar->set_value_from_string(it->name.c_str(),type,value_str);
|
|
delete[] val;
|
|
}
|
|
|
|
const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
|
|
{
|
|
char* val;
|
|
//::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
|
|
::igl::deserialize_xml(val,it->name,file_name);
|
|
sscanf(val,"%s %[^\n]",type_str,value_str);
|
|
|
|
if(!bar->type_from_string(type_str,type))
|
|
{
|
|
printf("ERROR: %s type not found... Skipping...\n",type_str);
|
|
continue;
|
|
}
|
|
|
|
bar->set_value_from_string(it->name.c_str(),type,value_str);
|
|
delete[] val;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc)
|
|
{
|
|
std::map<std::string,char*> variables;
|
|
std::map<std::string,char*> cbVariables;
|
|
|
|
const char * name_chars = TwGetBarName(bar->bar);
|
|
std::string name = std::string(name_chars) + "_AntTweakBar";
|
|
::igl::XMLSerializer* s = new ::igl::XMLSerializer(name);
|
|
|
|
std::map<std::string,char*>::iterator iter;
|
|
const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
|
|
{
|
|
variables[it->name] = NULL;
|
|
iter = variables.find(it->name);
|
|
s->Add(iter->second,iter->first);
|
|
}
|
|
|
|
// Add all CB variables
|
|
const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
|
|
for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
|
|
{
|
|
cbVariables[it->name] = NULL;
|
|
iter = cbVariables.find(it->name);
|
|
s->Add(iter->second,iter->first);
|
|
}
|
|
|
|
s->LoadFromXMLDoc(doc);
|
|
|
|
// Set loaded values
|
|
char type_str[REANTTWEAKBAR_MAX_WORD];
|
|
char value_str[REANTTWEAKBAR_MAX_WORD];
|
|
TwType type;
|
|
|
|
for(iter = variables.begin(); iter != variables.end(); iter++)
|
|
{
|
|
if(iter->second == NULL)
|
|
{
|
|
printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str());
|
|
continue;
|
|
}
|
|
|
|
sscanf(iter->second,"%s %[^\n]",type_str,value_str);
|
|
|
|
if(!bar->type_from_string(type_str,type))
|
|
{
|
|
printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str());
|
|
continue;
|
|
}
|
|
|
|
bar->set_value_from_string(iter->first.c_str(),type,value_str);
|
|
}
|
|
|
|
for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
|
|
{
|
|
if(iter->second == NULL)
|
|
{
|
|
printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str());
|
|
continue;
|
|
}
|
|
|
|
sscanf(iter->second,"%s %[^\n]",type_str,value_str);
|
|
|
|
if(!bar->type_from_string(type_str,type))
|
|
{
|
|
printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str());
|
|
continue;
|
|
}
|
|
|
|
bar->set_value_from_string(iter->first.c_str(),type,value_str);
|
|
}
|
|
|
|
// delete buffers
|
|
for(iter = variables.begin(); iter != variables.end(); iter++)
|
|
delete[] iter->second;
|
|
|
|
for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
|
|
delete[] iter->second;
|
|
|
|
delete s;
|
|
|
|
return true;
|
|
}*/
|
|
|
|
// }
|
|
}
|
|
}
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|
|
const char *__doc_igl_xml_serialize_xml = R"igl_Qu8mg5v7(//
|
|
// Copyright (C) 2014 Christian Sch�ller <schuellchr@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License
|
|
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
// obtain one at http://mozilla.org/MPL/2.0/.
|
|
#ifndef IGL_XML_SERIALIZABLE_XML_H
|
|
#define IGL_XML_SERIALIZABLE_XML_H
|
|
// -----------------------------------------------------------------------------
|
|
// Functions to save and load a serialization of fundamental c++ data types to
|
|
// and from a xml file. STL containers, Eigen matrix types and nested data
|
|
// structures are also supported. To serialize a user defined class implement
|
|
// the interface XMLSerializable or XMLSerializableBase.
|
|
//
|
|
// See also: serialize.h
|
|
// -----------------------------------------------------------------------------
|
|
|
|
#include "../igl_inline.h"
|
|
|
|
#include <type_traits>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <map>
|
|
#include <memory>
|
|
|
|
#include <Eigen/Dense>
|
|
#include <Eigen/Sparse>
|
|
|
|
#include <igl/serialize.h>
|
|
|
|
#include "tinyxml2.h"
|
|
|
|
//#define SERIALIZE_XML(x) igl::xml::serialize_xml(x,#x,doc,element);
|
|
//#define DESERIALIZE_XML(x) igl::xml::deserialize_xml(x,#x,,doc,element);
|
|
|
|
namespace igl
|
|
{
|
|
namespace xml
|
|
{
|
|
// serializes the given object either to a xml file or to the provided doc data
|
|
//
|
|
// Templates:
|
|
// T type of the object to serialize
|
|
// Inputs:
|
|
// obj object to serialize
|
|
// objectName unique object name,used for the identification
|
|
// filename name of the file containing the serialization
|
|
// binary set to true to serialize the object in binary format (faster for big data)
|
|
// overwrite set to true to overwrite an existing xml file
|
|
// element tinyxml2 virtual representation of the current xml node
|
|
// Outputs:
|
|
// doc contains current tinyxml2 virtual representation of the xml data
|
|
//
|
|
template <typename T>
|
|
IGL_INLINE void serialize_xml(const T& obj,const std::string& filename);
|
|
template <typename T>
|
|
IGL_INLINE void serialize_xml(const T& obj,const std::string& objectName,const std::string& filename, bool binary = false,bool overwrite = false);
|
|
template <typename T>
|
|
IGL_INLINE void serialize_xml(const T& obj,const std::string& objectName,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,bool binary = false);
|
|
|
|
// deserializes the given data from a xml file or doc data back to the provided object
|
|
//
|
|
// Templates:
|
|
// T type of the object to serialize
|
|
// Inputs:
|
|
//
|
|
// objectName unique object name,used for the identification
|
|
// filename name of the file containing the serialization
|
|
// binary set to true to serialize the object in binary format (faster for big data)
|
|
// overwrite set to true to overwrite an existing xml file
|
|
// doc contains current tinyxml2 virtual representation of the xml data
|
|
// element tinyxml2 virtual representation of the current xml node
|
|
// Outputs:
|
|
// obj object to load back serialization to
|
|
//
|
|
template <typename T>
|
|
IGL_INLINE void deserialize_xml(T& obj,const std::string& filename);
|
|
template <typename T>
|
|
IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename);
|
|
template <typename T>
|
|
IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
|
|
|
|
// interface for user defined types
|
|
struct XMLSerializableBase : public SerializableBase
|
|
{
|
|
virtual void Serialize(std::vector<char>& buffer) const = 0;
|
|
virtual void Deserialize(const std::vector<char>& buffer) = 0;
|
|
virtual void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const = 0;
|
|
virtual void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) = 0;
|
|
};
|
|
|
|
// Convenient interface for user defined types
|
|
class XMLSerializable: public XMLSerializableBase
|
|
{
|
|
private:
|
|
|
|
template <typename T>
|
|
struct XMLSerializationObject: public XMLSerializableBase
|
|
{
|
|
bool Binary;
|
|
std::string Name;
|
|
T* Object;
|
|
|
|
void Serialize(std::vector<char>& buffer) const {
|
|
serialize(*Object,Name,buffer);
|
|
}
|
|
|
|
void Deserialize(const std::vector<char>& buffer) {
|
|
deserialize(*Object,Name,buffer);
|
|
}
|
|
|
|
void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const {
|
|
serialize_xml(*Object,Name,doc,element,Binary);
|
|
}
|
|
|
|
void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) {
|
|
deserialize_xml(*Object,Name,doc,element);
|
|
}
|
|
};
|
|
|
|
mutable bool initialized;
|
|
mutable std::vector<XMLSerializableBase*> objects;
|
|
|
|
public:
|
|
|
|
// Override this function to add your member variables which should be serialized
|
|
IGL_INLINE virtual void InitSerialization() = 0;
|
|
|
|
// Following functions can be overridden to handle the specific events.
|
|
// Return false to prevent the de-/serialization of an object.
|
|
IGL_INLINE virtual bool PreSerialization() const;
|
|
IGL_INLINE virtual void PostSerialization() const;
|
|
IGL_INLINE virtual bool PreDeserialization();
|
|
IGL_INLINE virtual void PostDeserialization();
|
|
|
|
// Default implementation of XMLSerializableBase interface
|
|
IGL_INLINE void Serialize(std::vector<char>& buffer) const;
|
|
IGL_INLINE void Deserialize(const std::vector<char>& buffer);
|
|
IGL_INLINE void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const;
|
|
IGL_INLINE void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
|
|
|
|
// Default constructor, destructor, assignment and copy constructor
|
|
IGL_INLINE XMLSerializable();
|
|
IGL_INLINE XMLSerializable(const XMLSerializable& obj);
|
|
IGL_INLINE ~XMLSerializable();
|
|
IGL_INLINE XMLSerializable& operator=(const XMLSerializable& obj);
|
|
|
|
// Use this function to add your variables which should be serialized
|
|
template <typename T>
|
|
IGL_INLINE void Add(T& obj,std::string name,bool binary = false);
|
|
};
|
|
|
|
// internal functions
|
|
namespace serialization_xml
|
|
{
|
|
// fundamental types
|
|
template <typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template <typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
// std::string
|
|
IGL_INLINE void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
IGL_INLINE void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
// XMLSerializableBase
|
|
template <typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template <typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
// STL containers
|
|
template <typename T1, typename T2>
|
|
IGL_INLINE void serialize(const std::pair<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template <typename T1,typename T2>
|
|
IGL_INLINE void deserialize(std::pair<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
template <typename T1,typename T2>
|
|
IGL_INLINE void serialize(const std::vector<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template <typename T1,typename T2>
|
|
IGL_INLINE void deserialize(std::vector<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
template <typename T>
|
|
IGL_INLINE void serialize(const std::set<T>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template <typename T>
|
|
IGL_INLINE void deserialize(std::set<T>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
template <typename T1,typename T2>
|
|
IGL_INLINE void serialize(const std::map<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template <typename T1,typename T2>
|
|
IGL_INLINE void deserialize(std::map<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
// Eigen types
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
IGL_INLINE void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template<typename T,int R,int C,int P,int MR,int MC>
|
|
IGL_INLINE void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
template<typename T,int P,typename I>
|
|
IGL_INLINE void serialize(const Eigen::SparseMatrix<T,P,I>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template<typename T,int P,typename I>
|
|
IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
// raw pointers
|
|
template <typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
template <typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
|
|
|
|
// helper functions
|
|
tinyxml2::XMLElement* getElement(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
|
|
IGL_INLINE void getAttribute(const char* src,bool& dest);
|
|
IGL_INLINE void getAttribute(const char* scr,char& dest);
|
|
IGL_INLINE void getAttribute(const char* src,std::string& dest);
|
|
IGL_INLINE void getAttribute(const char* src,float& dest);
|
|
IGL_INLINE void getAttribute(const char* src,double& dest);
|
|
template<typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest);
|
|
template<typename T>
|
|
IGL_INLINE typename std::enable_if<std::is_integral<T>::value && !std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest);
|
|
IGL_INLINE void replaceSubString(std::string& str,const std::string& search,const std::string& replace);
|
|
IGL_INLINE void encodeXMLElementName(std::string& name);
|
|
IGL_INLINE void decodeXMLElementName(std::string& name);
|
|
IGL_INLINE std::string base64_encode(unsigned char const* bytes_to_encode,unsigned int in_len);
|
|
IGL_INLINE std::string base64_decode(std::string const& encoded_string);
|
|
|
|
// compile time type serializable check
|
|
template <typename T>
|
|
struct is_stl_container { static const bool value = false; };
|
|
template <typename T1,typename T2>
|
|
struct is_stl_container<std::pair<T1,T2> > { static const bool value = true; };
|
|
template <typename T1,typename T2>
|
|
struct is_stl_container<std::vector<T1,T2> > { static const bool value = true; };
|
|
template <typename T>
|
|
struct is_stl_container<std::set<T> > { static const bool value = true; };
|
|
template <typename T1,typename T2>
|
|
struct is_stl_container<std::map<T1,T2> > { static const bool value = true; };
|
|
|
|
template <typename T>
|
|
struct is_eigen_type { static const bool value = false; };
|
|
template <typename T,int R,int C,int P,int MR,int MC>
|
|
struct is_eigen_type<Eigen::Matrix<T,R,C,P,MR,MC> > { static const bool value = true; };
|
|
template <typename T,int P,typename I>
|
|
struct is_eigen_type<Eigen::SparseMatrix<T,P,I> > { static const bool value = true; };
|
|
|
|
template <typename T>
|
|
struct is_serializable {
|
|
using T0 = typename std::remove_pointer<T>::type;
|
|
static const bool value = std::is_fundamental<T0>::value || std::is_same<std::string,T0>::value || std::is_base_of<XMLSerializableBase,T0>::value
|
|
|| is_stl_container<T0>::value || is_eigen_type<T0>::value;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef IGL_STATIC_LIBRARY
|
|
#include "serialize_xml.cpp"
|
|
#endif
|
|
|
|
#endif
|
|
)igl_Qu8mg5v7";
|