| 438 | } |
| 439 | |
| 440 | static PJ_UV complex_iterative_inverse_impl(PJ *P, const HORNER *transformation, |
| 441 | PJ_UV position) { |
| 442 | |
| 443 | double n, e; |
| 444 | // in this case fwd_origin and any existing flipping needs to be added in |
| 445 | // the end |
| 446 | e = position.u; |
| 447 | n = position.v; |
| 448 | |
| 449 | if (coords_out_of_range(P, transformation, n, e)) { |
| 450 | return generate_error_coords(); |
| 451 | } |
| 452 | |
| 453 | { |
| 454 | // complex real part corresponds to Northing, imag part to Easting |
| 455 | const double tol = transformation->inverse_tolerance; |
| 456 | const std::complex<double> dZ(n - transformation->fwd_c[0], |
| 457 | e - transformation->fwd_c[1]); |
| 458 | std::complex<double> w0(0.0, 0.0); |
| 459 | int loops = 32; // usually converges really fast (1-2 loops) |
| 460 | bool converged = false; |
| 461 | while (loops-- > 0 && !converged) { |
| 462 | // sum coefficient pointers from back to front until the first |
| 463 | // complex pair (fwd_c0+i*fwd_c1) |
| 464 | const double *c = transformation->fwd_c; |
| 465 | PJ_UV en = {w0.imag(), w0.real()}; |
| 466 | en = complex_horner_eval(transformation->order, c, en, 1); |
| 467 | std::complex<double> det(en.v, en.u); |
| 468 | std::complex<double> w1 = dZ / det; |
| 469 | converged = (fabs(w1.real() - w0.real()) < tol) && |
| 470 | (fabs(w1.imag() - w0.imag()) < tol); |
| 471 | w0 = w1; |
| 472 | } |
| 473 | // if loops have been exhausted and we have not converged yet, |
| 474 | // we are never going to converge |
| 475 | if (!converged) { |
| 476 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM); |
| 477 | position = generate_error_coords(); |
| 478 | } else { |
| 479 | double E = w0.imag(); |
| 480 | double N = w0.real(); |
| 481 | if (transformation->uneg) |
| 482 | E = -E; |
| 483 | if (transformation->vneg) |
| 484 | N = -N; |
| 485 | position.u = E + transformation->fwd_origin->u; |
| 486 | position.v = N + transformation->fwd_origin->v; |
| 487 | } |
| 488 | return position; |
| 489 | } |
| 490 | } |
| 491 | |
| 492 | static void complex_horner_forward_4d(PJ_COORD &point, PJ *P) { |
| 493 | const HORNER *transformation = reinterpret_cast<const HORNER *>(P->opaque); |
no test coverage detected