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