00001
00002 #include "vgui_projection_inspector.h"
00003
00004
00005
00006
00007
00008 #include <vcl_cassert.h>
00009 #include <vcl_cstdlib.h>
00010 #include <vcl_iostream.h>
00011
00012 #include <vnl/vnl_double_2.h>
00013 #include <vnl/vnl_double_3.h>
00014 #include <vnl/vnl_matlab_print.h>
00015
00016 #include <vgui/vgui_gl.h>
00017
00018
00019
00020 void vgui_projection_inspector::print(vcl_ostream& strm) const
00021 {
00022 strm << "vgui_projection_inspector: {\n"
00023 << "VP = " << vp[0] << ' ' << vp[1] << ' ' << vp[2] << ' ' << vp[3] << '\n';
00024 vnl_matlab_print(strm, P, "P");
00025 vnl_matlab_print(strm, M, "M");
00026 strm << "}\n";
00027 }
00028
00029
00030
00031 bool vgui_projection_inspector::back_project(double const x[3],
00032 double const p[4],
00033 double X[4]) const
00034 {
00035
00036 vnl_double_4x4 T = P*M;
00037
00038
00039 vnl_double_4 a = T.get_row(0);
00040 vnl_double_4 b = T.get_row(1);
00041 vnl_double_4 c = T.get_row(3);
00042
00043
00044 double devx = 2*(x[0]-vp[0]*x[2])/vp[2] - x[2];
00045 double devy = 2*(x[1]-vp[1]*x[2])/vp[3] - x[2];
00046 double devw = x[2];
00047
00048
00049 vnl_double_4x4 omega = devx*outer_product(b,c) + devy*outer_product(c,a) + devw*outer_product(a,b);
00050 omega -= omega.transpose();
00051
00052
00053 double omegad_[16]={
00054 0 , +omega(2,3), -omega(1,3), +omega(1,2),
00055 -omega(2,3), 0 , +omega(0,3), -omega(0,2),
00056 +omega(1,3), -omega(0,3), 0 , +omega(0,1),
00057 -omega(1,2), +omega(0,2), -omega(0,1), 0
00058 };
00059 vnl_double_4x4 omegad(omegad_);
00060
00061
00062 vnl_double_4 X_ = omegad * vnl_double_4(p[0],p[1],p[2],p[3]);
00063
00064
00065 double mag = X_.two_norm();
00066 if (mag == 0)
00067 {
00068 vcl_cerr << "mag=0, X_=" << X_ << vcl_endl;
00069 return false;
00070 }
00071
00072
00073 if (X_[3]<0)
00074 X_ *= (-1.0/mag);
00075 else
00076 X_ *= (1.0/mag);
00077 X[0] = X_[0];
00078 X[1] = X_[1];
00079 X[2] = X_[2];
00080 X[3] = X_[3];
00081
00082 return true;
00083 }
00084
00085 vnl_vector<double> vgui_projection_inspector::back_project(vnl_double_2 const &x,
00086 vnl_double_4 const &p) const
00087 {
00088 vnl_double_3 x_(x[0],x[1],1.0);
00089 vnl_double_4 X_ = back_project(x_,p);
00090 return (X_/X_[3]).extract(3,0);
00091 }
00092
00093 vnl_vector<double> vgui_projection_inspector::back_project(vnl_double_3 const &x,
00094 vnl_double_4 const &p) const
00095 {
00096 vnl_double_4 X;
00097 if (!back_project(x.data_block(), p.data_block(), X.data_block()))
00098 X.fill(0);
00099 return X.as_ref();
00100 }
00101
00102 vnl_vector<double> vgui_projection_inspector::back_project(double x,double y,
00103 vnl_double_4 const &p) const
00104 {
00105 vnl_double_2 xy(x,y);
00106 return back_project(xy,p);
00107 }
00108
00109 vnl_vector<double> vgui_projection_inspector::back_project(double x,double y,double z,
00110 vnl_double_4 const &p) const
00111 {
00112 vnl_double_3 xyz(x,y,z);
00113 return back_project(xyz,p);
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 static bool is_affine(const vnl_double_4x4 &M)
00126 {
00127 return M(3,0)==0 && M(3,1)==0 && M(3,2)==0 && M(3,3)!=0;
00128 }
00129
00130 void vgui_projection_inspector::inspect()
00131 {
00132
00133 glGetIntegerv(GL_VIEWPORT,(GLint*)vp);
00134
00135
00136 {
00137 glGetDoublev(GL_PROJECTION_MATRIX,P.data_block());
00138 P.inplace_transpose();
00139
00140 glGetDoublev(GL_MODELVIEW_MATRIX,M.data_block());
00141 M.inplace_transpose();
00142 }
00143
00144
00145 vnl_double_4x4 T = P*M;
00146
00147
00148
00149
00150
00151
00152
00153
00154 if (is_affine(T) &&
00155 T(1,0)==0 && T(0,1)==0 &&
00156 T(2,0)==0 && T(0,2)==0 &&
00157 T(2,1)==0 && T(1,2)==0 &&
00158 T(3,3)!=0)
00159 {
00160
00161 diagonal_scale_3d = true;
00162
00163
00164
00165 x1 = float(((-1)*T(3,3)-T(0,3))/T(0,0));
00166 y1 = float(((-1)*T(3,3)-T(1,3))/T(1,1));
00167
00168 x2 = float(((+1)*T(3,3)-T(0,3))/T(0,0));
00169 y2 = float(((+1)*T(3,3)-T(1,3))/T(1,1));
00170
00171
00172 s[0] = float(T(0,0)/T(3,3));
00173 s[1] = float(T(1,1)/T(3,3));
00174 s[2] = float(T(2,2)/T(3,3));
00175
00176 t[0] = float(T(0,3)/T(3,3));
00177 t[1] = float(T(1,3)/T(3,3));
00178 t[2] = float(T(2,3)/T(3,3));
00179 }
00180
00181
00182 else
00183 {
00184 diagonal_scale_3d = false;
00185 #ifdef DEBUG
00186 vcl_cerr << "T =\n" << T << '\n';
00187 #endif
00188 }
00189 }
00190
00191 void vgui_projection_inspector::window_to_image_coordinates(int x,int y,
00192 float &xi,float &yi) const
00193 {
00194 if (!diagonal_scale_3d)
00195 {
00196 vcl_cerr << "vgui_projection_inspector::window_to_image_coordinates() - ERROR: Need diagonal GL matrices\n";
00197 print(vcl_cerr);
00198 vcl_abort();
00199 }
00200
00201
00202 int winx=vp[2];
00203 int winy=vp[3];
00204
00205
00206 x -= vp[0];
00207 y -= vp[1];
00208
00209
00210 xi = ((winx-x)*x1 + ( x)*x2)/winx;
00211 yi = ((winy-y)*y1 + ( y)*y2)/winy;
00212 #if 0
00213 yi = (( y)*y1 + (winy-y)*y2)/winy;
00214 #endif // 0
00215 }
00216
00217
00218 void vgui_projection_inspector::image_to_window_coordinates(float ix,float iy,float &wx,float &wy) const
00219 {
00220 assert(diagonal_scale_3d);
00221
00222
00223 vnl_double_4x4 T = P*M;
00224
00225
00226 vnl_double_4 img(ix,iy,0.0,1.0);
00227
00228
00229 vnl_double_4 win = T*img;
00230
00231
00232 float nx = float(win[0]/win[3]);
00233 float ny = float(win[1]/win[3]);
00234
00235
00236 wx = vp[0] + (nx - -1)/2 * vp[2];
00237 wy = vp[1] + (ny - -1)/2 * vp[3];
00238 }
00239
00240
00241 bool vgui_projection_inspector::compute_as_2d_affine(int width, int height,
00242 float* offsetX, float* offsetY,
00243 float* scaleX, float* scaleY)
00244 {
00245 if (!diagonal_scale_3d)
00246 return false;
00247
00248 image_to_window_coordinates(0,0,*offsetX, *offsetY);
00249
00250 float tmpX, tmpY;
00251 image_to_window_coordinates(width, height, tmpX, tmpY);
00252
00253 *scaleX = (tmpX - *offsetX)/width;
00254 *scaleY = -(tmpY - *offsetY)/height;
00255
00256 return true;
00257 }
00258
00259
00260
00261 bool vgui_projection_inspector::image_viewport(float& a0, float& b0,
00262 float& a1, float& b1)
00263 {
00264 if (!diagonal_scale_3d)
00265 return false;
00266
00267 a0 = x1;
00268 b0 = y1;
00269 a1 = x2;
00270 b1 = y2;
00271
00272 return true;
00273 }