You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
9.6 KiB
291 lines
9.6 KiB
/**************************************************************************** |
|
* VCGLib o o * |
|
* Visual and Computer Graphics Library o o * |
|
* _ O _ * |
|
* Copyright(C) 2004-2016 \/)\/ * |
|
* 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. * |
|
* * |
|
****************************************************************************/ |
|
/**************************************************************************** |
|
History |
|
|
|
$Log: gen_normal.h,v $ |
|
****************************************************************************/ |
|
|
|
#ifndef __VCG_GEN_NORMAL |
|
#define __VCG_GEN_NORMAL |
|
|
|
namespace vcg { |
|
|
|
template <class ScalarType> |
|
class GenNormal |
|
{ |
|
public: |
|
typedef Point3<ScalarType> Point3x; |
|
|
|
static void Random(int vn, std::vector<Point3<ScalarType > > &NN) |
|
{ |
|
NN.clear(); |
|
while(NN.size()<vn) |
|
{ |
|
Point3x pp(((float)rand())/RAND_MAX, |
|
((float)rand())/RAND_MAX, |
|
((float)rand())/RAND_MAX); |
|
pp=pp*2.0-Point3x(1,1,1); |
|
if(pp.SquaredNorm()<1) |
|
{ |
|
Normalize(pp); |
|
NN.push_back(pp); |
|
} |
|
} |
|
} |
|
|
|
|
|
static Point3x FibonacciPt(int i, int n) |
|
{ |
|
const ScalarType Phi = ScalarType(std::sqrt(ScalarType(5))*0.5 + 0.5); |
|
const ScalarType phi = 2.0*M_PI* (i/Phi - floor(i/Phi)); |
|
ScalarType cosTheta = 1.0 - (2*i + 1.0)/ScalarType(n); |
|
ScalarType sinTheta = 1 - cosTheta*cosTheta; |
|
sinTheta = std::sqrt(std::min(ScalarType(1),std::max(ScalarType(0),sinTheta))); |
|
return Point3x( |
|
cos(phi)*sinTheta, |
|
sin(phi)*sinTheta, |
|
cosTheta); |
|
} |
|
|
|
// Implementation of the Spherical Fibonacci Point Sets |
|
// according to the description of |
|
// Spherical Fibonacci Mapping |
|
// Benjamin Keinert, Matthias Innmann, Michael Sanger, Marc Stamminger |
|
// TOG 2015 |
|
static void Fibonacci(int n, std::vector<Point3x > &NN) |
|
{ |
|
NN.resize(n); |
|
for(int i=0;i<n;++i) |
|
NN[i]=FibonacciPt(i,n); |
|
} |
|
|
|
static void UniformCone(int vn, std::vector<Point3<ScalarType > > &NN, ScalarType AngleRad, Point3x dir=Point3x(0,1,0)) |
|
{ |
|
assert(AngleRad>0 && AngleRad<M_PI); |
|
std::vector<Point3<ScalarType > > NNT; |
|
NN.clear(); |
|
// To compute the number of points we need to know the area of |
|
// the spherical cap and then use the ratio with the total surface of the sphere |
|
ScalarType Height= 1.0 - cos(AngleRad); // height is measured from top... |
|
ScalarType CapArea = 2.0*M_PI*Height; // Surface is the one of the tangent cylinder |
|
ScalarType Ratio = CapArea / (4.0*M_PI); |
|
|
|
// printf("----------AngleRad %f Angledeg %f ratio %f vn %i vn2 %i \n",AngleRad,math::ToDeg(AngleRad),Ratio,vn,int(vn/Ratio)); |
|
Fibonacci(vn/Ratio,NNT); |
|
// printf("asked %i got %i (expecting %i instead of %i)\n", int(vn/Ratio), int(NNT.size()), int(NNT.size()*Ratio), vn); |
|
|
|
ScalarType cosAngle = cos(AngleRad); |
|
for(auto ni : NNT) |
|
{ |
|
if(dir.dot(ni) >= cosAngle) NN.push_back(ni); |
|
} |
|
} |
|
|
|
// This is an Implementation of the Dave Rusin’s Disco Ball algorithm |
|
// You can spread the points as follows: |
|
// Put N+1 points on the meridian from north to south poles, equally spaced. |
|
// If you swing this meridian around the sphere, you'll sweep out the entire |
|
// surface; in the process, each of the points will sweep out a circle. You |
|
// can show that the ith point will sweep out a circle of radius sin(pi i/N). |
|
// If you space points equally far apart on this circle, keeping the |
|
// displacement roughly the same as on that original meridian, you'll be |
|
// able to fit about 2N sin(pi i/N) points here. This process will put points |
|
// pretty evenly spaced on the sphere; the number of such points is about |
|
// 2+ 2N*Sum(i=1 to N-1) sin(pi i/N). |
|
// The closed form of this summation |
|
// 2.0 - ( (2.0*N * sin (M_PI/N))/(cos(M_PI/N) - 1.0)); |
|
static void DiscoBall(int vn, std::vector<Point3<ScalarType > > &NN) |
|
{ |
|
// Guess the right N |
|
ScalarType N=0; |
|
|
|
for(N=1;N<vn;++N) |
|
{ |
|
ScalarType expectedPoints = 2.0 - ( (2.0*N * sin (M_PI/N))/(cos(M_PI/N) - 1.0)); |
|
if(expectedPoints >= vn) break; |
|
} |
|
|
|
ScalarType VerticalAngle = M_PI / N; |
|
NN.push_back(Point3<ScalarType>(0,0,1.0)); |
|
for (int i =1; i<N; ++i) |
|
{ |
|
// Z is the north/south axis |
|
ScalarType HorizRadius = sin(i*VerticalAngle); |
|
ScalarType CircleLength = 2.0 * M_PI * HorizRadius; |
|
ScalarType Z = cos(i*VerticalAngle); |
|
ScalarType PointNumPerCircle = floor( CircleLength / VerticalAngle); |
|
ScalarType HorizontalAngle = 2.0*M_PI/PointNumPerCircle; |
|
for(ScalarType j=0;j<PointNumPerCircle;++j) |
|
{ |
|
ScalarType X = cos(j*HorizontalAngle)*HorizRadius; |
|
ScalarType Y = sin(j*HorizontalAngle)*HorizRadius; |
|
NN.push_back(Point3<ScalarType>(X,Y,Z)); |
|
} |
|
} |
|
NN.push_back(Point3<ScalarType>(0,0,-1.0)); |
|
} |
|
|
|
static void RecursiveOctahedron(int vn, std::vector<Point3<ScalarType > > &NN) |
|
{ |
|
OctaLevel pp; |
|
|
|
int ll=10; |
|
while(pow(4.0f,ll)+2>vn) ll--; |
|
|
|
pp.Init(ll); |
|
sort(pp.v.begin(),pp.v.end()); |
|
int newsize = unique(pp.v.begin(),pp.v.end())-pp.v.begin(); |
|
pp.v.resize(newsize); |
|
|
|
NN=pp.v; |
|
//Perturb(NN); |
|
} |
|
|
|
static void Perturb(std::vector<Point3<ScalarType > > &NN) |
|
{ |
|
float width=0.2f/sqrt(float(NN.size())); |
|
|
|
typename std::vector<Point3<ScalarType> >::iterator vi; |
|
for(vi=NN.begin(); vi!=NN.end();++vi) |
|
{ |
|
Point3x pp(((float)rand())/RAND_MAX, |
|
((float)rand())/RAND_MAX, |
|
((float)rand())/RAND_MAX); |
|
pp=pp*2.0-Point3x(1,1,1); |
|
pp*=width; |
|
(*vi)+=pp; |
|
(*vi).Normalize(); |
|
} |
|
|
|
} |
|
|
|
/* |
|
Trova la normale piu vicina a quella data. |
|
Assume che tutte normale in ingresso sia normalizzata; |
|
*/ |
|
static int BestMatchingNormal(const Point3x &n, std::vector<Point3x> &nv) |
|
{ |
|
int ret=-1; |
|
ScalarType bestang=-1; |
|
ScalarType cosang; |
|
typename std::vector<Point3x>::iterator ni; |
|
for(ni=nv.begin();ni!=nv.end();++ni) |
|
{ |
|
cosang=(*ni).dot(n); |
|
if(cosang>bestang) { |
|
bestang=cosang; |
|
ret=ni-nv.begin(); |
|
} |
|
} |
|
assert(ret>=0 && ret <int(nv.size())); |
|
return ret; |
|
} |
|
|
|
|
|
private : |
|
class OctaLevel |
|
{ |
|
public: |
|
std::vector<Point3x> v; |
|
int level; |
|
int sz; |
|
int sz2; |
|
|
|
Point3x &Val(int i, int j) { |
|
|
|
assert(i>=-sz2 && i<=sz2); |
|
assert(j>=-sz2 && j<=sz2); |
|
return v[i+sz2 +(j+sz2)*sz]; |
|
} |
|
/* |
|
* Only the first quadrant is generated and replicated onto the other ones. |
|
* |
|
* o lev == 1 |
|
* | \ sz2 = 2^lev = 2 |
|
* o - o sz = 5 (eg. all the points lie in a 5x5 squre) |
|
* | \ | \ |
|
* o - o - o |
|
* |
|
* | |
|
* V |
|
* |
|
* o |
|
* | \ lev == 1 |
|
* o - o sz2 = 4 |
|
* | \ | \ sz = 9 (eg. all the points lie in a 9x9 squre) |
|
* o - o - o |
|
* | \ | \ | \ |
|
* o - o - o - o |
|
* | \ | \ | \ | \ |
|
* o - o - o - o - o |
|
* |
|
* |
|
*/ |
|
void Init(int lev) |
|
{ |
|
sz2=pow(2.0f,lev); |
|
sz=sz2*2+1; |
|
v.resize(sz*sz,Point3x(0,0,0)); |
|
if(lev==0) |
|
{ |
|
Val( 0,0)=Point3x( 0, 0, 1); |
|
Val( 1,0)=Point3x( 1, 0, 0); |
|
Val( 0,1)=Point3x( 0, 1, 0); |
|
} |
|
else |
|
{ |
|
OctaLevel tmp; |
|
tmp.Init(lev-1); |
|
int i,j; |
|
for(i=0;i<=sz2;++i) |
|
for(j=0;j<=(sz2-i);++j) |
|
{ |
|
if((i%2)==0 && (j%2)==0) |
|
Val(i,j)=tmp.Val(i/2,j/2); |
|
if((i%2)!=0 && (j%2)==0) |
|
Val(i,j)=(tmp.Val((i-1)/2,j/2)+tmp.Val((i+1)/2,j/2))/2.0; |
|
if((i%2)==0 && (j%2)!=0) |
|
Val(i,j)=(tmp.Val(i/2,(j-1)/2)+tmp.Val(i/2,(j+1)/2))/2.0; |
|
if((i%2)!=0 && (j%2)!=0) |
|
Val(i,j)=(tmp.Val((i-1)/2,(j+1)/2)+tmp.Val((i+1)/2,(j-1)/2))/2.0; |
|
|
|
Val( sz2-j, sz2-i)[0] = Val(i,j)[0]; Val( sz2-j, sz2-i)[1] = Val(i,j)[1]; Val( sz2-j, sz2-i)[2] = -Val(i,j)[2]; |
|
Val(-sz2+j, sz2-i)[0] =-Val(i,j)[0]; Val(-sz2+j, sz2-i)[1] = Val(i,j)[1]; Val(-sz2+j, sz2-i)[2] = -Val(i,j)[2]; |
|
Val( sz2-j,-sz2+i)[0] = Val(i,j)[0]; Val( sz2-j,-sz2+i)[1] =-Val(i,j)[1]; Val( sz2-j,-sz2+i)[2] = -Val(i,j)[2]; |
|
Val(-sz2+j,-sz2+i)[0] =-Val(i,j)[0]; Val(-sz2+j,-sz2+i)[1] =-Val(i,j)[1]; Val(-sz2+j,-sz2+i)[2] = -Val(i,j)[2]; |
|
|
|
Val(-i,-j)[0] = -Val(i,j)[0]; Val(-i,-j)[1] = -Val(i,j)[1]; Val(-i,-j)[2] = Val(i,j)[2]; |
|
Val( i,-j)[0] = Val(i,j)[0]; Val( i,-j)[1] = -Val(i,j)[1]; Val( i,-j)[2] = Val(i,j)[2]; |
|
Val(-i, j)[0] = -Val(i,j)[0]; Val(-i, j)[1] = Val(i,j)[1]; Val(-i, j)[2] = Val(i,j)[2]; |
|
} |
|
|
|
typename std::vector<Point3<ScalarType> >::iterator vi; |
|
for(vi=v.begin(); vi!=v.end();++vi) |
|
(*vi).Normalize(); |
|
} |
|
} |
|
}; |
|
}; |
|
} |
|
#endif
|
|
|