core/vpgl/algo/vpgl_ray.cxx
Go to the documentation of this file.
00001 // This is core/vpgl/algo/vpgl_ray.cxx
00002 #include "vpgl_ray.h"
00003 //:
00004 // \file
00005 #include <vnl/vnl_double_2.h>
00006 #include <vnl/vnl_double_3.h>
00007 #include <vnl/vnl_double_4.h>
00008 #include <vnl/vnl_math.h>
00009 #include <vgl/vgl_tolerance.h>
00010 #include <vgl/vgl_distance.h>
00011 #include <vgl/vgl_point_3d.h>
00012 #include <vgl/vgl_vector_3d.h>
00013 #include <vgl/vgl_plane_3d.h>
00014 #include <vgl/vgl_intersection.h>
00015 #include <vpgl/algo/vpgl_invmap_cost_function.h>
00016 #include "vpgl_backproject.h"
00017 
00018 bool vpgl_ray::ray(const vpgl_camera<double>* cam,
00019                    vnl_double_3 const& point_3d,
00020                    vnl_double_3& r)
00021 {
00022   // special case of a generic camera
00023   if (cam->type_name()=="vpgl_generic_camera")
00024   {
00025     vgl_point_3d<double> p(point_3d[0], point_3d[1], point_3d[2]);
00026     vgl_ray_3d<double> ray;
00027     const vpgl_generic_camera<double>* gcam = dynamic_cast<const vpgl_generic_camera<double>*>(cam);
00028     ray = gcam->ray(p);
00029     vgl_vector_3d<double> dir = ray.direction();
00030     r = vnl_double_3(dir.x(), dir.y(), dir.z());
00031     return true;
00032   }
00033   //create an image point
00034   double u, v;
00035   cam->project(point_3d[0], point_3d[1], point_3d[2], u, v);
00036   vnl_double_2 image_point(u, v);
00037 
00038   //construct a shifted plane by 1 unit in - z direction
00039   vnl_double_4 plane(0, 0, 1.0, -point_3d[2]+ 1.0);
00040 
00041   //backproject onto the shifted plane
00042   vnl_double_3 shifted_point;
00043 
00044   if (!vpgl_backproject::bproj_plane(cam, image_point, plane, point_3d,
00045                                      shifted_point))
00046     return false;
00047   //The ray direction is just the difference
00048   r = shifted_point - point_3d;
00049   r.normalize();
00050   return true;
00051 }
00052 
00053 bool vpgl_ray::ray(const vpgl_camera<double>*  cam,
00054                    vgl_point_3d<double> const& point_3d,
00055                    vgl_vector_3d<double>& r)
00056 {
00057   vnl_double_3 p3d(point_3d.x(), point_3d.y(), point_3d.z());
00058   vnl_double_3 tr;
00059   bool success = vpgl_ray::ray(cam, p3d, tr);
00060   if (!success) return false;
00061   r.set(tr[0], tr[1], tr[2]);
00062   return true;
00063 }
00064 
00065 //construct a ray at a 3-d point with an origin lying in the origin_z plane
00066 bool vpgl_ray::ray(const vpgl_camera<double>*  cam,
00067                    vgl_point_3d<double> const& point_3d,
00068                    double origin_z,
00069                    vgl_ray_3d<double>& ray)
00070 {
00071   vgl_plane_3d<double> pl(0.0, 0.0, 1.0, -origin_z);
00072   vgl_vector_3d<double> dir;
00073   bool success = vpgl_ray::ray(cam, point_3d, dir);
00074   if (!success) return false;
00075   // create an infinite line along dir
00076   vgl_infinite_line_3d<double> infl(point_3d, dir);
00077   vgl_point_3d<double> origin;
00078   // intersect with the z plane
00079   if (!vgl_intersection(infl, pl, origin))
00080     return false;
00081   ray.set(origin, dir);
00082   return true;
00083 }
00084 
00085 bool vpgl_ray::ray(vpgl_rational_camera<double> const& rcam,
00086                    vnl_double_3 const& point_3d,
00087                    vnl_double_3& ray)
00088 {
00089     const vpgl_camera<double>*  cam =
00090       static_cast<const vpgl_camera<double>* >(&rcam);
00091     return vpgl_ray::ray(cam, point_3d, ray);
00092 }
00093 
00094 bool vpgl_ray::ray(vpgl_rational_camera<double> const& rcam,
00095                    vgl_point_3d<double> const& point_3d,
00096                    vgl_vector_3d<double>& ray)
00097 {
00098     const vpgl_camera<double>*  cam =
00099       static_cast<const vpgl_camera<double>* >(&rcam);
00100 
00101    return vpgl_ray::ray(cam,point_3d,ray);
00102 }
00103 
00104 bool vpgl_ray::ray(vpgl_rational_camera<double> const& rcam,
00105                    vgl_point_3d<double> const& point_3d,
00106                    vgl_ray_3d<double>& ray)
00107 {
00108   double z_off = rcam.offset(vpgl_rational_camera<double>::Z_INDX);
00109   double z_scale = rcam.scale(vpgl_rational_camera<double>::Z_INDX);
00110   double zmax = z_off + z_scale;
00111 
00112     const vpgl_camera<double>*  cam =
00113       static_cast<const vpgl_camera<double>* >(&rcam);
00114 
00115    return vpgl_ray::ray(cam,point_3d,zmax,ray);
00116 }
00117 
00118 
00119 // compute a ray in local Cartesian coordinates for a local rational cam
00120 bool vpgl_ray::ray(vpgl_local_rational_camera<double> const& lrcam,
00121                    const double u, const double v,
00122                    vgl_point_3d<double>& origin,
00123                    vgl_vector_3d<double>& dir)
00124 {
00125   // find the horizontal plane at the top of the 3-d region
00126   // of valid RPC projection
00127   double z_off = lrcam.offset(vpgl_rational_camera<double>::Z_INDX);
00128   double z_scale = lrcam.scale(vpgl_rational_camera<double>::Z_INDX);
00129   double zmax = z_off + z_scale;
00130 
00131   // find the point of intersection of the back-projected ray with zmax
00132   vgl_plane_3d<double> top_plane(0.0, 0.0, 1.0, -zmax);
00133   vgl_point_2d<double> image_point(u, v);
00134   vgl_point_3d<double> initial_guess(0.0, 0.0, zmax);
00135   vpgl_local_rational_camera<double>* lrcam_ptr =
00136     const_cast<vpgl_local_rational_camera<double>*>(&lrcam);
00137   vpgl_camera<double>* cam = static_cast<vpgl_camera<double>*>(lrcam_ptr);
00138   if (!vpgl_backproject::bproj_plane(cam, image_point, top_plane,
00139                                      initial_guess, origin))
00140     return false;
00141 
00142   // find the point of intersection of the back-projected ray with the
00143   // plane at mid elevation.
00144   //
00145   vgl_plane_3d<double> mid_plane(0.0, 0.0, 1.0, -z_off);
00146   vgl_point_3d<double> mid_initial_guess(0.0, 0.0, z_off), mid_point;
00147   if (!vpgl_backproject::bproj_plane(cam, image_point, mid_plane,
00148                                      mid_initial_guess, mid_point))
00149     return false;
00150 
00151   dir = mid_point - origin;
00152   dir/=dir.length();//unit vector
00153 
00154   return true;
00155 }
00156 
00157 //: compute a ray in local Cartesian coordinates at a given (u, v)
00158 bool vpgl_ray::ray(vpgl_local_rational_camera<double> const& lrcam,
00159                    const double u, const double v,
00160                    vgl_ray_3d<double>& ray)
00161 {
00162   vgl_point_3d<double> origin; vgl_vector_3d<double> dir;
00163   bool success = vpgl_ray::ray(lrcam, u, v, origin, dir);
00164   if (!success) return false;
00165   ray.set(origin, dir);
00166   return true;
00167 }
00168 
00169 // compute a ray in local Cartesian coordinates for a local rational cam
00170 bool vpgl_ray::plane_ray(vpgl_local_rational_camera<double> const& lrcam,
00171                          const vgl_point_2d<double> image_point1,
00172                          const vgl_point_2d<double> image_point2,
00173                          vgl_plane_3d<double>& plane)
00174 {
00175   // find the horizontal plane at the top of the 3-d region
00176   // of valid RPC projection
00177   double z_off = lrcam.offset(vpgl_rational_camera<double>::Z_INDX);
00178   double z_scale = lrcam.scale(vpgl_rational_camera<double>::Z_INDX);
00179   double zmax = z_off + z_scale;
00180 
00181   // find the point of intersection of the back-projected ray with zmax
00182   vgl_plane_3d<double> top_plane(0.0, 0.0, 1.0, -zmax);
00183   //vgl_point_2d<double> image_point(u, v);
00184   vgl_point_3d<double> initial_guess(0.0, 0.0, zmax);
00185   vgl_point_3d<double> point1,point2;
00186   vpgl_local_rational_camera<double>* lrcam_ptr =
00187     const_cast<vpgl_local_rational_camera<double>*>(&lrcam);
00188   vpgl_camera<double>* cam = static_cast<vpgl_camera<double>*>(lrcam_ptr);
00189   if (!vpgl_backproject::bproj_plane(cam, image_point1, top_plane,
00190                                      initial_guess, point1))
00191     return false;
00192   if (!vpgl_backproject::bproj_plane(cam, image_point2, top_plane,
00193                                      initial_guess, point2))
00194     return false;
00195 
00196   // find the point of intersection of the back-projected ray with the
00197   // plane at mid elevation.
00198   //
00199   vgl_plane_3d<double> mid_plane(0.0, 0.0, 1.0, -z_off);
00200   vgl_point_3d<double> mid_initial_guess(0.0, 0.0, z_off), mid_point1;
00201   if (!vpgl_backproject::bproj_plane(cam, image_point1, mid_plane,
00202                                      mid_initial_guess, mid_point1))
00203     return false;
00204 
00205   plane=vgl_plane_3d<double>(point1,point2,mid_point1);
00206 
00207   return true;
00208 }
00209 
00210 bool vpgl_ray::ray(vpgl_proj_camera<double> const& cam,
00211                    vgl_point_3d<double> const& world_pt,
00212                    vgl_ray_3d<double>& ray)
00213 {
00214   vgl_point_3d<double> cc = cam.camera_center();
00215   if (vgl_distance(cc, world_pt)<vgl_tolerance<double>::position)
00216     return false;
00217   ray = vgl_ray_3d<double>(cc, world_pt);
00218   return true;
00219 }
00220 
00221 bool vpgl_ray::principal_ray(vpgl_proj_camera<double> const& cam,
00222                              vgl_ray_3d<double>& pray)
00223 {
00224   vnl_matrix_fixed<double, 3, 4> C = cam.get_matrix();
00225   vgl_vector_3d<double> dir(C[2][0], C[2][1], C[2][2]);
00226   //check if camera is affine. if so, the principal ray is not defined
00227   if (dir.length()<vgl_tolerance<double>::position)
00228     return false;
00229   dir = normalize(dir);
00230   vgl_point_3d<double> cent = cam.camera_center();
00231   pray = vgl_ray_3d<double>(cent, cent + dir); 
00232   return true;
00233 }
00234 
00235 bool vpgl_ray::ray(vpgl_perspective_camera<double> const& cam,
00236                    vgl_point_3d<double> const& world_pt,
00237                    vgl_ray_3d<double>& ray)
00238 {
00239   if (cam.is_behind_camera(vgl_homg_point_3d<double>(world_pt.x(), world_pt.y(), world_pt.z())))
00240     return false;
00241   ray = vgl_ray_3d<double>(cam.camera_center(), world_pt);
00242   return true;
00243 }
00244 
00245 bool vpgl_ray::ray(vpgl_generic_camera<double> const& cam,
00246                    vgl_point_3d<double> const& world_pt,
00247                    vgl_ray_3d<double>& ray)
00248 {
00249   ray = cam.ray(world_pt);
00250   return true;
00251 }
00252 
00253 double vpgl_ray::angle_between_rays(vgl_rotation_3d<double> const& r0,
00254                                     vgl_rotation_3d<double> const& r1)
00255 {
00256   vnl_vector_fixed<double, 3> zaxis, a0, a1;
00257   zaxis[0]=0.0;  zaxis[1]=0.0;  zaxis[2]=1.0;
00258   vgl_rotation_3d<double> r0i = r0.inverse(), r1i = r1.inverse();
00259   a0 = r0i*zaxis; a1 = r1i*zaxis;
00260   double dp = dot_product(a0, a1);
00261   return vcl_acos(dp);
00262 }
00263 
00264 double vpgl_ray::rot_about_ray(vgl_rotation_3d<double> const& r0,
00265                                vgl_rotation_3d<double> const& r1)
00266 {
00267   // find axes for each rotation
00268   vnl_vector_fixed<double, 3> zaxis, a0, a1;
00269   zaxis[0]=0.0;  zaxis[1]=0.0;  zaxis[2]=1.0;
00270   vgl_rotation_3d<double> r0i = r0.inverse(), r1i = r1.inverse();
00271   a0 = r0i*zaxis; a1 = r1i*zaxis;
00272   // find the transforms that map the z-axis to each axis
00273   vgl_rotation_3d<double> r0b(zaxis, a0), r1b(zaxis,a1);
00274   //  find rotations about z axis
00275   vgl_rotation_3d<double> r0_alpha = r0*r0b, r1_alpha = r1*r1b;
00276   vnl_vector_fixed<double, 3> r0_alpha_rod = r0_alpha.as_rodrigues(), r1_alpha_rod = r1_alpha.as_rodrigues();
00277   // get angle difference
00278   double ang0 = r0_alpha_rod.magnitude(), ang1 = r1_alpha_rod.magnitude();
00279   return vcl_fabs(ang0-ang1);
00280 }
00281 
00282 vgl_rotation_3d<double> vpgl_ray::
00283 rot_to_point_ray(vgl_vector_3d<double> const& ray_dir)
00284 {
00285   vnl_vector_fixed<double, 3> za(0.0, 0.0, 1.0),
00286     v(ray_dir.x(), ray_dir.y(), ray_dir.z());
00287   //rotation from principal axis to z axis
00288   vgl_rotation_3d<double> R_axis(v, za);
00289   return R_axis;
00290 }
00291 
00292 vgl_rotation_3d<double> vpgl_ray::rot_to_point_ray(double azimuth,
00293                                                    double elevation)
00294 {
00295   double el_rad = elevation*vnl_math::pi_over_180;
00296   double s = vcl_sin(el_rad), c = vcl_cos(el_rad);
00297   double az_rad = azimuth*vnl_math::pi_over_180;
00298   double x = s*vcl_cos(az_rad), y = s*vcl_sin(az_rad), z = c;
00299   return vpgl_ray::rot_to_point_ray(vgl_vector_3d<double>(x, y, z));
00300 }