134 T
const* a,
int size, T sin_arg_r, T cos_arg_r, T sinh_arg_i, T cosh_arg_i, T* R, T* I)
136 T r, i, hr, hr1, hr2, hi, hi1, hi2;
217 if (dir == direction::FORWARD)
218 return forward(coord);
220 return inverse(coord);
223 static constexpr T utm_central_meridian = T{500000};
225 static constexpr T utm_central_parallel(
hemisphere h)
227 return (h == hemisphere::NORTH) ? T{0} : T{10000000};
238 params_ = input_params;
241 auto& params = params_;
242 auto& tmerc_params = params_.tmerc_params_;
247 params.x0 = utm_central_meridian;
248 params.y0 = utm_central_parallel(params.utm_hemisphere_);
250 if (params.utm_zone_ > 0 && params.utm_zone_ <= 60) {
253 params.utm_zone_ = lround((floor((detail::wrap_to_pi(params.lam0_) + M_PI) * 30. / M_PI)));
254 params.utm_zone_ = std::clamp(params.utm_zone_, 0, 59);
257 params.lam0_ = (params.utm_zone_ + .5) * M_PI / 30. - M_PI;
258 params.k0 = T{0.9996};
270 tmerc_params.cgb[0] =
272 (2 + n * (-2 / 3.0 + n * (-2 + n * (116 / 45.0 + n * (26 / 45.0 + n * (-2854 / 675.0))))));
273 tmerc_params.cbg[0] =
274 n * (-2 + n * (2 / 3.0 +
275 n * (4 / 3.0 + n * (-82 / 45.0 + n * (32 / 45.0 + n * (4642 / 4725.0))))));
277 tmerc_params.cgb[1] =
278 np * (7 / 3.0 + n * (-8 / 5.0 + n * (-227 / 45.0 + n * (2704 / 315.0 + n * (2323 / 945.0)))));
279 tmerc_params.cbg[1] =
280 np * (5 / 3.0 + n * (-16 / 15.0 + n * (-13 / 9.0 + n * (904 / 315.0 + n * (-1522 / 945.0)))));
283 tmerc_params.cgb[2] =
284 np * (56 / 15.0 + n * (-136 / 35.0 + n * (-1262 / 105.0 + n * (73814 / 2835.0))));
285 tmerc_params.cbg[2] =
286 np * (-26 / 15.0 + n * (34 / 21.0 + n * (8 / 5.0 + n * (-12686 / 2835.0))));
289 tmerc_params.cgb[3] = np * (4279 / 630.0 + n * (-332 / 35.0 + n * (-399572 / 14175.0)));
290 tmerc_params.cbg[3] = np * (1237 / 630.0 + n * (-12 / 5.0 + n * (-24832 / 14175.0)));
292 tmerc_params.cgb[4] = np * (4174 / 315.0 + n * (-144838 / 6237.0));
293 tmerc_params.cbg[4] = np * (-734 / 315.0 + n * (109598 / 31185.0));
295 tmerc_params.cgb[5] = np * (601676 / 22275.0);
296 tmerc_params.cbg[5] = np * (444337 / 155925.0);
302 tmerc_params.Qn = params.k0 / (1 + n) * (1 + np * (1 / 4.0 + np * (1 / 64.0 + np / 256.0)));
306 tmerc_params.utg[0] =
309 n * (-37 / 96.0 + n * (1 / 360.0 + n * (81 / 512.0 + n * (-96199 / 604800.0))))));
310 tmerc_params.gtu[0] =
311 n * (0.5 + n * (-2 / 3.0 + n * (5 / 16.0 + n * (41 / 180.0 +
312 n * (-127 / 288.0 + n * (7891 / 37800.0))))));
313 tmerc_params.utg[1] =
315 n * (-1 / 15.0 + n * (437 / 1440.0 + n * (-46 / 105.0 + n * (1118711 / 3870720.0)))));
316 tmerc_params.gtu[1] =
318 n * (-3 / 5.0 + n * (557 / 1440.0 + n * (281 / 630.0 + n * (-1983433 / 1935360.0)))));
320 tmerc_params.utg[2] =
321 np * (-17 / 480.0 + n * (37 / 840.0 + n * (209 / 4480.0 + n * (-5569 / 90720.0))));
322 tmerc_params.gtu[2] =
323 np * (61 / 240.0 + n * (-103 / 140.0 + n * (15061 / 26880.0 + n * (167603 / 181440.0))));
325 tmerc_params.utg[3] = np * (-4397 / 161280.0 + n * (11 / 504.0 + n * (830251 / 7257600.0)));
326 tmerc_params.gtu[3] = np * (49561 / 161280.0 + n * (-179 / 168.0 + n * (6601661 / 7257600.0)));
328 tmerc_params.utg[4] = np * (-4583 / 161280.0 + n * (108847 / 3991680.0));
329 tmerc_params.gtu[4] = np * (34729 / 80640.0 + n * (-3418889 / 1995840.0));
331 tmerc_params.utg[5] = np * (-20648693 / 638668800.0);
332 tmerc_params.gtu[5] = np * (212378941 / 319334400.0);
335 T
const Z = detail::gatg(
336 tmerc_params.cbg,
ETMERC_ORDER, params.phi0, cos(2 * params.phi0), sin(2 * params.phi0));
341 -tmerc_params.Qn * (Z + detail::clenshaw_real(tmerc_params.gtu,
ETMERC_ORDER, 2 * Z));
353 CUPROJ_HOST_DEVICE Coordinate forward(Coordinate
const& coord)
const
356 auto& tmerc_params = this->params_.tmerc_params_;
357 auto&
ellipsoid = this->params_.ellipsoid_;
361 detail::gatg(tmerc_params.cbg,
ETMERC_ORDER, coord.y, cos(2 * coord.y), sin(2 * coord.y));
364 T
const sin_Cn = sin(Cn);
365 T
const cos_Cn = cos(Cn);
366 T
const sin_Ce = sin(coord.x);
367 T
const cos_Ce = cos(coord.x);
369 T
const cos_Cn_cos_Ce = cos_Cn * cos_Ce;
370 Cn = atan2(sin_Cn, cos_Cn_cos_Ce);
372 T
const inv_denom_tan_Ce = 1. / hypot(sin_Cn, cos_Cn_cos_Ce);
373 T
const tan_Ce = sin_Ce * cos_Cn * inv_denom_tan_Ce;
381 T Ce = asinh(tan_Ce);
396 T
const two_inv_denom_tan_Ce = 2 * inv_denom_tan_Ce;
397 T
const two_inv_denom_tan_Ce_square = two_inv_denom_tan_Ce * inv_denom_tan_Ce;
398 T
const tmp_r = cos_Cn_cos_Ce * two_inv_denom_tan_Ce_square;
399 T
const sin_arg_r = sin_Cn * tmp_r;
400 T
const cos_arg_r = cos_Cn_cos_Ce * tmp_r - 1;
420 T
const sinh_arg_i = tan_Ce * two_inv_denom_tan_Ce;
421 T
const cosh_arg_i = two_inv_denom_tan_Ce_square - 1;
424 Cn += detail::clenshaw_complex(
425 tmerc_params.gtu,
ETMERC_ORDER, sin_arg_r, cos_arg_r, sinh_arg_i, cosh_arg_i, &dCn, &dCe);
430 "Coordinate transform outside projection domain");
431 Coordinate xy{0.0, 0.0};
432 xy.y = tmerc_params.Qn * Cn + tmerc_params.Zb;
433 xy.x = tmerc_params.Qn * Ce;
443 CUPROJ_HOST_DEVICE Coordinate inverse(Coordinate
const& coord)
const
446 auto& tmerc_params = this->params_.tmerc_params_;
447 auto& ellipsoid = this->params_.ellipsoid_;
450 T Cn = (coord.y - tmerc_params.Zb) / tmerc_params.Qn;
451 T Ce = coord.x / tmerc_params.Qn;
454 "Coordinate transform outside projection domain");
457 T
const sin_arg_r = sin(2 * Cn);
458 T
const cos_arg_r = cos(2 * Cn);
462 T
const exp_2_Ce = exp(2 * Ce);
463 T
const half_inv_exp_2_Ce = T{0.5} / exp_2_Ce;
464 T
const sinh_arg_i = T{0.5} * exp_2_Ce - half_inv_exp_2_Ce;
465 T
const cosh_arg_i = T{0.5} * exp_2_Ce + half_inv_exp_2_Ce;
468 Cn += detail::clenshaw_complex(tmerc_params.utg,
479 T
const sin_Cn = sin(Cn);
480 T
const cos_Cn = cos(Cn);
485 Ce = atan (sinh (Ce));
488 Ce = atan2 (sin_Ce, cos_Ce*cos_Cn);
489 Cn = atan2 (sin_Cn*cos_Ce, hypot (sin_Ce, cos_Ce*cos_Cn));
499 T
const sinhCe = sinh(Ce);
500 Ce = atan2(sinhCe, cos_Cn);
501 T
const modulus_Ce = hypot(sinhCe, cos_Cn);
502 Cn = atan2(sin_Cn, modulus_Ce);
508 T
const tmp = 2 * modulus_Ce / (sinhCe * sinhCe + 1);
509 T
const sin_2_Cn = sin_Cn * tmp;
510 T
const cos_2_Cn = tmp * modulus_Ce - 1.;
514 return Coordinate{Ce, detail::gatg(tmerc_params.cgb,
ETMERC_ORDER, Cn, cos_2_Cn, sin_2_Cn)};
522 T lam0()
const {
return this->params_.lam0_; }
525 projection_parameters<T> params_{};