42 const size_t n_points = p.size();
46 std::vector<double> angle_constraints = angle_constraints_input;
52 if (std::isnan(angle_constraints[0]))
55 angles[0] = atan2(P1P2[1],P1P2[0]);
59 angles[0] = angle_constraints[0];
64 for (
size_t p_i = 1; p_i < n_points-1; ++p_i)
67 if (std::isnan(angle_constraints[p_i]))
72 const Point<2> P3P2 = points[p_i+1]-points[p_i];
75 const double angle_p1p2 = atan2(P1P2[1],P1P2[0]);
76 const double angle_p3p1 = atan2(P3P2[1],P3P2[0]);
78 const double average_angle = (angle_p1p2 + angle_p3p1)*0.5;
79 angles[p_i] = average_angle;
84 angles[p_i] = angle_constraints[p_i];
89 if (std::isnan(angle_constraints[n_points-1]))
92 angles[n_points-1] = atan2(P1P2[1],P1P2[0]);
96 angles[n_points-1] = angle_constraints[n_points-1];
108 const double fraction_of_length = 0.2;
120 const bool side_of_line_1 = (p1[0] - p2[0]) * (
control_points[0][1][1] - p1[1])
123 const bool side_of_line_2 = (p1[0] - p2[0]) * (p3[1] - p1[1])
124 - (p1[1] - p2[1]) * (p3[0] - p1[0])
126 if (side_of_line_1 == side_of_line_2)
135 for (
size_t p_i = 1; p_i < n_points-1; ++p_i)
139 const double length = (
points[p_i]-
points[p_i+1]).norm();
145 const bool side_of_line_1 = (p1[0] - p2[0]) * (
control_points[p_i-1][1][1] - p1[1])
148 const bool side_of_line_2 = (p1[0] - p2[0]) * (
control_points[p_i][0][1] - p1[1])
151 if (side_of_line_1 == side_of_line_2)
162 if (p_i+1 < n_points-1)
165 const bool side_of_line_1 = (p1[0] - p2[0]) * (
control_points[p_i][1][1] - p1[1])
168 const bool side_of_line_2 = (p1[0] - p2[0]) * (p3[1] - p1[1])
169 - (p1[1] - p2[1]) * (p3[0] - p1[0])
171 if (side_of_line_1 == side_of_line_2)
187 "Trying to access index " << i <<
", but points.size() = " <<
points.size() <<
", and control_points = " <<
control_points.size() <<
".");
194 const bool verbose)
const 198 double min_squared_distance = std::numeric_limits<double>::infinity();
204 std::stringstream output;
212 const Point<2> P1Pc = check_point-p1;
214 const double P2P2_dot = P1P2*P1P2;
216 double est = P2P2_dot > 0.0 ? std::min(1.,std::max(0.,(P1Pc*P1P2) / P2P2_dot)) : 1.0;
224 const double c_0 = -3.*points[cp_i][0] + 3.*
control_points[cp_i][0][0];
225 const double c_1 = -3.*points[cp_i][1] + 3.*
control_points[cp_i][0][1];
226 const double d_0 = points[cp_i][0];
227 const double d_1 = points[cp_i][1];
229 const double d_min_cp_0 = d_0-cp[0];
230 const double d_min_cp_1 = d_1-cp[1];
233 double estimate_point_min_cp_0_dg = a_0*est*est*est+b_0*est*est+c_0*est+d_min_cp_0;
234 double estimate_point_min_cp_1_dg = a_1*est*est*est+b_1*est*est+c_1*est+d_min_cp_1;
235 double min_squared_distance_cartesian_temp_dg = (estimate_point_min_cp_0_dg*estimate_point_min_cp_0_dg)+(estimate_point_min_cp_1_dg*estimate_point_min_cp_1_dg);
238 for (
size_t newton_i = 0; newton_i < 150; newton_i++)
241 output <<
" wolfram alpha: (" << a_0 <<
"*x^3+" << b_0 <<
"*x^2+"<< c_0 <<
"*x+" << d_0 <<
"-" << cp[0] <<
")^2+(" << a_1 <<
"*x^3+" << b_1 <<
"*x^2+"<< c_1 <<
"*x+" << d_1 <<
"-" << cp[1] <<
")^2 with x=" << est << std::endl;
243 const double est_sq = est*est;
244 const double estimate_point_min_cp_0 = a_0*est_sq*est+b_0*est_sq+c_0*est+d_min_cp_0;
245 const double estimate_point_min_cp_1 = a_1*est_sq*est+b_1*est_sq+c_1*est+d_min_cp_1;
247 const double deriv_0 = 3.0*a_0*est_sq+2.0*b_0*est+c_0;
248 const double deriv_1 = 3.0*a_1*est_sq+2.0*b_1*est+c_1;
249 const double squared_distance_cartesian = (estimate_point_min_cp_0*estimate_point_min_cp_0)+(estimate_point_min_cp_1*estimate_point_min_cp_1);
251 const double squared_distance_cartesian_derivative = 2.0*(deriv_0*estimate_point_min_cp_0 + deriv_1*estimate_point_min_cp_1);
252 const double squared_distance_cartesian_second_derivative_abs = std::fabs(2.0*((6.0*a_0*est+2.0*b_0)*estimate_point_min_cp_0 + deriv_0*deriv_0
253 + (6.0*a_1*est+2.0*b_1)*estimate_point_min_cp_1 + deriv_1*deriv_1));
255 if (squared_distance_cartesian_second_derivative_abs <= 0.0)
262 const double update = std::min(0.5,std::max(-0.5,squared_distance_cartesian_derivative/squared_distance_cartesian_second_derivative_abs));
263 double line_search = 1.;
265 if (std::fabs(update) > 1e-1)
267 double est_test = est-update*line_search;
268 double squared_distance_cartesian_test = squared_distance_cartesian;
269 double squared_distance_cartesian_test_previous = squared_distance_cartesian;
271 for (
unsigned int i = 0; i < 10; i++)
273 est_test = est-update*line_search;
274 const double est_test_sq = est_test*est_test;
275 const double estimate_point_min_cp_test_0 = a_0*est_test_sq*est_test+b_0*est_test_sq+c_0*est_test+d_min_cp_0;
276 const double estimate_point_min_cp_test_1 = a_1*est_test_sq*est_test+b_1*est_test_sq+c_1*est_test+d_min_cp_1;
278 squared_distance_cartesian_test = (estimate_point_min_cp_test_0*estimate_point_min_cp_test_0)+(estimate_point_min_cp_test_1*estimate_point_min_cp_test_1);
285 const double squared_distance_cartesian_derivative_test = 2.0*(3.0*a_0*est_test*est_test+2.0*b_0*est_test+c_0)*(a_0*est_test*est_test*est_test+b_0*est_test*est_test+c_0*est_test+d_0-cp[0])
286 + 2.0*(3.0*a_1*est_test*est_test+2.0*b_1*est_test+c_1)*(a_1*est_test*est_test*est_test+b_1*est_test*est_test+c_1*est_test+d_1-cp[1]);
287 const double squared_distance_cartesian_second_derivative_test = 2.0*(6.0*a_0*est_test + 2.0*b_0)*(a_0*est_test*est_test*est_test+b_0*est_test*est_test+c_0*est_test+d_0-cp[0])
288 + 2.0*(3.0*a_0*est_test*est_test + 2.0*b_0*est_test + c_0)*(3.0*a_0*est_test*est_test + 2.0*b_0*est_test + c_0)
289 + 2.0*(6.0*a_1*est_test + 2.0*b_1)*(a_1*est_test*est_test*est_test+b_1*est_test*est_test+c_1*est_test+d_1-cp[1])
290 + 2.0*(3.0*a_1*est_test*est_test + 2.0*b_1*est_test + c_1)*(3.0*a_1*est_test*est_test + 2.0*b_1*est_test + c_1) ;
291 output <<
" i: " << cp_i <<
", ni: " << newton_i<<
", lsi: " << i <<
", line_search_step=" << 2./3. <<
": squared_distance_cartesian_test = " << squared_distance_cartesian_test <<
", diff= " << squared_distance_cartesian_test-squared_distance_cartesian
292 <<
", tests: " << (squared_distance_cartesian_test_previous < squared_distance_cartesian ?
"true" :
"false") <<
":" << (squared_distance_cartesian_test > squared_distance_cartesian_test_previous ?
"true" :
"false") <<
", est_test=" << est_test
293 <<
", update=" << update <<
", ls=" << line_search <<
", up*ls=" << update *line_search <<
", test deriv =" << squared_distance_cartesian_derivative_test <<
", test update=" << squared_distance_cartesian_derivative_test/fabs(squared_distance_cartesian_second_derivative_test)
294 <<
", p1=" << p1 <<
", p2= " << p2 <<
", poc= " << a *est_test *est_test *est_test + b *est_test *est_test+c *est_test+d <<
", cp= " << check_point <<
", ds:" << ((a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d)-check_point).
norm_square() <<
":" << min_squared_distance_cartesian_temp_dg
295 <<
", diff = " << squared_distance_cartesian_test-min_squared_distance_cartesian_temp_dg << std::endl;
297 if (i > 0 && (squared_distance_cartesian_test > squared_distance_cartesian_test_previous))
299 if (squared_distance_cartesian_test_previous-squared_distance_cartesian < 0)
301 line_search *= 3./2.;
305 squared_distance_cartesian_test_previous = squared_distance_cartesian_test;
307 line_search *= 2./3.;
311 est -= update*line_search;
313 if (std::fabs(update) < 1e-4 || est < -0.1 || est > 1.1)
320 WBAssertThrow(found,
"Could not find a good solution. " << output.str());
322 WBAssertThrow(found,
"Could not find a good solution. Enable debug mode for more info.");
325 const double est_min_cp_end_0 = a_0*est*est*est+b_0*est*est+c_0*est+d_min_cp_0;
326 const double est_min_cp_end_1 = a_1*est*est*est+b_1*est*est+c_1*est+d_min_cp_1;
327 const double min_squared_distance_temp = (est_min_cp_end_0*est_min_cp_end_0)+(est_min_cp_end_1*est_min_cp_end_1);
328 if (min_squared_distance_temp < min_squared_distance)
330 if (est >= -1e-8 && static_cast<double>(cp_i)+est > 0 && est-1. <= 1e-8 && est-1. <
static_cast<double>(cp_i))
332 min_squared_distance = min_squared_distance_temp;
333 const Point<2> point_on_curve =
Point<2>(a_0*est*est*est+b_0*est*est+c_0*est+d_0,a_1*est*est*est+b_1*est*est+c_1*est+d_1,cp.get_coordinate_system());
334 WBAssert(!std::isnan(point_on_curve[0]) && !std::isnan(point_on_curve[1]),
"Point on curve has NAN entries: " << point_on_curve);
338 const Point<2> derivative_point = points[cp_i]*((6.-3.*est)*est-3.) +
control_points[cp_i][0]*(est*(9*est-12)+3)
339 +
control_points[cp_i][1]*(6.-9.*est)*est + points[cp_i+1]*3.*est*est;
341 Point<2> tangent_point = derivative_point - point_on_curve;
343 const double dot_product = (tangent_point*(check_point-point_on_curve));
344 const double sign = dot_product < 0. ? -1. : 1.;
347 closest_point_on_curve.
distance = sign*std::sqrt(min_squared_distance);
350 closest_point_on_curve.
index = cp_i;
351 closest_point_on_curve.
point = point_on_curve;
352 WBAssert(!std::isnan(point_on_curve[0]) && !std::isnan(point_on_curve[1]),
"Point on curve has NAN entries: " << point_on_curve);
355 Point<2> derivative =
Point<2>(a_0*est*est+b_0*est+c_0,a_1*est*est+b_1*est+c_1,cp.get_coordinate_system());
357 const double normal_size = derivative.
norm();
358 if (normal_size > 0.)
360 normal[0] = derivative[1]/normal_size;
361 normal[1] = -derivative[0]/normal_size;
364 closest_point_on_curve.
normal = normal;
371 const double cos_cp_lat =
cos(cp[1]);
378 const Point<2> P1Pc = check_point-p1;
380 const double P2P2_dot = P1P2*P1P2;
382 double est = P2P2_dot > 0.0 ? std::min(1.,std::max(0.,(P1Pc*P1P2) / P2P2_dot)) : 1.0;
386 std::stringstream output;
393 Point<2> estimate_point = a*est*est*est+b*est*est+c*est+d;
398 double min_squared_distance_cartesian_temp_dg =
NaN::DSNAN;
401 cos_lat_dg =
cos(estimate_point[1]);
402 sin_d_long_h_dg =
sin((estimate_point[0]-cp[0])*0.5);
403 sin_d_lat_h_dg =
sin((estimate_point[1]-cp[1])*0.5);
404 min_squared_distance_cartesian_temp_dg = sin_d_lat_h_dg*sin_d_lat_h_dg+sin_d_long_h_dg*sin_d_long_h_dg*cos_cp_lat*cos_lat_dg;
405 output <<
"cp_i=" << cp_i <<
", init est = " << est <<
", min_squared_distance = " << min_squared_distance <<
", min_squared_distance_cartesian_temp_dg: " << min_squared_distance_cartesian_temp_dg <<
", p1: " << p1 <<
", p2: " << p2 << std::endl;
406 output << std::setprecision(6) <<
" wolfram: sin((" << a[1] <<
"*x^3+" << b[1] <<
"*x^2+"<< c[1] <<
"*x+" << d[1] <<
"-" << cp[1] <<
")*.5)^2+sin((" << a[0] <<
"*x^3+" << b[0] <<
"*x^2+"<< c[0] <<
"*x+" << d[0] <<
"-" << cp[0] <<
")*.5)^2*cos(" << cp[1] <<
")*cos(" << a[1] <<
"*x^3+" << b[1] <<
"*x^2+"<< c[1] <<
"*x+" << d[1] <<
"-" << cp[1] <<
") with x=" << est << std::endl;
407 output << std::setprecision(10) <<
" python: y=np.sin((" << a[1] <<
"*x**3+" << b[1] <<
"*x**2+"<< c[1] <<
"*x+" << d[1] <<
"-" << cp[1] <<
")*.5)**2+np.sin((" << a[0] <<
"*x**3+" << b[0] <<
"*x**2+"<< c[0] <<
"*x+" << d[0] <<
"-" << cp[0] <<
")*.5)**2*np.cos(" << cp[1] <<
")*np.cos(" << a[1] <<
"*x**3+" << b[1] <<
"*x**2+"<< c[1] <<
"*x+" << d[1] <<
"-" << cp[1] <<
"); x=" << est << std::endl;
409 for (
size_t newton_i = 0; newton_i < 150; newton_i++)
412 estimate_point = a*est*est*est+b*est*est+c*est+d;
414 double sin_d_long_h =
sin((estimate_point[0]-cp[0])*0.5);
415 double sin_d_lat_h =
sin((estimate_point[1]-cp[1])*0.5);
416 const double cos_d_lat =
cos(estimate_point[1]-cp[1]);
417 const double squared_distance_cartesian = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*cos_d_lat;
419 double sin_dlat =
sin(estimate_point[1]-cp[1]);
420 const double cos_dlong_h =
cos(0.5*(estimate_point[0]-cp[0]));
421 double cos_dlat_h =
cos(0.5*(estimate_point[1]-cp[1]));
422 double deriv_long = (3.0*a[0]*est*est+2.0*b[0]*est+c[0]);
423 double deriv_lat = (3.0*a[1]*est*est+2.0*b[1]*est+c[1]);
425 const double squared_distance_cartesian_derivative = cos_cp_lat*(-deriv_lat)*sin_d_long_h*sin_d_long_h*sin_dlat+cos_cp_lat*deriv_long*sin_d_long_h*cos_dlong_h*cos_d_lat+deriv_lat*sin_d_lat_h*cos_dlat_h;
427 if (std::fabs(squared_distance_cartesian_derivative) > 1e-15)
429 const double squared_distance_cartesian_second_derivative = cos_cp_lat*cos_d_lat*(-0.5*deriv_long*deriv_long*sin_d_long_h*sin_d_long_h+0.5*deriv_long*deriv_long*cos_dlong_h*cos_dlong_h+(6.0*a[0]*est+2.0*b[0])*sin_d_long_h*cos_dlong_h)+cos_cp_lat*sin_d_long_h*sin_d_long_h*(deriv_lat*deriv_lat*(-cos_d_lat)-(6.0*a[1]*est+2.0*b[1])*sin_dlat)-2.0*cos_cp_lat*deriv_long*deriv_lat*sin_d_long_h*cos_dlong_h*sin_dlat-0.5*deriv_lat*deriv_lat*sin_d_lat_h*sin_d_lat_h+0.5*deriv_lat*deriv_lat*cos_dlat_h*cos_dlat_h+(6.0*a[1]*est+2.0*b[1])*sin_d_lat_h*cos_dlat_h;
433 const double squared_distance_cartesian_full =
sin((a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])*0.5)*
sin((a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])*0.5)+
sin((a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0])*0.5)*
sin((a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0])*0.5)*
cos(cp[1])*
cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]);
434 const double squared_distance_cartesian_derivative_full =
cos(cp[1])*(-(3.0*a[1]*est*est+2.0*b[1]*est+c[1]))*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
sin(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])+
cos(cp[1])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])+(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*
sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*
cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]));
435 const double squared_distance_cartesian_second_derivative_full =
cos(cp[1])*
cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])*(-0.5*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))+0.5*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*
cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))+(6.0*a[0]*est+2.0*b[0])*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0])))+
cos(cp[1])*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*((3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(-
cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))-(6.0*a[1]*est+2.0*b[1])*
sin(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))-2.0*
cos(cp[1])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*
sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*
sin(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])-0.5*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*
sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*
sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))+0.5*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*
cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*
cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))+(6.0*a[1]*est+2.0*b[1])*
sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*
cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]));
436 output <<
"sqd = " << squared_distance_cartesian <<
":" << squared_distance_cartesian_full <<
", diff=" << squared_distance_cartesian-squared_distance_cartesian_full <<
", sqdd: " << squared_distance_cartesian_derivative <<
":" << squared_distance_cartesian_derivative_full <<
", diff="<< squared_distance_cartesian_derivative-squared_distance_cartesian_derivative_full <<
", sqdd: " << squared_distance_cartesian_second_derivative <<
":" << squared_distance_cartesian_second_derivative_full <<
", diff= " << squared_distance_cartesian_second_derivative-squared_distance_cartesian_second_derivative_full <<
", est: " << est << std::endl;
439 update = std::min(0.5,std::max(-0.5,squared_distance_cartesian_derivative/std::fabs(squared_distance_cartesian_second_derivative)));
440 double line_search = 1.;
441 double est_test = est-update*line_search;
442 double squared_distance_cartesian_test = squared_distance_cartesian;
443 double squared_distance_cartesian_test_previous = squared_distance_cartesian;
444 double line_search_step = 2./3.;
446 for (
unsigned int i = 0; i < 10; i++)
448 est_test = est-update*line_search;
449 estimate_point = a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d;
451 sin_d_long_h =
sin((estimate_point[0]-cp[0])*0.5);
452 sin_d_lat_h =
sin((estimate_point[1]-cp[1])*0.5);
453 squared_distance_cartesian_test = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*
cos(estimate_point[1]-cp[1]);
457 sin_dlat =
sin(estimate_point[1]-cp[1]);
458 deriv_long = (3.0*a[0]*est_test*est_test+2.0*b[0]*est_test+c[0]);
459 deriv_lat = (3.0*a[1]*est_test*est_test+2.0*b[1]*est_test+c[1]);
460 const double squared_distance_cartesian_derivative_test = cos_cp_lat*(-deriv_lat)*sin_d_long_h*sin_d_long_h*sin_dlat+cos_cp_lat*deriv_long*sin_d_long_h*cos_dlong_h*cos_d_lat+deriv_lat*sin_d_lat_h*cos_dlat_h;
461 const double squared_distance_cartesian_second_derivative_test = cos_cp_lat*cos_d_lat*(-0.5*deriv_long*deriv_long*sin_d_long_h*sin_d_long_h+0.5*deriv_long*deriv_long*cos_dlong_h*cos_dlong_h+(6.0*a[0]*est_test+2.0*b[0])*sin_d_long_h*cos_dlong_h)+cos_cp_lat*sin_d_long_h*sin_d_long_h*(deriv_lat*deriv_lat*(-cos_d_lat)-(6.0*a[1]*est_test+2.0*b[1])*sin_dlat)-2.0*cos_cp_lat*deriv_long*deriv_lat*sin_d_long_h*cos_dlong_h*sin_dlat-0.5*deriv_lat*deriv_lat*sin_d_lat_h*sin_d_lat_h+0.5*deriv_lat*deriv_lat*cos_dlat_h*cos_dlat_h+(6.0*a[1]*est_test+2.0*b[1])*sin_d_lat_h*cos_dlat_h;
462 output <<
" i: " << cp_i <<
", ni: " << newton_i<<
", lsi: " << i <<
", line_search_step=" << line_search_step <<
": squared_distance_cartesian_test = " << squared_distance_cartesian_test <<
", diff= " << squared_distance_cartesian_test-squared_distance_cartesian <<
", tests: " << (squared_distance_cartesian_test_previous < squared_distance_cartesian ?
"true" :
"false") <<
":" << (squared_distance_cartesian_test > squared_distance_cartesian_test_previous ?
"true" :
"false") <<
", est_test=" << est_test <<
", update=" << update <<
", ls=" << line_search <<
", up*ls=" << update *line_search <<
", test deriv =" << squared_distance_cartesian_derivative_test <<
", test update=" << squared_distance_cartesian_derivative_test/fabs(squared_distance_cartesian_second_derivative_test) <<
", p1=" << p1 <<
", p2= " << p2 <<
", poc= " << a *est_test *est_test *est_test+b *est_test *est_test+c *est_test+d <<
", cp= " << check_point <<
", ds:" << ((a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d)-check_point).
norm_square() <<
":" << min_squared_distance_cartesian_temp_dg <<
", diff = " << squared_distance_cartesian_test-min_squared_distance_cartesian_temp_dg<< std::endl;
464 if (i > 0 && (squared_distance_cartesian_test > squared_distance_cartesian_test_previous))
466 if (squared_distance_cartesian_test_previous-squared_distance_cartesian < 0)
468 line_search *= 1/line_search_step;
473 line_search *= (1/line_search_step)*(1/line_search_step);
474 est_test = est-update*line_search;
475 estimate_point = a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d;
477 sin_d_long_h =
sin((estimate_point[0]-cp[0])*0.5);
478 sin_d_lat_h =
sin((estimate_point[1]-cp[1])*0.5);
479 squared_distance_cartesian_test_previous = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*
cos(estimate_point[1]-cp[1]);
480 line_search_step = std::min(line_search_step*(11./10.),0.95);
484 squared_distance_cartesian_test_previous = squared_distance_cartesian_test;
486 line_search *= line_search_step;
490 output <<
" i: " << cp_i <<
", ni: " << newton_i<<
", est= " << est-update *line_search <<
", ls:" << line_search <<
": squared_distance_cartesian_test = " << squared_distance_cartesian_test <<
", diff= " << squared_distance_cartesian_test-squared_distance_cartesian << std::endl;
492 est -= update*line_search;
495 if (std::fabs(squared_distance_cartesian_derivative) <= 1e-15 || std::fabs(update) < 1e-4 || est < -0.1 || est > 1.1)
502 if (verbose ==
true && found ==
false)
505 WBAssertThrow(found,
"Could not find a good solution. " << output.str());
507 else if (verbose ==
false && found ==
false)
513 estimate_point = a*est*est*est+b*est*est+c*est+d;
515 const double sin_d_long_h =
sin((estimate_point[0]-cp[0])*0.5);
516 const double sin_d_lat_h =
sin((estimate_point[1]-cp[1])*0.5);
518 const double min_squared_distance_cartesian_temp = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*
cos(estimate_point[1]-cp[1]);
520 if (min_squared_distance_cartesian_temp < min_squared_distance)
522 if (est >= -1e-8 && static_cast<double>(cp_i)+est > 0 && est-1. <= 1e-8 && est-1. < static_cast<double>(cp_i))
524 min_squared_distance = min_squared_distance_cartesian_temp;
525 const Point<2> point_on_curve = a*est*est*est+b*est*est+c*est+d;
530 const Point<2> derivative_point = points[cp_i]*((6.-3.*est)*est-3.) +
control_points[cp_i][0]*(est*(9*est-12)+3)
531 +
control_points[cp_i][1]*(6.-9.*est)*est + points[cp_i+1]*3.*est*est;
533 Point<2> tangent_point = derivative_point - point_on_curve;
535 const double dot_product = (tangent_point*(check_point-point_on_curve));
536 const double sign = dot_product < 0. ? -1. : 1.;
539 closest_point_on_curve.
distance = sign*std::sqrt(min_squared_distance);
542 closest_point_on_curve.
index = cp_i;
543 closest_point_on_curve.
point = point_on_curve;
546 Point<2> derivative = a*est*est+b*est+c;
548 const double normal_size = derivative.
norm();
549 if (normal_size > 0.)
551 normal[0] = derivative[1]/normal_size;
552 normal[1] = -derivative[0]/normal_size;
555 closest_point_on_curve.
normal = normal;
561 return closest_point_on_curve;
Point< 2 > operator()(const size_t i, const double x) const
BezierCurve()=default
Construct a new Bezier Curve object.
double norm_square() const
double parametric_fraction
double interpolation_fraction
std::vector< Point< 2 > > points
std::vector< std::array< Point< 2 >, 2 > > control_points
CoordinateSystem get_coordinate_system() const
#define WBAssert(condition, message)
std::vector< double > angles
double cos(const double angle)
ClosestPointOnCurve closest_point_on_curve_segment(const Point< 2 > &p, const bool verbose=false) const
Finds the closest point on the curve. If the the closest point doesn't fall on the segment...
#define WBAssertThrow(condition, message)
std::vector< double > lengths
double sin(const double raw_angle)