File indexing completed on 2025-01-18 09:35:37
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 #ifndef BOOST_GEOMETRY_SRS_PROJECTIONS_IMPL_PJ_APPLY_GRIDSHIFT_HPP
0041 #define BOOST_GEOMETRY_SRS_PROJECTIONS_IMPL_PJ_APPLY_GRIDSHIFT_HPP
0042
0043
0044 #include <boost/geometry/core/assert.hpp>
0045 #include <boost/geometry/core/radian_access.hpp>
0046
0047 #include <boost/geometry/srs/projections/impl/adjlon.hpp>
0048 #include <boost/geometry/srs/projections/impl/function_overloads.hpp>
0049 #include <boost/geometry/srs/projections/impl/pj_gridlist.hpp>
0050
0051 #include <boost/geometry/util/range.hpp>
0052
0053
0054 namespace boost { namespace geometry { namespace projections
0055 {
0056
0057 namespace detail
0058 {
0059
0060
0061 template <typename CalcT>
0062 inline void nad_intr(CalcT in_lon, CalcT in_lat,
0063 CalcT & out_lon, CalcT & out_lat,
0064 pj_ctable const& ct)
0065 {
0066 pj_ctable::lp_t frct;
0067 pj_ctable::ilp_t indx;
0068 boost::int32_t in;
0069
0070 indx.lam = int_floor(in_lon /= ct.del.lam);
0071 indx.phi = int_floor(in_lat /= ct.del.phi);
0072 frct.lam = in_lon - indx.lam;
0073 frct.phi = in_lat - indx.phi;
0074
0075 out_lon = out_lat = HUGE_VAL;
0076 if (indx.lam < 0) {
0077 if (indx.lam == -1 && frct.lam > 0.99999999999) {
0078 ++indx.lam;
0079 frct.lam = 0.;
0080 } else
0081 return;
0082 } else if ((in = indx.lam + 1) >= ct.lim.lam) {
0083 if (in == ct.lim.lam && frct.lam < 1e-11) {
0084 --indx.lam;
0085 frct.lam = 1.;
0086 } else
0087 return;
0088 }
0089 if (indx.phi < 0) {
0090 if (indx.phi == -1 && frct.phi > 0.99999999999) {
0091 ++indx.phi;
0092 frct.phi = 0.;
0093 } else
0094 return;
0095 } else if ((in = indx.phi + 1) >= ct.lim.phi) {
0096 if (in == ct.lim.phi && frct.phi < 1e-11) {
0097 --indx.phi;
0098 frct.phi = 1.;
0099 } else
0100 return;
0101 }
0102 boost::int32_t index = indx.phi * ct.lim.lam + indx.lam;
0103 pj_ctable::flp_t const& f00 = ct.cvs[index++];
0104 pj_ctable::flp_t const& f10 = ct.cvs[index];
0105 index += ct.lim.lam;
0106 pj_ctable::flp_t const& f11 = ct.cvs[index--];
0107 pj_ctable::flp_t const& f01 = ct.cvs[index];
0108 CalcT m00, m10, m01, m11;
0109 m11 = m10 = frct.lam;
0110 m00 = m01 = 1. - frct.lam;
0111 m11 *= frct.phi;
0112 m01 *= frct.phi;
0113 frct.phi = 1. - frct.phi;
0114 m00 *= frct.phi;
0115 m10 *= frct.phi;
0116 out_lon = m00 * f00.lam + m10 * f10.lam +
0117 m01 * f01.lam + m11 * f11.lam;
0118 out_lat = m00 * f00.phi + m10 * f10.phi +
0119 m01 * f01.phi + m11 * f11.phi;
0120 }
0121
0122
0123 template <bool Inverse, typename CalcT>
0124 inline void nad_cvt(CalcT const& in_lon, CalcT const& in_lat,
0125 CalcT & out_lon, CalcT & out_lat,
0126 pj_gi const& gi)
0127 {
0128 static const int max_iterations = 10;
0129 static const CalcT tol = 1e-12;
0130 static const CalcT toltol = tol * tol;
0131 static const CalcT pi = math::pi<CalcT>();
0132
0133
0134 BOOST_GEOMETRY_ASSERT_MSG(gi.format != pj_gi::gtx,
0135 "Vertical grid cannot be used in horizontal shift.");
0136
0137 pj_ctable const& ct = gi.ct;
0138
0139
0140 if (in_lon == HUGE_VAL)
0141 {
0142 out_lon = HUGE_VAL;
0143 out_lat = HUGE_VAL;
0144 return;
0145 }
0146
0147
0148 pj_ctable::lp_t tb;
0149 tb.lam = in_lon - ct.ll.lam;
0150 tb.phi = in_lat - ct.ll.phi;
0151 tb.lam = adjlon (tb.lam - pi) + pi;
0152
0153 pj_ctable::lp_t t;
0154 nad_intr(tb.lam, tb.phi, t.lam, t.phi, ct);
0155 if (t.lam == HUGE_VAL)
0156 {
0157 out_lon = HUGE_VAL;
0158 out_lat = HUGE_VAL;
0159 return;
0160 }
0161
0162 if (! Inverse)
0163 {
0164 out_lon = in_lon - t.lam;
0165 out_lat = in_lat - t.phi;
0166 return;
0167 }
0168
0169 t.lam = tb.lam + t.lam;
0170 t.phi = tb.phi - t.phi;
0171
0172 int i = max_iterations;
0173 pj_ctable::lp_t del, dif;
0174 do
0175 {
0176 nad_intr(t.lam, t.phi, del.lam, del.phi, ct);
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 if (del.lam == HUGE_VAL)
0188 {
0189
0190 break;
0191 }
0192
0193 dif.lam = t.lam - del.lam - tb.lam;
0194 dif.phi = t.phi + del.phi - tb.phi;
0195 t.lam -= dif.lam;
0196 t.phi -= dif.phi;
0197
0198 }
0199 while (--i && (dif.lam*dif.lam + dif.phi*dif.phi > toltol));
0200
0201 if (i==0)
0202 {
0203
0204 out_lon = HUGE_VAL;
0205 out_lat = HUGE_VAL;
0206 return;
0207 }
0208
0209 out_lon = adjlon (t.lam + ct.ll.lam);
0210 out_lat = t.phi + ct.ll.phi;
0211 }
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223 template <typename T>
0224 inline bool grid_disjoint(T const& lam, T const& phi,
0225 pj_ctable const& ct)
0226 {
0227 double epsilon = (fabs(ct.del.phi)+fabs(ct.del.lam))/10000.0;
0228 return ct.ll.phi - epsilon > phi
0229 || ct.ll.lam - epsilon > lam
0230 || (ct.ll.phi + (ct.lim.phi-1) * ct.del.phi + epsilon < phi)
0231 || (ct.ll.lam + (ct.lim.lam-1) * ct.del.lam + epsilon < lam);
0232 }
0233
0234 template <typename T>
0235 inline pj_gi * find_grid(T const& lam,
0236 T const& phi,
0237 std::vector<pj_gi>::iterator first,
0238 std::vector<pj_gi>::iterator last)
0239 {
0240 pj_gi * gip = NULL;
0241
0242 for( ; first != last ; ++first )
0243 {
0244
0245 if (! grid_disjoint(lam, phi, first->ct))
0246 {
0247
0248 if (first->format != pj_gi::gtx)
0249 {
0250 gip = boost::addressof(*first);
0251 break;
0252 }
0253 }
0254 }
0255
0256
0257 if( gip == NULL )
0258 return gip;
0259
0260
0261 pj_gi * child = find_grid(lam, phi, first->children.begin(), first->children.end());
0262 if (child != NULL)
0263 gip = child;
0264
0265 return gip;
0266 }
0267
0268 template <typename T>
0269 inline pj_gi * find_grid(T const& lam,
0270 T const& phi,
0271 pj_gridinfo & grids,
0272 std::vector<std::size_t> const& gridindexes)
0273 {
0274 pj_gi * gip = NULL;
0275
0276
0277 for (std::size_t i = 0 ; i < gridindexes.size() ; ++i)
0278 {
0279 pj_gi & gi = grids[gridindexes[i]];
0280
0281
0282 if (! grid_disjoint(lam, phi, gi.ct))
0283 {
0284
0285 if (gi.format != pj_gi::gtx)
0286 {
0287 gip = boost::addressof(gi);
0288 break;
0289 }
0290 }
0291 }
0292
0293 if (gip == NULL)
0294 return gip;
0295
0296
0297 pj_gi * child = find_grid(lam, phi, gip->children.begin(), gip->children.end());
0298 if (child != NULL)
0299 gip = child;
0300
0301
0302 return gip;
0303 }
0304
0305
0306 template <typename StreamPolicy>
0307 inline bool load_grid(StreamPolicy const& stream_policy, pj_gi_load & gi)
0308 {
0309
0310 if (gi.ct.cvs.empty())
0311 {
0312 typename StreamPolicy::stream_type is;
0313 stream_policy.open(is, gi.gridname);
0314
0315 if (! pj_gridinfo_load(is, gi))
0316 {
0317
0318 return false;
0319 }
0320 }
0321
0322 return true;
0323 }
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333 template <bool Inverse, typename CalcT, typename StreamPolicy, typename Range, typename Grids>
0334 inline bool pj_apply_gridshift_3(StreamPolicy const& stream_policy,
0335 Range & range,
0336 Grids & grids,
0337 std::vector<std::size_t> const& gridindexes,
0338 grids_tag)
0339 {
0340 typedef typename boost::range_size<Range>::type size_type;
0341
0342
0343 if (gridindexes.empty())
0344 {
0345
0346
0347 return false;
0348 }
0349
0350 size_type point_count = boost::size(range);
0351
0352 for (size_type i = 0 ; i < point_count ; ++i)
0353 {
0354 typename boost::range_reference<Range>::type
0355 point = range::at(range, i);
0356
0357 CalcT in_lon = geometry::get_as_radian<0>(point);
0358 CalcT in_lat = geometry::get_as_radian<1>(point);
0359
0360 pj_gi * gip = find_grid(in_lon, in_lat, grids.gridinfo, gridindexes);
0361
0362 if ( gip != NULL )
0363 {
0364
0365 if (! gip->ct.cvs.empty() || load_grid(stream_policy, *gip))
0366 {
0367
0368 CalcT out_lon = HUGE_VAL;
0369 CalcT out_lat = HUGE_VAL;
0370
0371 nad_cvt<Inverse>(in_lon, in_lat, out_lon, out_lat, *gip);
0372
0373
0374 if ( out_lon != HUGE_VAL )
0375 {
0376 geometry::set_from_radian<0>(point, out_lon);
0377 geometry::set_from_radian<1>(point, out_lat);
0378 }
0379 }
0380 }
0381 }
0382
0383 return true;
0384 }
0385
0386
0387 template <bool Inverse, typename CalcT, typename StreamPolicy, typename Range, typename SharedGrids>
0388 inline bool pj_apply_gridshift_3(StreamPolicy const& stream_policy,
0389 Range & range,
0390 SharedGrids & grids,
0391 std::vector<std::size_t> const& gridindexes,
0392 shared_grids_tag)
0393 {
0394 typedef typename boost::range_size<Range>::type size_type;
0395
0396
0397 if (gridindexes.empty())
0398 {
0399
0400
0401 return false;
0402 }
0403
0404 size_type point_count = boost::size(range);
0405
0406
0407 pj_gi_load local_gi;
0408
0409 for (size_type i = 0 ; i < point_count ; )
0410 {
0411 bool load_needed = false;
0412
0413 CalcT in_lon = 0;
0414 CalcT in_lat = 0;
0415
0416 {
0417 typename SharedGrids::read_locked lck_grids(grids);
0418
0419 for ( ; i < point_count ; ++i )
0420 {
0421 typename boost::range_reference<Range>::type
0422 point = range::at(range, i);
0423
0424 in_lon = geometry::get_as_radian<0>(point);
0425 in_lat = geometry::get_as_radian<1>(point);
0426
0427 pj_gi * gip = find_grid(in_lon, in_lat, lck_grids.gridinfo, gridindexes);
0428
0429 if (gip == NULL)
0430 {
0431
0432 }
0433 else if (! gip->ct.cvs.empty())
0434 {
0435
0436 CalcT out_lon = HUGE_VAL;
0437 CalcT out_lat = HUGE_VAL;
0438
0439 nad_cvt<Inverse>(in_lon, in_lat, out_lon, out_lat, *gip);
0440
0441
0442 if (out_lon != HUGE_VAL)
0443 {
0444 geometry::set_from_radian<0>(point, out_lon);
0445 geometry::set_from_radian<1>(point, out_lat);
0446 }
0447 }
0448 else
0449 {
0450
0451 local_gi = *gip;
0452 load_needed = true;
0453 break;
0454 }
0455 }
0456 }
0457
0458 if (load_needed)
0459 {
0460 if (load_grid(stream_policy, local_gi))
0461 {
0462 typename SharedGrids::write_locked lck_grids(grids);
0463
0464
0465 pj_gi * gip = find_grid(in_lon, in_lat, lck_grids.gridinfo, gridindexes);
0466
0467 if (gip != NULL && gip->ct.cvs.empty())
0468 {
0469
0470 local_gi.swap(*gip);
0471 }
0472 }
0473 else
0474 {
0475 ++i;
0476 }
0477 }
0478 }
0479
0480 return true;
0481 }
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493 template <bool Inverse, typename Par, typename Range, typename ProjGrids>
0494 inline bool pj_apply_gridshift_2(Par const& , Range & range, ProjGrids const& proj_grids)
0495 {
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507 if (proj_grids.hindexes.empty())
0508 return false;
0509
0510 return pj_apply_gridshift_3
0511 <
0512 Inverse, typename Par::type
0513 >(proj_grids.grids_storage().stream_policy,
0514 range,
0515 proj_grids.grids_storage().hgrids,
0516 proj_grids.hindexes,
0517 typename ProjGrids::grids_storage_type::grids_type::tag());
0518 }
0519
0520 template <bool Inverse, typename Par, typename Range>
0521 inline bool pj_apply_gridshift_2(Par const& , Range & , srs::detail::empty_projection_grids const& )
0522 {
0523 return false;
0524 }
0525
0526
0527 }
0528
0529 }}}
0530
0531 #endif