1 #include <iostream>
2 #include "testlib/testlib_test.h"
3 #include <imesh/algo/imesh_imls_surface.h>
4 #include "test_share.h"
5 #include <imesh/algo/imesh_transform.h>
6 #ifdef _MSC_VER
7 #  include "vcl_msvc_warnings.h"
8 #endif
9 
10 #include <imesh/imesh_fileio.h>
11 #include <imesh/imesh_operations.h>
12 #include "vnl/vnl_matlab_filewrite.h"
13 #include "vnl/vnl_matrix.h"
14 #include "vnl/vnl_math.h"
15 
approx_deriv(const imesh_imls_surface & f,const vgl_point_3d<double> & p,vgl_vector_3d<double> & dp,double eps=1e-6)16 double approx_deriv(const imesh_imls_surface& f,
17                     const vgl_point_3d<double>& p,
18                     vgl_vector_3d<double>& dp, double eps = 1e-6)
19 {
20   double fp = f(p);
21   double fpx = f(p+vgl_vector_3d<double>(eps,0,0));
22   double fpy = f(p+vgl_vector_3d<double>(0,eps,0));
23   double fpz = f(p+vgl_vector_3d<double>(0,0,eps));
24   dp.set((fpx-fp)/eps, (fpy-fp)/eps, (fpz-fp)/eps);
25   return fp;
26 }
27 
28 
test_imls_surface()29 static void test_imls_surface()
30 {
31   double I1,Ix;
32   double k1 = 1.5, k2 = 4.0;
33   imesh_imls_surface::line_integrals(k1,k2,I1,Ix);
34   double I1_,Ix_,dI1,dIx,dIx2;
35   imesh_imls_surface::line_integrals(k1,k2,I1_,Ix_,dI1,dIx,dIx2);
36 
37   // numerical integration by trapezoid rule
38   double quad_I1 = 0.0, quad_Ix = 0.0;
39   double quad_dI1 = 0.0, quad_dIx = 0.0, quad_dIx2 = 0.0;
40   double step = 0.00001;
41   for (double i=step/2.0; i<1.0; i+=step) {
42     double x_pk1 = i+k1;
43     double x_pk1_2 = x_pk1*x_pk1;
44     double x_pk1_2_pk2 = x_pk1_2 + k2;
45     double x_pk1_2_pk2_2 = x_pk1_2_pk2 * x_pk1_2_pk2;
46     double x_pk1_2_pk2_3 = x_pk1_2_pk2_2 * x_pk1_2_pk2;
47     quad_I1 += 1.0 / x_pk1_2_pk2_2;
48     quad_Ix += i / x_pk1_2_pk2_2;
49     quad_dI1 += 1.0 / x_pk1_2_pk2_3;
50     quad_dIx += i / x_pk1_2_pk2_3;
51     quad_dIx2 += i*i / x_pk1_2_pk2_3;
52   }
53   quad_I1 *= step;
54   quad_Ix *= step;
55   quad_dI1 *= step;
56   quad_dIx *= step;
57   quad_dIx2 *= step;
58 
59   TEST_NEAR("Line Integral 1",I1, quad_I1, 1e-12);
60   TEST_NEAR("Line Integral X",Ix, quad_Ix, 1e-12);
61   TEST_NEAR("Line Integral d1",dI1, quad_dI1, 1e-12);
62   TEST_NEAR("Line Integral dX",dIx, quad_dIx, 1e-12);
63   TEST_NEAR("Line Integral dX^2",dIx2, quad_dIx2, 1e-12);
64   TEST("Derivative version same", I1 == I1_ && Ix == Ix_, true);
65 
66   vgl_point_3d<double> p0(-1,3,.5), p1(3,4,2), x(1,2,0);
67   double v0=1, v1=3, eps2=.01*.01;
68   double li = imesh_imls_surface::line_integral(x,p0,p1,v0,v1,eps2);
69 
70   vgl_vector_3d<double> diff(p1-p0);
71   double quad_li = 0.0;
72   for (double i=step/2.0; i<1.0; i+=step) {
73     vgl_point_3d<double> p = p0 + i*diff;
74     double val = v0 + i*(v1-v0);
75 
76     double s = ((p-x).sqr_length() + eps2);
77     quad_li += val / (s*s);
78   }
79   quad_li *= step * diff.length();
80 
81   TEST_NEAR("Line Integral 3D",li, quad_li, 1e-10);
82 
83   {
84     vgl_vector_3d<double> deriv_x
85         = imesh_imls_surface::line_integral_deriv(x,p0,p1,v0,v1,eps2);
86     double eps = 1e-7;
87     double dx = imesh_imls_surface::line_integral(x+vgl_vector_3d<double>(eps,0,0),
88                                                   p0,p1,v0,v1,eps2) - li;
89     double dy = imesh_imls_surface::line_integral(x+vgl_vector_3d<double>(0,eps,0),
90                                                   p0,p1,v0,v1,eps2) - li;
91     double dz = imesh_imls_surface::line_integral(x+vgl_vector_3d<double>(0,0,eps),
92                                                   p0,p1,v0,v1,eps2) - li;
93     vgl_vector_3d<double> step_deriv_x(dx/eps,dy/eps,dz/eps);
94     TEST_NEAR("Line Integral of deriv 3D",(step_deriv_x - deriv_x).length(), 0.0, eps);
95   }
96 
97   vgl_point_3d<double> p2(2,0,-4);
98   double v2 = 2;
99 
100   // project x onto the triangle plane
101   vgl_vector_3d<double> n = normalized(cross_product(p1-p0,p2-p0));
102   x -= .90*dot_product(n,x-p0)*n;
103 
104   double alpha = 2.0/3.0;
105   double u=alpha;
106   double last_li = 0.0;
107   double sum = 0.0;
108   vgl_vector_3d<double> sum_dx(0,0,0), last_dx(0,0,0);
109   for (; u>0.01; u*=alpha) {
110     vgl_point_3d<double> p0i((1-u)*p0.x() + u*p2.x(),(1-u)*p0.y() + u*p2.y(),(1-u)*p0.z() + u*p2.z());
111     vgl_point_3d<double> p1i((1-u)*p1.x() + u*p2.x(),(1-u)*p1.y() + u*p2.y(),(1-u)*p1.z() + u*p2.z());
112     double v0i = (1-u)*v0 + u*v2;
113     double v1i = (1-u)*v1 + u*v2;
114     li = imesh_imls_surface::line_integral(x,p0i,p1i,v0i,v1i,eps2);
115     vgl_vector_3d<double> dx = imesh_imls_surface::line_integral_deriv(x,p0i,p1i,v0i,v1i,eps2);
116     double i_size = u/alpha - u;
117     sum += i_size*(li + last_li)/2.0;
118     sum_dx += i_size*(dx + last_dx)/2.0;
119     last_li = li;
120     last_dx = dx;
121   }
122 
123   li = imesh_imls_surface::line_integral(x,p0,p1,v0,v1,eps2);
124   vgl_vector_3d<double> dx = imesh_imls_surface::line_integral_deriv(x,p0,p1,v0,v1,eps2);
125   sum += u/alpha*(li + last_li)/2.0;
126   sum_dx += u/alpha*(dx + last_dx)/2.0;
127 
128   sum *= cross_product(p2-p0,p1-p0).length() / (p1-p0).length();
129   sum_dx *= cross_product(p2-p0,p1-p0).length() / (p1-p0).length();
130 
131   std::cout << "integral 1 = "<<sum << std::endl
132            << "integral 1 dx = "<<sum_dx << std::endl;
133 
134   vgl_vector_2d<double> ii = imesh_imls_surface::split_triangle_quadrature(x,p0,p1,p2,v0,v1,v2,eps2);
135   std::cout << "integral 2 = "<<ii.x()<<std::endl;
136 
137   imesh_imls_surface::integral_data id =
138       imesh_imls_surface::split_triangle_quadrature_with_deriv(x,p0,p1,p2,v0,v1,v2,eps2);
139   std::cout << "integral 2 dx = "<<id.dI_phi<<std::endl;
140 
141   TEST_NEAR("Same with and without deriv (phi)", ii.x(), id.I_phi, 2e-10);
142   TEST_NEAR("Same with and without deriv ", ii.y(), id.I, 1e-10);
143 
144   n = cross_product(p1-p0,p2-p0)/2.0;
145   {
146     typedef vgl_vector_2d<double> T;
147     typedef vgl_vector_2d<double> (*F) (const vgl_point_3d<double>&, const vgl_point_3d<double>&,
148                                         const vgl_point_3d<double>&, const vgl_point_3d<double>&,
149                                         double, double, double, double);
150     T data = imesh_imls_surface::triangle_quadrature<T,F>(imesh_imls_surface::split_triangle_quadrature,
151                                                           x,p0,p1,p2,n,v0,v1,v2,eps2);
152     std::cout << "integral 3 = "<<data<<std::endl;
153   }
154 
155   {
156     typedef imesh_imls_surface::integral_data T;
157     typedef T (*F) (const vgl_point_3d<double>&, const vgl_point_3d<double>&,
158                     const vgl_point_3d<double>&, const vgl_point_3d<double>&,
159                     double, double, double, double);
160     T data = imesh_imls_surface::triangle_quadrature<T,F>
161                    (imesh_imls_surface::split_triangle_quadrature_with_deriv,
162                     x,p0,p1,p2,n,v0,v1,v2,eps2);
163     std::cout << "integral 3a = "<< data.I << ' ' << data.I_phi
164              << ' ' <<data.dI << ' ' << data.dI_phi << std::endl;
165   }
166 
167   {
168     unsigned int num_samps = 1000;
169     double sum = 0.0;
170     vgl_vector_3d<double> sum_dx(0,0,0);
171     for (unsigned i=0; i<num_samps; ++i) {
172       double u = (i+0.5)/num_samps;
173       for (unsigned j=0; j<num_samps-i; ++j) {
174         double v = (j+0.5)/num_samps;
175         double t = 1.0-u-v;
176         vgl_point_3d<double> p(t*p0.x() + u*p1.x() + v*p2.x(),
177                                t*p0.y() + u*p1.y() + v*p2.y(),
178                                t*p0.z() + u*p1.z() + v*p2.z());
179         double val = t*v0 + u*v1 + v*v2;
180         double w = 1.0/((p-x).sqr_length()+eps2);
181         if (i+j+1 == num_samps) {
182           sum += val*w*w/2.0;
183           sum_dx += 4*(p-x)*val*w*w*w/2.0;
184         }
185         else {
186           sum += val*w*w;
187           sum_dx += 4*(p-x)*val*w*w*w;
188         }
189       }
190     }
191     sum /= num_samps * num_samps;
192     sum *= cross_product(p1-p0, p2-p0).length();
193     sum_dx /= num_samps * num_samps;
194     sum_dx *= cross_product(p1-p0, p2-p0).length();
195     std::cout << "true integral = " << sum << std::endl
196              << "true integral of dx = " << sum_dx << std::endl
197              << "area = " << cross_product(p1-p0, p2-p0).length()/2.0 << std::endl;
198   }
199 
200   {
201     imesh_mesh cube;
202     make_cube(cube);
203     imesh_transform_inplace(cube, vgl_rotation_3d<double>(0,0,vnl_math::pi_over_4));
204     imesh_quad_subdivide(cube);
205     imesh_quad_subdivide(cube);
206     std::set<unsigned int> no_normals;
207     for (unsigned int i=32; i<64; i+=2) {
208       no_normals.insert(i);
209     }
210     imesh_imls_surface f(cube,.1,.1,true,no_normals);
211 
212     //imesh_write_obj("cube.obj",cube);
213 
214     vgl_point_3d<double> p(3.0,.5,.1);
215     vgl_vector_3d<double> dp, dp2;
216     double fval = approx_deriv(f,p,dp,1e-8);
217     double fval2 = f.deriv(p,dp2);
218     TEST_NEAR("Evaluation same with deriv",fval, fval2, 1e-10);
219     // FIXME: can this derivative be made more accurate?
220     TEST_NEAR("Function derivative",(dp-dp2).length(),0.0,1e-3);
221 
222 #if 0
223     vnl_matrix<double> M(200,200);
224     for (int i=0; i<200; ++i) {
225       std::cout << "row "<< i<<std::endl;
226       for (int j=0; j<200; ++j) {
227         M(i,j) = f(double(i-100)/50.0, double(j-100)/50.0, 0.25);
228       }
229     }
230     vnl_matlab_filewrite mfw("slice.mat");
231     mfw.write(M,"M");
232 #endif
233   }
234 }
235 
236 TESTMAIN(test_imls_surface);
237