contrib/brl/bbas/imesh/algo/imesh_imls_surface.h
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/algo/imesh_imls_surface.h
00002 #ifndef imesh_imls_surface_h_
00003 #define imesh_imls_surface_h_
00004 //:
00005 // \file
00006 // \brief Interpolating Surface functions using IMLS
00007 // \author Matt Leotta (mleotta@lems.brown.edu)
00008 // \date June 4, 2008
00009 //
00010 // This code is based on the paper:
00011 // C. Shen, J. O'Brien, J. Shewchuk
00012 // "Interpolating and Approximating Implicit Surfaces from Polygon Soup"
00013 // SIGGRAPH 2004
00014 //
00015 // \verbatim
00016 //  Modifications
00017 //   <none yet>
00018 // \endverbatim
00019 
00020 #include <imesh/imesh_mesh.h>
00021 #include <imesh/algo/imesh_kd_tree.h>
00022 #include <vnl/vnl_double_3x3.h>
00023 
00024 
00025 class imesh_imls_surface
00026 {
00027  public:
00028   //: Constructor
00029   imesh_imls_surface(const imesh_mesh& mesh,
00030                      double eps = 0.01, double lambda = 0.1,
00031                      bool enforce_bounded = false,
00032                      const vcl_set<unsigned int>& no_normal_faces = vcl_set<unsigned int>());
00033 
00034   //: Copy Constructor
00035   imesh_imls_surface(const imesh_imls_surface& other);
00036 
00037   //: evaluate the implicit surface at a point
00038   double operator() (const vgl_point_3d<double>& p) const;
00039 
00040   //: evaluate the implicit surface at a point
00041   double operator() (double x, double y, double z) const
00042   {
00043     return (*this)(vgl_point_3d<double>(x,y,z));
00044   }
00045 
00046   //: evaluate the squared weighting function given a squared distance
00047   double w2(double dist2) const
00048   {
00049     double w = 1.0 / (dist2 + eps2_);
00050     return w*w;
00051   }
00052 
00053   //: return a bounding box for the original input mesh
00054   vgl_box_3d<double> bounding_box() const;
00055 
00056   //: evaluate the function and its derivative (returned by reference)
00057   double deriv(const vgl_point_3d<double>& p, vgl_vector_3d<double>& dp) const;
00058 
00059   //: evaluate the function and its first and second derivatives (returned by reference)
00060   double deriv2(const vgl_point_3d<double>& p, vgl_vector_3d<double>& dp,
00061                 vnl_double_3x3& ddp) const;
00062 
00063   //: change the epsilon (smoothness) of the surface
00064   void set_epsilon(double eps);
00065 
00066   //: change the lambda (accuracy parameter)
00067   void set_lambda(double lambda) { lambda_ = lambda; }
00068 
00069   //: a data structure to hold the integral terms
00070   struct integral_data
00071   {
00072     integral_data()
00073       : I(0), I_phi(0), dI(0,0,0), dI_phi(0,0,0) {}
00074     integral_data(double i, double i_phi,
00075                   const vgl_vector_3d<double>& di,
00076                   const vgl_vector_3d<double>& di_phi)
00077       : I(i), I_phi(i_phi), dI(di), dI_phi(di_phi) {}
00078     integral_data operator+ (const integral_data& other) const
00079     {
00080       return integral_data(I+other.I, I_phi+other.I_phi,
00081                            dI+other.dI, dI_phi+other.dI_phi);
00082     }
00083     integral_data& operator+= (const integral_data& other)
00084     {
00085       I += other.I;   I_phi += other.I_phi;
00086       dI += other.dI; dI_phi += other.dI_phi;
00087       return *this;
00088     }
00089     integral_data& operator*= (const double& s)
00090     {
00091       I *= s;   I_phi *= s;
00092       dI *= s; dI_phi *= s;
00093       return *this;
00094     }
00095 
00096     double I, I_phi;
00097     vgl_vector_3d<double> dI, dI_phi;
00098   };
00099 
00100   //: integrals of f(x)dx and x*f(x)dx over [0,1] where f(x)= 1/((x+k1)^2 + k2)^2
00101   static void line_integrals(double k1, double k2, double& I1, double& Ix);
00102 
00103   //: integrals of f(x)dx and x*f(x)dx over [0,1] where f(x)= 1/((x+k1)^2 + k2)^2
00104   //  Also compute the integrals when f(x)=1/((x+k1)^2 + k2)^3 (for use in derivatives)
00105   static void line_integrals(double k1, double k2,
00106                              double& I1, double& Ix,
00107                              double& dI1, double& dIx, double& dIx2);
00108 
00109   //: line integral of the squared weight function times a linear value on the line from p0 to p1
00110   //  (value at p0 is v0 and at p1 is v1)
00111   //  \a eps2 is epsilon^2
00112   static double line_integral(const vgl_point_3d<double>& x,
00113                               const vgl_point_3d<double>& p0,
00114                               const vgl_point_3d<double>& p1,
00115                               double v0, double v1, double eps);
00116 
00117   //: The derivative of the line integral with respect to x
00118   static vgl_vector_3d<double>
00119   line_integral_deriv(const vgl_point_3d<double>& x,
00120                       const vgl_point_3d<double>& p0,
00121                       const vgl_point_3d<double>& p1,
00122                       double v0, double v1, double eps2);
00123 
00124   //: area integral of the squared weight function times a linearly interpolated value
00125   //  \a m is the point closest point on the triangle to sample point \a x
00126   //  \a pp is second closest vertex and \a pm is the furthest
00127   //  call triangle_quadrature to first split an arbitrary triangle
00128   //  \a eps2 is epsilon^2
00129   static vgl_vector_2d<double>
00130   split_triangle_quadrature(const vgl_point_3d<double>& x,
00131                             const vgl_point_3d<double>& m,
00132                             const vgl_point_3d<double>& pp,
00133                             const vgl_point_3d<double>& pm,
00134                             double v0, double v1, double v2,
00135                             double eps);
00136 
00137   //: area integral of the squared weight function times a linearly interpolated value
00138   //  \a eps2 is epsilon^2
00139   template <class T, class F>
00140   static T
00141   triangle_quadrature(F quad_func,
00142                       const vgl_point_3d<double>& x,
00143                       const vgl_point_3d<double>& p0,
00144                       const vgl_point_3d<double>& p1,
00145                       const vgl_point_3d<double>& p2,
00146                       const vgl_vector_3d<double>& n,
00147                       double v0, double v1, double v2,
00148                       double eps);
00149 
00150   //: area integral of the squared weight function times a linearly interpolated value
00151   //  Also computes vector term used in the derivative
00152   //  \a m is the point closest point on the triangle to sample point \a x
00153   //  \a pp is second closest vertex and \a pm is the furthest
00154   //  call triangle_quadrature to first split an arbitrary triangle
00155   //  \a eps2 is epsilon^2
00156   static integral_data
00157   split_triangle_quadrature_with_deriv(const vgl_point_3d<double>& x,
00158                                        const vgl_point_3d<double>& m,
00159                                        const vgl_point_3d<double>& pp,
00160                                        const vgl_point_3d<double>& pm,
00161                                        double v0, double v1, double v2,
00162                                        double eps);
00163 
00164  private:
00165 
00166   //: recursively compute the area weighted centroids
00167   void compute_centroids_rec(const vcl_auto_ptr<imesh_kd_tree_node>& node,
00168                              const vcl_set<unsigned int>& no_normal_faces);
00169 
00170   //: recursively compute the unweighted integrals
00171   void compute_unweighed_rec(const vcl_auto_ptr<imesh_kd_tree_node>& node);
00172 
00173 
00174   //: compute the iso value such that the mean value at the vertices is zero
00175   void compute_iso_level();
00176 
00177   //: adjust the phi values until all vertices are within the iso surface
00178   //  Also computes the iso level
00179   void compute_enclosing_phi();
00180 
00181   vcl_vector<vgl_point_3d<double> > verts_;     // mesh vertices
00182   vcl_auto_ptr<imesh_regular_face_array<3> > triangles_; // mesh triangles
00183 
00184   vcl_auto_ptr<imesh_kd_tree_node> kd_tree_;    // root node of a kd-tree on triangles
00185   vcl_vector<double> phi_;                      // phi values assigned per vertex
00186   vcl_vector<double> area_;                     // surface area per node
00187   vcl_vector<double> unweighted_;               // unweighted integrals of phi over the surface per node
00188   vcl_vector<vgl_point_3d<double> > centroid_;  // area weighted centroid per node
00189   vcl_vector<vgl_vector_3d<double> > normals_;  // area weighted normal per node
00190   vcl_vector<double> normal_len_;               // cached magnitude of above normals
00191 
00192   double eps2_;
00193   double lambda_;
00194   double iso_level_;
00195   bool bounded_;
00196 };
00197 
00198 
00199 //: find the zero crossing point by bisection between positive point \a pp and negative point \a pn
00200 //  Stops searching when $||p_p-p_n|| < x_{eps}$ or $|f(p_m)| < f_{eps}$
00201 vgl_point_3d<double> bisect(const imesh_imls_surface& f,
00202                             vgl_point_3d<double> pp, vgl_point_3d<double> pn,
00203                             double feps = 1e-8,  double xeps = 1e-16);
00204 
00205 
00206 //: Move the point \a p along the gradient direction until reaching a zero crossing of \a f (within \a eps).
00207 //  Return true if successful
00208 bool snap_to_surface(const imesh_imls_surface& f,
00209                      vgl_point_3d<double>& p,
00210                      double step = 0.5, double eps = 1e-5);
00211 
00212 
00213 //: Move the point \a p to minimize (f^2 + (n*f' - 1)^2)/f'*f' a zero crossing of \a f (within \a eps).
00214 //  Return true if successful
00215 bool snap_to_surface_with_normal(const imesh_imls_surface& f,
00216                                  vgl_point_3d<double>& p,
00217                                  vgl_vector_3d<double> n,
00218                                  double step = 0.5, double eps = 1e-8);
00219 
00220 
00221 //: Move the point \a p along direction \a dir until reaching a zero crossing of \a f (within \a eps).
00222 //  Return true if successful
00223 bool snap_to_surface(const imesh_imls_surface& f,
00224                      vgl_vector_3d<double> dir,
00225                      vgl_point_3d<double>& p,
00226                      double step = 0.5, double eps = 1e-5);
00227 
00228 
00229 #endif // imesh_imls_surface_h_