first version
This commit is contained in:
parent
240b88a582
commit
8e4a8e9b6e
|
@ -0,0 +1,295 @@
|
|||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2004 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __VCGLIB_ZONOHEDRON
|
||||
#define __VCGLIB_ZONOHEDRON
|
||||
|
||||
|
||||
#include<vcg/complex/allocate.h>
|
||||
#include<map>
|
||||
typedef unsigned int uint;
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
/** \addtogroup trimesh */
|
||||
//@{
|
||||
/**
|
||||
A class to build a Zonohedron.
|
||||
|
||||
A zonohedron is a solid with a closed surface composed only of parallelograms.
|
||||
Given a set of input vectors (the sides of the parallelograms), it is defined
|
||||
by the convex hull of all the points which can be co
|
||||
|
||||
Creates a pure-quad mesh (triangular bit-quad),
|
||||
(faces with 4 vertices are split into quads).
|
||||
|
||||
USAGE:
|
||||
1) Instantiate a Zonohedron.
|
||||
2) Add input vectors at will to it, with addVector(s)
|
||||
3) When you are done, call createMesh.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
template <class Scalar>
|
||||
class Zonohedron{
|
||||
public:
|
||||
|
||||
typedef Point3<Scalar> Vec3;
|
||||
|
||||
Zonohedron(){}
|
||||
|
||||
void addVector(Scalar x, Scalar y, Scalar z);
|
||||
void addVector(Vec3 v);
|
||||
void addVectors(const std::vector< Vec3 > );
|
||||
|
||||
const std::vector< Vec3 >& vectors() const {
|
||||
return vec;
|
||||
}
|
||||
|
||||
template<class MeshType>
|
||||
void createMesh( MeshType& output );
|
||||
|
||||
private:
|
||||
|
||||
/* classes for internal use */
|
||||
/****************************/
|
||||
|
||||
typedef int VecIndex; // a number in [0..n)
|
||||
|
||||
/* the signature of a vertex (a 0 or 1 per input vector) */
|
||||
struct Signature {
|
||||
std::vector< bool > v;
|
||||
Signature(){}
|
||||
Signature(int n){ v.resize(n,false); }
|
||||
|
||||
bool operator == (const Signature & b) const {
|
||||
return (b.v == v);
|
||||
}
|
||||
bool operator < (const Signature & b) const {
|
||||
return (b.v < v);
|
||||
}
|
||||
Signature& set(VecIndex i, bool value){
|
||||
v[i] = value;
|
||||
return *this;
|
||||
}
|
||||
Signature& set(VecIndex i, bool valueI, VecIndex j, bool valueJ){
|
||||
v[i] = valueI;
|
||||
v[j] = valueJ;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct Face {
|
||||
int vert[4]; // index to vertex array
|
||||
};
|
||||
|
||||
/* precomputed cross products for all pairs of vectors */
|
||||
std::vector< Vec3 > precomputedCross;
|
||||
|
||||
void precompteAllCrosses(){
|
||||
precomputedCross.resize(n*n);
|
||||
for (int i=0; i<n; i++) for (int j=0; j<n; j++) {
|
||||
precomputedCross[i*n+j] = vec[i] ^ vec[j] ;
|
||||
}
|
||||
}
|
||||
|
||||
Vec3 cross(VecIndex i, VecIndex j){
|
||||
return precomputedCross[i*n+j];
|
||||
}
|
||||
|
||||
// given a vector, returns a copy pointing a unique verse
|
||||
static Vec3 uniqueVerse(Vec3 v){
|
||||
if (v.X()>0) return v;
|
||||
else if (v.X()<0) return -v;
|
||||
else if (v.Y()>0) return v;
|
||||
else if (v.Y()<0) return -v;
|
||||
else if (v.Z()>0) return v;
|
||||
return -v;
|
||||
}
|
||||
|
||||
// returns signof: (i x j) * k
|
||||
bool signOf_IxJoK(VecIndex i, VecIndex j, VecIndex k){
|
||||
bool invert = false;
|
||||
// sort i,j,k
|
||||
if (i<j) { std::swap(i,j); invert = !invert; }
|
||||
if (j<k) { std::swap(j,k); invert = !invert;
|
||||
if (i<j) { std::swap(i,j); invert = !invert; }
|
||||
}
|
||||
|
||||
//Scalar res = Vec3::dot( Vec3::cross( vec[i] , vec[j] ) , vec[k] );
|
||||
Scalar res = cross( i , j ) * vec[k] ;
|
||||
|
||||
if (res==0) {
|
||||
// three coplanar vectors!
|
||||
res = uniqueVerse( cross(i,j) ) * cross(j,k) ;
|
||||
/*if (res==0) {
|
||||
printf("COLINEAR\n");
|
||||
// three colinear vectors!
|
||||
res = Vec3::dot( uniqueVerse(vec[i]) , vec[j])*
|
||||
Vec3::dot( uniqueVerse(vec[i]) , vec[k]);
|
||||
}*/
|
||||
}
|
||||
|
||||
return ( (res>=0) != invert ); // XOR
|
||||
}
|
||||
|
||||
int n; // number of input vectors
|
||||
std::vector<Vec3> vec; // input vectors
|
||||
|
||||
int vertCount;
|
||||
std::vector<Face> _face;
|
||||
|
||||
typedef std::map< Signature, int > VertexMap;
|
||||
VertexMap vertexMap;
|
||||
|
||||
// given a vertex signature, returns index of vert (newly created or not)
|
||||
VecIndex vertexIndex(const Signature &s){
|
||||
typename VertexMap::iterator i;
|
||||
//Vec3 pos = s; //toPos(s);
|
||||
i = vertexMap.find( s );
|
||||
if (i!= vertexMap.end() ) return i->second;
|
||||
else {
|
||||
int newVertex = vertCount++;
|
||||
//vertexMap.insert(s)
|
||||
vertexMap[s] = newVertex;
|
||||
return newVertex;
|
||||
}
|
||||
}
|
||||
|
||||
// given two index of vectors, returns face
|
||||
Face& face(VecIndex i, VecIndex j){
|
||||
assert(i!=j);
|
||||
assert( i*n + j < (int) _face.size() );
|
||||
return _face[i*n + j];
|
||||
}
|
||||
|
||||
Vec3 toPos(const Signature &s) const{
|
||||
Vec3 res(0,0,0);
|
||||
for (int i=0; i<n; i++)
|
||||
if (s.v[i]) res += vec[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
void createInternalMesh() {
|
||||
|
||||
n = vec.size();
|
||||
precompteAllCrosses();
|
||||
|
||||
// allocate faces
|
||||
_face.resize( n*n );
|
||||
|
||||
vertCount = 0;
|
||||
vertexMap.clear();
|
||||
|
||||
for (int i=0; i<n; i++) {
|
||||
//::showProgress(i,n);
|
||||
for (int j=0; j<n; j++) if(i!=j) {
|
||||
Signature s(n);
|
||||
for (int k=0; k<n; k++) if ((k!=j) && (k!=i))
|
||||
{
|
||||
s.set( k , signOf_IxJoK( i,j,k ) );
|
||||
}
|
||||
face(i,j).vert[0] = vertexIndex( s.set(i,false, j,false) );
|
||||
face(i,j).vert[1] = vertexIndex( s.set(i,false, j,true ) );
|
||||
face(i,j).vert[2] = vertexIndex( s.set(i,true, j,true ) );
|
||||
face(i,j).vert[3] = vertexIndex( s.set(i,true, j,false) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<class Scalar>
|
||||
void Zonohedron<Scalar>::addVectors(std::vector< Zonohedron<Scalar>::Vec3 > input){
|
||||
for (uint i=0; i<input.size(); i++) {
|
||||
addVector( input[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void Zonohedron<Scalar>::addVector(Scalar x, Scalar y, Scalar z) {
|
||||
addVector( Vec3(x,y,z) );
|
||||
}
|
||||
|
||||
|
||||
template<class Scalar>
|
||||
void Zonohedron<Scalar>::addVector(Zonohedron<Scalar>::Vec3 v){
|
||||
vec.push_back(v);
|
||||
}
|
||||
|
||||
|
||||
template<class Scalar>
|
||||
template<class MeshType>
|
||||
void Zonohedron<Scalar>::createMesh(MeshType &m){
|
||||
typedef MeshType Mesh;
|
||||
typedef typename Mesh::VertexPointer MeshVertexPointer;
|
||||
typedef typename Mesh::VertexIterator MeshVertexIterator;
|
||||
typedef typename Mesh::FaceIterator MeshFaceIterator;
|
||||
typedef typename Mesh::FaceType MeshFace;
|
||||
|
||||
createInternalMesh();
|
||||
|
||||
m.Clear();
|
||||
Allocator<MeshType>::AddVertices(m,vertexMap.size());
|
||||
Allocator<MeshType>::AddFaces(m,n*(n-1) * 2);
|
||||
|
||||
// assign vertex positions
|
||||
MeshVertexIterator vi=m.vert.begin();
|
||||
for (typename VertexMap::iterator i=vertexMap.begin(); i!=vertexMap.end(); i++){
|
||||
(vi + i->second )->P() = toPos( i->first );
|
||||
}
|
||||
|
||||
// assegn FV connectivity
|
||||
MeshFaceIterator fi=m.face.begin();
|
||||
|
||||
for (int i=0; i<n; i++) {
|
||||
for (int j=0; j<n; j++) if (i!=j) {
|
||||
const Face &f( face(i,j) );
|
||||
for (int k=0; k<2; k++) { // two tri faces per quad
|
||||
for (int w=0; w<3; w++) {
|
||||
fi->V(w) = &* (vi + f.vert[(w+k*2)%4] );
|
||||
}
|
||||
if (tri::HasPerFaceNormal(m)) {
|
||||
fi->N() = cross(i,j).normalized();
|
||||
}
|
||||
if (tri::HasPerFaceFlags(m)) {
|
||||
fi->SetF(2); // quad diagonals are faux
|
||||
}
|
||||
fi++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//@}
|
||||
|
||||
} // End Namespace TriMesh
|
||||
} // End Namespace vcg
|
||||
|
||||
#endif // __VCGLIB_ZONOHEDRON
|
Loading…
Reference in New Issue