00001
00002 #include "bgui3d_project2d_tableau.h"
00003
00004
00005
00006 #include <vcl_iostream.h>
00007 #include <vcl_cassert.h>
00008 #include <vgui/vgui_gl.h>
00009 #include <vgui/vgui_glu.h>
00010 #include <vgui/vgui_menu.h>
00011 #include <vgui/vgui_command.h>
00012 #include <vnl/vnl_double_3x3.h>
00013 #include <vnl/vnl_double_3x4.h>
00014 #include <vnl/vnl_double_4x4.h>
00015 #include <vnl/vnl_det.h>
00016 #include <vgl/vgl_point_3d.h>
00017 #include <vgl/algo/vgl_rotation_3d.h>
00018
00019 #include <vpgl/vpgl_perspective_camera.h>
00020 #include "bgui3d_algo.h"
00021
00022 #include <Inventor/actions/SoGetBoundingBoxAction.h>
00023 #include <Inventor/SbLinear.h>
00024
00025
00026
00027 bgui3d_project2d_tableau::bgui3d_project2d_tableau()
00028 : bgui3d_tableau(NULL), draw_headlight_(true)
00029 {
00030
00031 this->set_camera(vpgl_proj_camera<double>());
00032 }
00033
00034
00035
00036 bgui3d_project2d_tableau::bgui3d_project2d_tableau( const vpgl_proj_camera<double>& camera,
00037 SoNode * scene_root )
00038 : bgui3d_tableau(scene_root), draw_headlight_(true)
00039 {
00040 this->set_camera(camera);
00041 }
00042
00043
00044
00045 bgui3d_project2d_tableau::~bgui3d_project2d_tableau()
00046 {
00047 }
00048
00049
00050 vcl_string bgui3d_project2d_tableau::type_name() const
00051 {
00052 return "bgui3d_project2d_tableau";
00053 }
00054
00055
00056
00057
00058 bool
00059 bgui3d_project2d_tableau::set_camera(const vpgl_proj_camera<double>& cam)
00060 {
00061 vnl_double_3x4 camera = cam.get_matrix();
00062
00063 vnl_double_3x3 K;
00064 vnl_double_3x3 R;
00065 vnl_double_3 t;
00066
00067
00068 if ( camera[2][0] == 0 && camera[2][1] == 0 && camera[2][2] == 0 )
00069 {
00070 vnl_double_3x4 ncamera = camera;
00071 ncamera /= ncamera[2][3];
00072
00073
00074
00075
00076
00077
00078 K.fill( 0.0 );
00079 vnl_double_3 r1, r2, r3, a1;
00080 r2[0] = ncamera[1][0]; r2[1] = ncamera[1][1]; r2[2] = ncamera[1][2];
00081 K[1][1] = vcl_sqrt( r2[0]*r2[0]+r2[1]*r2[1]+r2[2]*r2[2] );
00082 r2 /= vcl_sqrt( r2[0]*r2[0]+r2[1]*r2[1]+r2[2]*r2[2] );
00083 a1[0] = ncamera[0][0]; a1[1] = ncamera[0][1]; a1[2] = ncamera[0][2];
00084 r3 = vnl_cross_3d( a1, r2 );
00085 r3 /= vcl_sqrt( r3[0]*r3[0]+r3[1]*r3[1]+r3[2]*r3[2] );
00086 r1 = vnl_cross_3d( r2, r3 );
00087 K[0][0] = a1[0]*r1[0] + a1[1]*r1[1] + a1[2]*r1[2];
00088 if ( K[0][0] < 0 ) {
00089 K[0][0] *= -1;
00090 r1 *= -1;
00091 }
00092 K[0][1] = a1[0]*r2[0] + a1[1]*r2[1] + a1[2]*r2[2];
00093 if ( K[1][1] < 0 ) {
00094 K[1][1] *= -1;
00095 r2 *= -1;
00096 K[0][1] *= -1;
00097 }
00098 K[0][2] = ncamera[0][3];
00099 K[1][2] = ncamera[1][3];
00100 K[2][2] = 1.0;
00101
00102
00103 vnl_double_3x4 mcamera( 0.0 );
00104 vnl_double_4x4 rcamera( 0.0 );
00105 mcamera[0][0] = mcamera[1][1] = mcamera[2][3] = 1;
00106 rcamera[0][0] = r1[0]; rcamera[0][1] = r1[1]; rcamera[0][2] = r1[2];
00107 rcamera[1][0] = r2[0]; rcamera[1][1] = r2[1]; rcamera[1][2] = r2[2];
00108 rcamera[2][0] = r3[0]; rcamera[2][1] = r3[1]; rcamera[2][2] = r3[2];
00109 rcamera[3][3] = 1.0;
00110 assert( (K*mcamera*rcamera - ncamera).fro_norm() > 1e-4 );
00111
00112
00113 t.fill( 0.0 );
00114 R[0][0] = r1[0]; R[0][1] = r1[1]; R[0][2] = r1[2];
00115 R[1][0] = r2[0]; R[1][1] = r2[1]; R[1][2] = r2[2];
00116 R[2][0] = r3[0]; R[2][1] = r3[1]; R[2][2] = r3[2];
00117 }
00118
00119 else {
00120
00121 vnl_double_3x4 cmr = camera;
00122 if (vnl_det(vnl_double_3x3(cmr.extract(3,3))) < 0)
00123 cmr *= -1.0;
00124 if (!bgui3d_decompose_camera(cmr, K, R, t)) {
00125 vcl_cerr << "decomposition error\n\n";
00126 return false;
00127 }
00128 }
00129
00130
00131 vnl_double_4x4 M(0.0);
00132 M.update(R.as_ref());
00133 M.set_column(3, t.as_ref());
00134 M(3,3) = 1.0;
00135
00136
00137 vnl_matrix_fixed<double,4,4> mm(model_matrix_);
00138 mm = M.transpose();
00139
00140
00141 vnl_double_4x4 Mi(0.0);
00142 Mi.update(R.transpose().as_ref());
00143 Mi.set_column(3, (-R.transpose()*t).as_ref());
00144 Mi(3,3) = 1.0;
00145
00146
00147 camera_z_ = camera * Mi;
00148
00149
00150
00151 assert(vcl_fabs(camera_z_(1,0))<1e-10);
00152 assert(vcl_fabs(camera_z_(2,0))<1e-10);
00153 assert(vcl_fabs(camera_z_(2,1))<1e-10);
00154 camera_z_(1,0) = camera_z_(2,0) = camera_z_(2,1) = 0.0;
00155
00156 return true;
00157 }
00158
00159
00160
00161
00162 vcl_auto_ptr<vpgl_proj_camera<double> >
00163 bgui3d_project2d_tableau::camera() const
00164 {
00165 vnl_matrix<double> mm(4,4,16,model_matrix_);
00166 vgl_rotation_3d<double> R(mm.extract(3,3).transpose());
00167 vgl_point_3d<double> t(-mm[3][0], -mm[3][1], -mm[3][2]);
00168 t = R.inverse()*t;
00169 if (camera_z_[2][2] != 0) {
00170 vpgl_calibration_matrix<double> K(camera_z_.extract(3,3));
00171 return vcl_auto_ptr<vpgl_proj_camera<double> >
00172 ( new vpgl_perspective_camera<double>(K,t,R) );
00173 }
00174 else
00175
00176 return vcl_auto_ptr<vpgl_proj_camera<double> >
00177 ( new vpgl_proj_camera<double>(camera_z_*mm.transpose()) );
00178 }
00179
00180
00181
00182 static void draw_headlight()
00183 {
00184 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
00185 GLfloat light0_pos[4] = { 0.0, 0.0, -1.0, 0.0 };
00186 GLfloat light0_diff[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
00187 GLfloat light0_amb[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
00188 GLfloat light0_spec[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
00189
00190 glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
00191 glLightfv(GL_LIGHT0, GL_AMBIENT, light0_amb);
00192 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diff);
00193 glLightfv(GL_LIGHT0, GL_SPECULAR, light0_spec);
00194
00195 glEnable(GL_LIGHT0);
00196 }
00197
00198
00199
00200 bool
00201 bgui3d_project2d_tableau::handle(const vgui_event& e)
00202 {
00203
00204 if ( e.type == vgui_DRAW || e.type == vgui_DRAW_OVERLAY ) {
00205
00206 double P[16] , M[16];
00207 glGetDoublev(GL_PROJECTION_MATRIX, P);
00208 glGetDoublev(GL_MODELVIEW_MATRIX, M);
00209
00210 if (this->setup_projection()) {
00211 glMatrixMode(GL_MODELVIEW);
00212 glLoadIdentity();
00213 if (draw_headlight_)
00214 draw_headlight();
00215 else
00216 glDisable(GL_LIGHT0);
00217 glLoadMatrixd(model_matrix_);
00218 if ( e.type == vgui_DRAW )
00219 return this->render();
00220 if ( e.type == vgui_DRAW_OVERLAY )
00221 return this->render_overlay();
00222 }
00223
00224
00225 glMatrixMode(GL_PROJECTION);
00226 glLoadMatrixd(P);
00227 glMatrixMode(GL_MODELVIEW);
00228 glLoadMatrixd(M);
00229 }
00230
00231 return bgui3d_tableau::handle(e);
00232 }
00233
00234
00235
00236 bool
00237 bgui3d_project2d_tableau::setup_projection()
00238 {
00239
00240
00241
00242 double M[16];
00243 glGetDoublev(GL_MODELVIEW_MATRIX, M);
00244 glMatrixMode(GL_PROJECTION);
00245 glMultMatrixd(M);
00246
00247
00248
00249 SoGetBoundingBoxAction sbba(get_viewport_region());
00250 sbba.apply(scene_root_);
00251
00252 SbXfBox3f xbox = sbba.getXfBoundingBox();
00253 SbMatrix mat;
00254 mat.makeIdentity();
00255 for (int i=0; i<4; ++i)
00256 for (int j=0; j<4; ++j)
00257 mat[i][j] = float(model_matrix_[4*i+j]);
00258 xbox.transform(mat);
00259 mat = xbox.getTransform();
00260 SbBox3f box = xbox.project();
00261
00262 double nearval = box.getMin()[2];
00263 double farval = box.getMax()[2];
00264
00265
00266
00267
00268
00269
00270 assert(!camera_z_(2,0) && !camera_z_(2,1));
00271
00272 double epsilon = 0.01;
00273 double denom = (farval - nearval)/(1.0-epsilon);
00274 double w1 = camera_z_[2][2];
00275 double w2 = camera_z_[2][3];
00276 double z2 = -(w1*(farval+nearval) + 2*w2)/denom;
00277 double z3 = (2*w1*farval*nearval + w2*(farval+nearval))/denom;
00278
00279 double P[4][4] = {
00280 { camera_z_(0,0), 0, 0, 0},
00281 { camera_z_(0,1), camera_z_(1,1), 0, 0},
00282 { camera_z_(0,2), camera_z_(1,2), z2, camera_z_(2,2)},
00283 { camera_z_(0,3), camera_z_(1,3), z3, camera_z_(2,3)}
00284 };
00285
00286
00287 glMultMatrixd((double *)P);
00288
00289 return true;
00290 }
00291
00292
00293
00294
00295 class bgui3d_headlight_command : public vgui_command
00296 {
00297 public:
00298 bgui3d_headlight_command(bgui3d_project2d_tableau* tab) : bgui3d_project2d_tab(tab) {}
00299 void execute()
00300 {
00301 bool headlight = bgui3d_project2d_tab->is_headlight();
00302 bgui3d_project2d_tab->set_headlight(!headlight);
00303 }
00304
00305 bgui3d_project2d_tableau *bgui3d_project2d_tab;
00306 };
00307
00308
00309
00310 void bgui3d_project2d_tableau::get_popup(const vgui_popup_params& ,
00311 vgui_menu &menu)
00312 {
00313 vcl_string headlight_item;
00314 if ( this->is_headlight() )
00315 headlight_item = "Disable Headlight";
00316 else
00317 headlight_item = "Enable Headlight";
00318
00319 menu.add(headlight_item, new bgui3d_headlight_command(this));
00320 }