Rev 335 | Blame | Last modification | View Log | RSS feed
// ----------------------------------------
// A simple Range Scan Viewer
//
// Controls:
// - left mouse down + mouse motion : rotate
// - Scroll button and +- buttons : zoom
// - right mouse click : centre trackball
// - esc : exits
// - x,y,z buttons : switch trackball up axis
// ----------------------------------------
#if (_MSC_VER >= 1200)
#pragma warning (disable: 4786)
#endif
#include <list>
#include <vector>
#include <assert.h>
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#include <io.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <CGLA/Vec2i.h>
#include <CGLA/Vec2f.h>
#include <CGLA/Vec3f.h>
#include <CGLA/Mat4x4f.h>
#include "GLGraphics/gel_glut.h"
#include "GLGraphics/QuatTrackBall.h"
#include "Geometry/KDTree.h"
#include "ply.h"
#include <CGLA/statistics.h>
#include <CGLA/eigensolution.h>
using namespace std;
using namespace CGLA;
using namespace Geometry;
using namespace GLGraphics;
namespace
{
int win_size_x = 800;
int win_size_y = 800;
QuatTrackBall* ball;
int spin_timer = 20;
void spin(int x);
int main_window;
Vec3f cen;
Vec3f pmin;
Vec3f bbsize;
std::vector<CGLA::Vec3f> verts;
std::vector<CGLA::Vec3f> norms;
float rad;
void verts_from_conf(std::string filename, float dist=0.002)
{
verts.clear();
norms.clear();
CGLA::Quatf qrot;
CGLA::Vec3f tr;
CGLA::Mat4x4f transform;
CGLA::Mat4x4f Ntransform;
char plyfile[50];
char elemtag[50];
FILE * pFile;
//filename = "data/" + filename;
pFile = fopen (filename.c_str(),"r");
if (pFile==NULL)
{
cout << "file error " << filename << endl;
return;
}
bool end=false;
cen=Vec3f(0,0,0);
pmin=Vec3f(1000,10000,1000);
bbsize=Vec3f(-100,-100,-100);
cout << "using file " << filename << endl;
while(!end)
{
//bmesh bun045.ply -0.0520211 -0.000383981 -0.0109223 0.00548449 -0.294635 -0.0038555 0.955586
//int params = fscanf (pFile, "%s %s %f %f %f %f %f %f %f", &elemtag, &plyfile, &tr[0], &tr[1], &tr[2], &qrot.qw ,&qrot.qv[0], &qrot.qv[1], &qrot.qv[2]);
int params = fscanf (pFile, "%s %s %f %f %f %f %f %f %f", &elemtag, &plyfile, &tr[0], &tr[1], &tr[2],&qrot.qv[0], &qrot.qv[1], &qrot.qv[2], &qrot.qw );
//int params = fscanf (pFile, "%s ", &elemtag);
if (params>0)
{
if ( strcmp(elemtag, "bmesh")==0 )
{
// fscanf (pFile, "%s %f %f %f %f %f %f %f\n", &plyfile, &tr[0], &tr[1], &tr[2],&qrot.qv[0], &qrot.qv[1], &qrot.qv[2], &qrot.qw );
string splyfile = string(plyfile);
cout << "found plyfile " << splyfile << endl;
qrot = qrot.inverse();
transform = CGLA::translation_Mat4x4f(tr) * qrot.get_Mat4x4f();
Ntransform = transform;
Ntransform = invert(Ntransform);
Ntransform = transpose(Ntransform);
PlyFile *ply;
int nelems;
int nprops;
char **elist;
int file_type;
float version;
int num_elems;
//PlyProperty **plist;
char *elem_name;
ply = ply_open_for_reading(splyfile.c_str(), &nelems, &elist, &file_type, &version);
/* print what we found out about the file */
printf ("version %f\n", version);
printf ("type %d\n", file_type);
/* go through each kind of element that we learned is in the file */
/* and read them */
cout << "nelems: " << nelems << endl;
for (int i = 0; i < nelems; i++)
{
cout << "." << flush;
/* get the description of the first element */
elem_name = elist[i];
//plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops);
ply_get_element_description (ply, elem_name, &num_elems, &nprops);
/* print the name of the element, for debugging */
printf ("element %s %d\n", elem_name, num_elems);
/* if we're on vertex elements, read them in */
if (equal_strings ("vertex", elem_name))
{
cout << "v" << flush;
typedef struct PlyVertex {
float x,y,z; /* the usual 3-space position of a vertex */
} PlyVertex;
PlyProperty vert_props[] = { /* list of property information for a vertex */
{"x", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,x), 0, 0, 0, 0},
{"y", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,y), 0, 0, 0, 0},
{"z", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,z), 0, 0, 0, 0},
};
/* set up for getting vertex elements */
ply_get_property (ply, elem_name, &vert_props[0]);
ply_get_property (ply, elem_name, &vert_props[1]);
ply_get_property (ply, elem_name, &vert_props[2]);
/* grab all the vertex elements */
for (int j = 0; j < num_elems; j++)
{
PlyVertex * pv = (PlyVertex *) malloc (sizeof (PlyVertex));
/* grab and element from the file */
ply_get_element (ply, (void*)pv);
Vec3f v = Ntransform.mul_3D_point(Vec3f(pv->x, pv->y, pv->z));
verts.push_back(v);
Vec3f n = Ntransform.mul_3D_vector(Vec3f(0,0,1));
norms.push_back(n);
cen += v;
pmin = v_min(pmin,v);
bbsize = v_max(bbsize,v);
}
}
}
}
}
else
{
end=true;
fclose(pFile);
}
}
if (dist>0)
{
Geometry::KDTree<CGLA::Vec3f,int>* tree = new Geometry::KDTree<CGLA::Vec3f,int>();
for (unsigned int i=0; i<verts.size(); ++i)
tree->insert(verts[i], i);
tree->build();
int skip=0;
for (unsigned int i=0; i<verts.size(); ++i)
{
if (i % 100000 == 0)
cerr << ".";
vector<CGLA::Vec3f> neigbours;
vector<int> neigbour_ids;
int num = tree->in_sphere(verts[i], dist, neigbours, neigbour_ids);
if (num > 5)
{
Mat3x3f A;
Vec3f m = covariance(neigbours, A);
Mat3x3f Q,L;
int n = power_eigensolution(A, Q, L);
int min_id;
if ( L[0][0] < L[1][1])
{
if ( L[0][0] < L[2][2])
min_id = 0;
else
min_id = 2;
}
else
{
if ( L[1][1] < L[2][2])
min_id = 1;
else
min_id = 2;
}
Vec3f temp_n(Q[min_id][0], Q[min_id][1], Q[min_id][2]);
temp_n.normalize();
float sgn = sign(dot(temp_n, norms[i]));
norms[i] = sgn*temp_n;
}
else
{
norms[i] = Vec3f(0,0,0);
skip++;
}
}
cout << skip << " of " << verts.size() << " with zero normal" << endl;;
}
cen /= (float)verts.size();
bbsize = bbsize-pmin;
rad = 0.7f*bbsize.length();
//for(unsigned int i=0; i<verts.size(); ++i )
// scale( verts[i], rad);
//
//pmin= Vec3f(0,0,0);
// //bbsize = Vec3f(cur_dim);
// bbsize = Vec3f(1,1,1);
// cen = 0.5f*bbsize;
}
void write_obj(string fn)
{
FILE* pFile = fopen (fn.c_str(),"w+");
if (pFile==NULL)
{
cout << "file error " << fn << endl;
return;
}
fprintf( pFile, "# %lu vertices with normal\n", verts.size());
//fprintf( pFile, "# center : %d vertices with normal", verts.size());
for(unsigned int i=0; i<verts.size(); ++i )
fprintf( pFile, "v %f %f %f\n", verts[i][0], verts[i][1], verts[i][2]);
for(unsigned int i=0; i<norms.size(); ++i )
fprintf( pFile, "vn %f %f %f\n", norms[i][0], norms[i][1], norms[i][2]);
fclose(pFile);
}
void mouse_motion(int x, int y)
{
ball->roll_ball(Vec2i(x,y));
}
void mouse(int btn, int state, int x, int y)
{
if(state == GLUT_DOWN)
{
if(btn == GLUT_LEFT_BUTTON)
ball->grab_ball(ROTATE_ACTION, Vec2i(x,y));
else if(btn == GLUT_MIDDLE_BUTTON)
ball->grab_ball(ZOOM_ACTION, Vec2i(x, y));
else if(btn == GLUT_RIGHT_BUTTON)
ball->grab_ball(PAN_ACTION, Vec2i(x, y));
}
else if(state == GLUT_UP)
ball->release_ball();
}
void spin(int x)
{
ball->do_spin();
glutTimerFunc(spin_timer, spin, 0);
glutPostRedisplay();
}
void draw()
{
glBegin(GL_POINTS);
for(unsigned int i=0; i<verts.size(); ++i )
{
glVertex3fv( verts[i].get());
}
glEnd();
}
void draw_normals(float l=0.001)
{
glBegin(GL_LINES);
for(unsigned int i=0; i<verts.size(); ++i )
{
Vec3f p1 = verts[i] + l*norms[i];
glVertex3fv( verts[i].get());
glVertex3fv( p1.get());
}
glEnd();
}
void display()
{
static bool washere = false;
static unsigned int lp, ln;
if(!washere)
{
cout << "Creating display list" << endl;
lp = glGenLists(1);
glNewList(lp, GL_COMPILE);
draw();
glEndList();
cout << "Creating display list" << endl;
ln = glGenLists(1);
glNewList(ln, GL_COMPILE);
draw_normals();
glEndList();
washere = true;
glutTimerFunc(spin_timer, spin, 0);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
ball->set_gl_modelview();
glColor3f(0.9,0.1,0);
glCallList(lp);
glColor3f(0.0,0.9,0.5);
glCallList(ln);
glPushMatrix();
glColor3f(0.7,0.9,0.3);
glTranslatef(cen[0], cen[1], cen[2]);
glScalef(bbsize[0], bbsize[1], bbsize[2]);
glutWireCube(1.0);
glPopMatrix();
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y)
{
switch(key)
{
case '\033': exit(0); break;
//case '+': ball->closer(); break;
//case '-': ball->farther(); break;
//default:
// ball->up_axis(key);
}
}
}
int main(int argc, char** argv)
{
// GLUT INIT
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(win_size_x, win_size_y);
glutInit(&argc, argv);
main_window = glutCreateWindow("OBJ Viewer");
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMotionFunc(mouse_motion);
glutMouseFunc(mouse);
//glutIdleFunc(idle);
// GL INIT
glClearColor(.8f, 0.9f, 1.0f, 0.f);
glEnable(GL_DEPTH_TEST);
// LOAD OBJ
string fn;
if(argc>1)
fn = argv[1];
else
fn = "/Users/jab/Studio/3DModels/OriginalBunnyScans/bunny/data/bun.conf";
verts_from_conf(fn, 0.002);
cout << "Loading " << fn << endl;
if(fn == "") exit(0);
write_obj("/Users/jab/Studio/3DModels/OriginalBunnyScans/bunny/data/bunny.obj");
//return 0;
// Initialize Trackball
ball = new QuatTrackBall(cen,2*rad,800,800);
// Setup projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(53,1.0f,rad/100.0,rad*3.0);
glMatrixMode(GL_MODELVIEW);
// Pass control to GLUT
glutMainLoop();
return 0;
}