File indexing completed on 2025-01-18 09:35:43
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
0041
0042
0043 #ifndef BOOST_GEOMETRY_PROJECTIONS_ISEA_HPP
0044 #define BOOST_GEOMETRY_PROJECTIONS_ISEA_HPP
0045
0046 #include <sstream>
0047
0048 #include <boost/core/ignore_unused.hpp>
0049
0050 #include <boost/geometry/core/assert.hpp>
0051
0052 #include <boost/geometry/srs/projections/impl/base_static.hpp>
0053 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
0054 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
0055 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
0056 #include <boost/geometry/srs/projections/impl/projects.hpp>
0057
0058 #include <boost/geometry/util/math.hpp>
0059
0060 namespace boost { namespace geometry
0061 {
0062
0063 namespace projections
0064 {
0065 #ifndef DOXYGEN_NO_DETAIL
0066 namespace detail { namespace isea
0067 {
0068 static const double epsilon = std::numeric_limits<double>::epsilon();
0069
0070
0071 static const double isea_scale = 0.8301572857837594396028083;
0072
0073 static const double v_lat = 0.46364760899944494524;
0074
0075 static const double e_rad = 0.91843818702186776133;
0076
0077 static const double f_rad = 0.18871053072122403508;
0078
0079 static const double table_g = 0.6615845383;
0080
0081 static const double table_h = 0.1909830056;
0082
0083 static const double isea_std_lat = 1.01722196792335072101;
0084 static const double isea_std_lon = .19634954084936207740;
0085
0086 template <typename T>
0087 inline T deg30_rad() { return T(30) * geometry::math::d2r<T>(); }
0088 template <typename T>
0089 inline T deg120_rad() { return T(120) * geometry::math::d2r<T>(); }
0090 template <typename T>
0091 inline T deg72_rad() { return T(72) * geometry::math::d2r<T>(); }
0092 template <typename T>
0093 inline T deg90_rad() { return geometry::math::half_pi<T>(); }
0094 template <typename T>
0095 inline T deg144_rad() { return T(144) * geometry::math::d2r<T>(); }
0096 template <typename T>
0097 inline T deg36_rad() { return T(36) * geometry::math::d2r<T>(); }
0098 template <typename T>
0099 inline T deg108_rad() { return T(108) * geometry::math::d2r<T>(); }
0100 template <typename T>
0101 inline T deg180_rad() { return geometry::math::pi<T>(); }
0102
0103 inline bool downtri(int tri) { return (((tri - 1) / 5) % 2 == 1); }
0104
0105
0106
0107
0108
0109
0110
0111 struct hex {
0112 int iso;
0113 int x, y, z;
0114 };
0115
0116
0117 inline
0118 int hex_xy(struct hex *h) {
0119 if (!h->iso) return 1;
0120 if (h->x >= 0) {
0121 h->y = -h->y - (h->x+1)/2;
0122 } else {
0123
0124 h->y = -h->y - h->x/2;
0125 }
0126 h->iso = 0;
0127
0128 return 1;
0129 }
0130
0131 inline
0132 int hex_iso(struct hex *h) {
0133 if (h->iso) return 1;
0134
0135 if (h->x >= 0) {
0136 h->y = (-h->y - (h->x+1)/2);
0137 } else {
0138
0139 h->y = (-h->y - (h->x)/2);
0140 }
0141
0142 h->z = -h->x - h->y;
0143 h->iso = 1;
0144 return 1;
0145 }
0146
0147 template <typename T>
0148 inline
0149 int hexbin2(T const& width, T x, T y, int *i, int *j)
0150 {
0151 T z, rx, ry, rz;
0152 T abs_dx, abs_dy, abs_dz;
0153 int ix, iy, iz, s;
0154 struct hex h;
0155
0156 static const T cos_deg30 = cos(deg30_rad<T>());
0157
0158 x = x / cos_deg30;
0159 y = y - x / 2.0;
0160
0161
0162 x /= width;
0163 y /= width;
0164
0165 z = -x - y;
0166
0167 rx = floor(x + 0.5);
0168 ix = (int)rx;
0169 ry = floor(y + 0.5);
0170 iy = (int)ry;
0171 rz = floor(z + 0.5);
0172 iz = (int)rz;
0173
0174 s = ix + iy + iz;
0175
0176 if (s) {
0177 abs_dx = fabs(rx - x);
0178 abs_dy = fabs(ry - y);
0179 abs_dz = fabs(rz - z);
0180
0181 if (abs_dx >= abs_dy && abs_dx >= abs_dz) {
0182 ix -= s;
0183 } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) {
0184 iy -= s;
0185 } else {
0186 iz -= s;
0187 }
0188 }
0189 h.x = ix;
0190 h.y = iy;
0191 h.z = iz;
0192 h.iso = 1;
0193
0194 hex_xy(&h);
0195 *i = h.x;
0196 *j = h.y;
0197 return ix * 100 + iy;
0198 }
0199
0200
0201
0202 enum isea_address_form {
0203 isea_addr_q2di, isea_addr_seqnum,
0204 isea_addr_plane, isea_addr_q2dd,
0205 isea_addr_projtri, isea_addr_vertex2dd, isea_addr_hex
0206 };
0207
0208 template <typename T>
0209 struct isea_dgg {
0210 T o_lat, o_lon, o_az;
0211 T radius;
0212 unsigned long serial;
0213
0214 int aperture;
0215 int resolution;
0216 int triangle;
0217 int quad;
0218
0219
0220 isea_address_form output;
0221 };
0222
0223 template <typename T>
0224 struct isea_pt {
0225 T x, y;
0226 };
0227
0228 template <typename T>
0229 struct isea_geo {
0230 T lon, lat;
0231 };
0232
0233 template <typename T>
0234 struct isea_address {
0235 T x,y;
0236 int type;
0237 int number;
0238 };
0239
0240
0241
0242 enum snyder_polyhedron {
0243 snyder_poly_hexagon = 0, snyder_poly_pentagon = 1,
0244 snyder_poly_tetrahedron = 2, snyder_poly_cube = 3,
0245 snyder_poly_octahedron = 4, snyder_poly_dodecahedron = 5,
0246 snyder_poly_icosahedron = 6
0247 };
0248
0249 template <typename T>
0250 struct snyder_constants {
0251 T g, G, theta, ea_w, ea_a, ea_b, g_w, g_a, g_b;
0252 };
0253
0254 template <typename T>
0255 inline const snyder_constants<T> * constants()
0256 {
0257
0258 static snyder_constants<T> result[] = {
0259 {23.80018260, 62.15458023, 60.0, 3.75, 1.033, 0.968, 5.09, 1.195, 1.0},
0260 {20.07675127, 55.69063953, 54.0, 2.65, 1.030, 0.983, 3.59, 1.141, 1.027},
0261 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
0262 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
0263 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
0264 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
0265 {37.37736814, 36.0, 30.0, 17.27, 1.163, 0.860, 13.14, 1.584, 1.0}
0266 };
0267 return result;
0268 }
0269
0270 template <typename T>
0271 inline const isea_geo<T> * vertex()
0272 {
0273 static isea_geo<T> result[] = {
0274 { 0.0, deg90_rad<T>()},
0275 { deg180_rad<T>(), v_lat},
0276 {-deg108_rad<T>(), v_lat},
0277 {-deg36_rad<T>(), v_lat},
0278 { deg36_rad<T>(), v_lat},
0279 { deg108_rad<T>(), v_lat},
0280 {-deg144_rad<T>(), -v_lat},
0281 {-deg72_rad<T>(), -v_lat},
0282 { 0.0, -v_lat},
0283 { deg72_rad<T>(), -v_lat},
0284 { deg144_rad<T>(), -v_lat},
0285 { 0.0, -deg90_rad<T>()}
0286 };
0287 return result;
0288 }
0289
0290
0291
0292 static int tri_v1[] = {0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 2, 3, 4, 5, 1, 11, 11, 11, 11, 11};
0293
0294
0295 template <typename T>
0296 inline const isea_geo<T> * icostriangles()
0297 {
0298 static isea_geo<T> result[] = {
0299 { 0.0, 0.0},
0300 {-deg144_rad<T>(), e_rad},
0301 {-deg72_rad<T>(), e_rad},
0302 { 0.0, e_rad},
0303 { deg72_rad<T>(), e_rad},
0304 { deg144_rad<T>(), e_rad},
0305 {-deg144_rad<T>(), f_rad},
0306 {-deg72_rad<T>(), f_rad},
0307 { 0.0, f_rad},
0308 { deg72_rad<T>(), f_rad},
0309 { deg144_rad<T>(), f_rad},
0310 {-deg108_rad<T>(), -f_rad},
0311 {-deg36_rad<T>(), -f_rad},
0312 { deg36_rad<T>(), -f_rad},
0313 { deg108_rad<T>(), -f_rad},
0314 { deg180_rad<T>(), -f_rad},
0315 {-deg108_rad<T>(), -e_rad},
0316 {-deg36_rad<T>(), -e_rad},
0317 { deg36_rad<T>(), -e_rad},
0318 { deg108_rad<T>(), -e_rad},
0319 { deg180_rad<T>(), -e_rad},
0320 };
0321 return result;
0322 }
0323
0324 template <typename T>
0325 inline T az_adjustment(int triangle)
0326 {
0327 T adj;
0328
0329 isea_geo<T> v;
0330 isea_geo<T> c;
0331
0332 v = vertex<T>()[tri_v1[triangle]];
0333 c = icostriangles<T>()[triangle];
0334
0335
0336
0337 adj = atan2(cos(v.lat) * sin(v.lon - c.lon),
0338 cos(c.lat) * sin(v.lat)
0339 - sin(c.lat) * cos(v.lat) * cos(v.lon - c.lon));
0340 return adj;
0341 }
0342
0343 template <typename T>
0344 inline isea_pt<T> isea_triangle_xy(int triangle)
0345 {
0346 isea_pt<T> c;
0347 T Rprime = 0.91038328153090290025;
0348
0349 triangle = (triangle - 1) % 20;
0350
0351 c.x = table_g * ((triangle % 5) - 2) * 2.0;
0352 if (triangle > 9) {
0353 c.x += table_g;
0354 }
0355 switch (triangle / 5) {
0356 case 0:
0357 c.y = 5.0 * table_h;
0358 break;
0359 case 1:
0360 c.y = table_h;
0361 break;
0362 case 2:
0363 c.y = -table_h;
0364 break;
0365 case 3:
0366 c.y = -5.0 * table_h;
0367 break;
0368 default:
0369
0370 BOOST_THROW_EXCEPTION( projection_exception() );
0371 };
0372 c.x *= Rprime;
0373 c.y *= Rprime;
0374
0375 return c;
0376 }
0377
0378
0379 template <typename T>
0380 inline T sph_azimuth(T const& f_lon, T const& f_lat, T const& t_lon, T const& t_lat)
0381 {
0382 T az;
0383
0384 az = atan2(cos(t_lat) * sin(t_lon - f_lon),
0385 cos(f_lat) * sin(t_lat)
0386 - sin(f_lat) * cos(t_lat) * cos(t_lon - f_lon)
0387 );
0388 return az;
0389 }
0390
0391
0392 template <typename T>
0393 inline int isea_snyder_forward(isea_geo<T> * ll, isea_pt<T> * out)
0394 {
0395 static T const two_pi = detail::two_pi<T>();
0396 static T const d2r = geometry::math::d2r<T>();
0397
0398 int i;
0399
0400
0401
0402
0403
0404 T g;
0405
0406
0407
0408
0409
0410 T G;
0411
0412
0413
0414
0415
0416 T theta;
0417
0418
0419 T q, Rprime, H, Ag, Azprime, Az, dprime, f, rho,
0420 x, y;
0421
0422
0423 T cot_theta, tan_g, az_offset;
0424
0425
0426 int Az_adjust_multiples;
0427
0428 snyder_constants<T> c;
0429
0430
0431
0432
0433
0434
0435
0436 c = constants<T>()[snyder_poly_icosahedron];
0437 theta = c.theta * d2r;
0438 g = c.g * d2r;
0439 G = c.G * d2r;
0440
0441 for (i = 1; i <= 20; i++) {
0442 T z;
0443 isea_geo<T> center;
0444
0445 center = icostriangles<T>()[i];
0446
0447
0448 z = acos(sin(center.lat) * sin(ll->lat)
0449 + cos(center.lat) * cos(ll->lat) * cos(ll->lon - center.lon));
0450
0451
0452 if (z > g + 0.000005) {
0453 continue;
0454 }
0455
0456 Az = sph_azimuth(center.lon, center.lat, ll->lon, ll->lat);
0457
0458
0459
0460
0461 az_offset = az_adjustment<T>(i);
0462
0463 Az -= az_offset;
0464
0465
0466
0467 if (Az < 0.0) {
0468 Az += two_pi;
0469 }
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479 Az_adjust_multiples = 0;
0480 while (Az < 0.0) {
0481 Az += deg120_rad<T>();
0482 Az_adjust_multiples--;
0483 }
0484 while (Az > deg120_rad<T>() + epsilon) {
0485 Az -= deg120_rad<T>();
0486 Az_adjust_multiples++;
0487 }
0488
0489
0490 cot_theta = 1.0 / tan(theta);
0491 tan_g = tan(g);
0492
0493
0494
0495 q = atan2(tan_g, cos(Az) + sin(Az) * cot_theta);
0496
0497
0498 if (z > q + 0.000005) {
0499 continue;
0500 }
0501
0502
0503
0504
0505
0506
0507
0508 Rprime = 0.91038328153090290025;
0509
0510
0511 H = acos(sin(Az) * sin(G) * cos(g) - cos(Az) * cos(G));
0512
0513
0514
0515 Ag = Az + G + H - deg180_rad<T>();
0516
0517
0518 Azprime = atan2(2.0 * Ag, Rprime * Rprime * tan_g * tan_g - 2.0 * Ag * cot_theta);
0519
0520
0521
0522 dprime = Rprime * tan_g / (cos(Azprime) + sin(Azprime) * cot_theta);
0523
0524
0525 f = dprime / (2.0 * Rprime * sin(q / 2.0));
0526
0527
0528 rho = 2.0 * Rprime * f * sin(z / 2.0);
0529
0530
0531
0532
0533
0534
0535 Azprime += deg120_rad<T>() * Az_adjust_multiples;
0536
0537
0538
0539 x = rho * sin(Azprime);
0540 y = rho * cos(Azprime);
0541
0542
0543
0544
0545
0546
0547
0548 out->x = x;
0549 out->y = y;
0550
0551 return i;
0552 }
0553
0554
0555
0556
0557
0558
0559
0560
0561 std::stringstream ss;
0562 ss << "impossible transform: " << ll->lon * geometry::math::r2d<T>()
0563 << " " << ll->lat * geometry::math::r2d<T>() << " is not on any triangle.";
0564
0565 BOOST_THROW_EXCEPTION( projection_exception(ss.str()) );
0566
0567
0568 return 0;
0569 }
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587 template <typename T>
0588 inline isea_geo<T> snyder_ctran(isea_geo<T> * np, isea_geo<T> * pt)
0589 {
0590 static T const pi = detail::pi<T>();
0591 static T const two_pi = detail::two_pi<T>();
0592
0593 isea_geo<T> npt;
0594 T alpha, phi, lambda, lambda0, beta, lambdap, phip;
0595 T sin_phip;
0596 T lp_b;
0597 T cos_p, sin_a;
0598
0599 phi = pt->lat;
0600 lambda = pt->lon;
0601 alpha = np->lat;
0602 beta = np->lon;
0603 lambda0 = beta;
0604
0605 cos_p = cos(phi);
0606 sin_a = sin(alpha);
0607
0608
0609 sin_phip = sin_a * sin(phi) - cos(alpha) * cos_p * cos(lambda - lambda0);
0610
0611
0612
0613
0614 lp_b = atan2(cos_p * sin(lambda - lambda0),
0615 (sin_a * cos_p * cos(lambda - lambda0) + cos(alpha) * sin(phi)));
0616
0617 lambdap = lp_b + beta;
0618
0619
0620
0621 lambdap = fmod(lambdap, two_pi);
0622 while (lambdap > pi)
0623 lambdap -= two_pi;
0624 while (lambdap < -pi)
0625 lambdap += two_pi;
0626
0627 phip = asin(sin_phip);
0628
0629 npt.lat = phip;
0630 npt.lon = lambdap;
0631
0632 return npt;
0633 }
0634
0635 template <typename T>
0636 inline isea_geo<T> isea_ctran(isea_geo<T> * np, isea_geo<T> * pt, T const& lon0)
0637 {
0638 static T const pi = detail::pi<T>();
0639 static T const two_pi = detail::two_pi<T>();
0640
0641 isea_geo<T> npt;
0642
0643 np->lon += pi;
0644 npt = snyder_ctran(np, pt);
0645 np->lon -= pi;
0646
0647 npt.lon -= (pi - lon0 + np->lon);
0648
0649
0650
0651
0652
0653 npt.lon += pi;
0654
0655 npt.lon = fmod(npt.lon, two_pi);
0656 while (npt.lon > pi)
0657 npt.lon -= two_pi;
0658 while (npt.lon < -pi)
0659 npt.lon += two_pi;
0660
0661 return npt;
0662 }
0663
0664
0665
0666
0667
0668 template <typename T>
0669 inline int isea_grid_init(isea_dgg<T> * g)
0670 {
0671 if (!g)
0672 return 0;
0673
0674
0675 g->o_lat = isea_std_lat;
0676 g->o_lon = isea_std_lon;
0677 g->o_az = 0.0;
0678 g->aperture = 4;
0679 g->resolution = 6;
0680 g->radius = 1.0;
0681
0682
0683 return 1;
0684 }
0685
0686 template <typename T>
0687 inline int isea_orient_isea(isea_dgg<T> * g)
0688 {
0689 if (!g)
0690 return 0;
0691 g->o_lat = isea_std_lat;
0692 g->o_lon = isea_std_lon;
0693 g->o_az = 0.0;
0694 return 1;
0695 }
0696
0697 template <typename T>
0698 inline int isea_orient_pole(isea_dgg<T> * g)
0699 {
0700 static T const half_pi = detail::half_pi<T>();
0701
0702 if (!g)
0703 return 0;
0704 g->o_lat = half_pi;
0705 g->o_lon = 0.0;
0706 g->o_az = 0;
0707 return 1;
0708 }
0709
0710 template <typename T>
0711 inline int isea_transform(isea_dgg<T> * g, isea_geo<T> * in,
0712 isea_pt<T> * out)
0713 {
0714 isea_geo<T> i, pole;
0715 int tri;
0716
0717 pole.lat = g->o_lat;
0718 pole.lon = g->o_lon;
0719
0720 i = isea_ctran(&pole, in, g->o_az);
0721
0722 tri = isea_snyder_forward(&i, out);
0723 out->x *= g->radius;
0724 out->y *= g->radius;
0725 g->triangle = tri;
0726
0727 return tri;
0728 }
0729
0730
0731 template <typename T>
0732 inline void isea_rotate(isea_pt<T> * pt, T const& degrees)
0733 {
0734 static T const d2r = geometry::math::d2r<T>();
0735 static T const two_pi = detail::two_pi<T>();
0736
0737 T rad;
0738
0739 T x, y;
0740
0741 rad = -degrees * d2r;
0742 while (rad >= two_pi) rad -= two_pi;
0743 while (rad <= -two_pi) rad += two_pi;
0744
0745 x = pt->x * cos(rad) + pt->y * sin(rad);
0746 y = -pt->x * sin(rad) + pt->y * cos(rad);
0747
0748 pt->x = x;
0749 pt->y = y;
0750 }
0751
0752 template <typename T>
0753 inline int isea_tri_plane(int tri, isea_pt<T> *pt, T const& radius)
0754 {
0755 isea_pt<T> tc;
0756
0757 if (downtri(tri)) {
0758 isea_rotate(pt, 180.0);
0759 }
0760 tc = isea_triangle_xy<T>(tri);
0761 tc.x *= radius;
0762 tc.y *= radius;
0763 pt->x += tc.x;
0764 pt->y += tc.y;
0765
0766 return tri;
0767 }
0768
0769
0770 template <typename T>
0771 inline int isea_ptdd(int tri, isea_pt<T> *pt)
0772 {
0773 int downtri, quad;
0774
0775 downtri = (((tri - 1) / 5) % 2 == 1);
0776 quad = ((tri - 1) % 5) + ((tri - 1) / 10) * 5 + 1;
0777
0778 isea_rotate(pt, downtri ? 240.0 : 60.0);
0779 if (downtri) {
0780 pt->x += 0.5;
0781
0782 pt->y += .86602540378443864672;
0783 }
0784 return quad;
0785 }
0786
0787 template <typename T>
0788 inline int isea_dddi_ap3odd(isea_dgg<T> *g, int quad, isea_pt<T> *pt, isea_pt<T> *di)
0789 {
0790 static T const pi = detail::pi<T>();
0791
0792 isea_pt<T> v;
0793 T hexwidth;
0794 T sidelength;
0795 int d, i;
0796 int maxcoord;
0797 hex h;
0798
0799
0800 sidelength = (math::pow(T(2), g->resolution) + T(1)) / T(2);
0801
0802
0803 hexwidth = cos(pi / 6.0) / sidelength;
0804
0805
0806
0807
0808 maxcoord = (int) (sidelength * 2.0 + 0.5);
0809
0810 v = *pt;
0811 hexbin2(hexwidth, v.x, v.y, &h.x, &h.y);
0812 h.iso = 0;
0813 hex_iso(&h);
0814
0815 d = h.x - h.z;
0816 i = h.x + h.y + h.y;
0817
0818
0819
0820
0821
0822 if (quad <= 5) {
0823 if (d == 0 && i == maxcoord) {
0824
0825 quad = 0;
0826 d = 0;
0827 i = 0;
0828 } else if (i == maxcoord) {
0829
0830 quad += 1;
0831 if (quad == 6)
0832 quad = 1;
0833 i = maxcoord - d;
0834 d = 0;
0835 } else if (d == maxcoord) {
0836
0837 quad += 5;
0838 d = 0;
0839 }
0840 } else if (quad >= 6) {
0841 if (i == 0 && d == maxcoord) {
0842
0843 quad = 11;
0844 d = 0;
0845 i = 0;
0846 } else if (d == maxcoord) {
0847
0848 quad += 1;
0849 if (quad == 11)
0850 quad = 6;
0851 d = maxcoord - i;
0852 i = 0;
0853 } else if (i == maxcoord) {
0854
0855 quad = (quad - 4) % 5;
0856 i = 0;
0857 }
0858 }
0859
0860 di->x = d;
0861 di->y = i;
0862
0863 g->quad = quad;
0864 return quad;
0865 }
0866
0867 template <typename T>
0868 inline int isea_dddi(isea_dgg<T> *g, int quad, isea_pt<T> *pt, isea_pt<T> *di)
0869 {
0870 isea_pt<T> v;
0871 T hexwidth;
0872 int sidelength;
0873 hex h;
0874
0875 if (g->aperture == 3 && g->resolution % 2 != 0) {
0876 return isea_dddi_ap3odd(g, quad, pt, di);
0877 }
0878
0879 if (g->aperture >0) {
0880 sidelength = (int) (math::pow(T(g->aperture), T(g->resolution / T(2))) + T(0.5));
0881 } else {
0882 sidelength = g->resolution;
0883 }
0884
0885 hexwidth = 1.0 / sidelength;
0886
0887 v = *pt;
0888 isea_rotate(&v, -30.0);
0889 hexbin2(hexwidth, v.x, v.y, &h.x, &h.y);
0890 h.iso = 0;
0891 hex_iso(&h);
0892
0893
0894 if (quad <= 5) {
0895 if (h.x == 0 && h.z == -sidelength) {
0896
0897 quad = 0;
0898 h.z = 0;
0899 h.y = 0;
0900 h.x = 0;
0901 } else if (h.z == -sidelength) {
0902 quad = quad + 1;
0903 if (quad == 6)
0904 quad = 1;
0905 h.y = sidelength - h.x;
0906 h.z = h.x - sidelength;
0907 h.x = 0;
0908 } else if (h.x == sidelength) {
0909 quad += 5;
0910 h.y = -h.z;
0911 h.x = 0;
0912 }
0913 } else if (quad >= 6) {
0914 if (h.z == 0 && h.x == sidelength) {
0915
0916 quad = 11;
0917 h.x = 0;
0918 h.y = 0;
0919 h.z = 0;
0920 } else if (h.x == sidelength) {
0921 quad = quad + 1;
0922 if (quad == 11)
0923 quad = 6;
0924 h.x = h.y + sidelength;
0925 h.y = 0;
0926 h.z = -h.x;
0927 } else if (h.y == -sidelength) {
0928 quad -= 4;
0929 h.y = 0;
0930 h.z = -h.x;
0931 }
0932 }
0933 di->x = h.x;
0934 di->y = -h.z;
0935
0936 g->quad = quad;
0937 return quad;
0938 }
0939
0940 template <typename T>
0941 inline int isea_ptdi(isea_dgg<T> *g, int tri, isea_pt<T> *pt,
0942 isea_pt<T> *di)
0943 {
0944 isea_pt<T> v;
0945 int quad;
0946
0947 v = *pt;
0948 quad = isea_ptdd(tri, &v);
0949 quad = isea_dddi(g, quad, &v, di);
0950 return quad;
0951 }
0952
0953
0954 template <typename T>
0955 inline int isea_disn(isea_dgg<T> *g, int quad, isea_pt<T> *di)
0956 {
0957 int sidelength;
0958 int sn, height;
0959 int hexes;
0960
0961 if (quad == 0) {
0962 g->serial = 1;
0963 return g->serial;
0964 }
0965
0966 hexes = (int) (math::pow(T(g->aperture), T(g->resolution)) + T(0.5));
0967 if (quad == 11) {
0968 g->serial = 1 + 10 * hexes + 1;
0969 return g->serial;
0970 }
0971 if (g->aperture == 3 && g->resolution % 2 == 1) {
0972 height = (int) (math::pow(T(g->aperture), T((g->resolution - 1) / T(2))));
0973 sn = ((int) di->x) * height;
0974 sn += ((int) di->y) / height;
0975 sn += (quad - 1) * hexes;
0976 sn += 2;
0977 } else {
0978 sidelength = (int) (math::pow(T(g->aperture), T(g->resolution / T(2))) + T(0.5));
0979 sn = (int) ((quad - 1) * hexes + sidelength * di->x + di->y + 2);
0980 }
0981
0982 g->serial = sn;
0983 return sn;
0984 }
0985
0986
0987
0988
0989
0990
0991 template <typename T>
0992 inline int isea_hex(isea_dgg<T> *g, int tri, isea_pt<T> *pt,
0993 isea_pt<T> *hex)
0994 {
0995 isea_pt<T> v;
0996 #ifdef BOOST_GEOMETRY_PROJECTIONS_FIXME
0997 int sidelength;
0998 int d, i, x, y;
0999 #endif
1000 int quad;
1001
1002 quad = isea_ptdi(g, tri, pt, &v);
1003
1004 hex->x = ((int)v.x << 4) + quad;
1005 hex->y = v.y;
1006
1007 return 1;
1008 #ifdef BOOST_GEOMETRY_PROJECTIONS_FIXME
1009 d = (int)v.x;
1010 i = (int)v.y;
1011
1012
1013 if (g->aperture == 3 && g->resolution % 2 != 0) {
1014 int offset = (int)(pow(T(3.0), T(g->resolution - 1)) + 0.5);
1015
1016 d += offset * ((g->quad-1) % 5);
1017 i += offset * ((g->quad-1) % 5);
1018
1019 if (quad == 0) {
1020 d = 0;
1021 i = offset;
1022 } else if (quad == 11) {
1023 d = 2 * offset;
1024 i = 0;
1025 } else if (quad > 5) {
1026 d += offset;
1027 }
1028
1029 x = (2*d - i) /3;
1030 y = (2*i - d) /3;
1031
1032 hex->x = x + offset / 3;
1033 hex->y = y + 2 * offset / 3;
1034 return 1;
1035 }
1036
1037
1038 sidelength = (int) (pow(T(g->aperture), T(g->resolution / 2.0)) + 0.5);
1039 if (g->quad == 0) {
1040 hex->x = 0;
1041 hex->y = sidelength;
1042 } else if (g->quad == 11) {
1043 hex->x = sidelength * 2;
1044 hex->y = 0;
1045 } else {
1046 hex->x = d + sidelength * ((g->quad-1) % 5);
1047 if (g->quad > 5) hex->x += sidelength;
1048 hex->y = i + sidelength * ((g->quad-1) % 5);
1049 }
1050
1051 return 1;
1052 #endif
1053 }
1054
1055 template <typename T>
1056 inline isea_pt<T> isea_forward(isea_dgg<T> *g, isea_geo<T> *in)
1057 {
1058 int tri;
1059 isea_pt<T> out, coord;
1060
1061 tri = isea_transform(g, in, &out);
1062
1063 if (g->output == isea_addr_plane) {
1064 isea_tri_plane(tri, &out, g->radius);
1065 return out;
1066 }
1067
1068
1069 out.x = out.x / g->radius * isea_scale;
1070 out.y = out.y / g->radius * isea_scale;
1071 out.x += 0.5;
1072 out.y += 2.0 * .14433756729740644112;
1073
1074 switch (g->output) {
1075 case isea_addr_projtri:
1076
1077 break;
1078 case isea_addr_vertex2dd:
1079 g->quad = isea_ptdd(tri, &out);
1080 break;
1081 case isea_addr_q2dd:
1082
1083 g->quad = isea_ptdd(tri, &out);
1084 break;
1085 case isea_addr_q2di:
1086 g->quad = isea_ptdi(g, tri, &out, &coord);
1087 return coord;
1088 break;
1089 case isea_addr_seqnum:
1090 isea_ptdi(g, tri, &out, &coord);
1091
1092 isea_disn(g, g->quad, &coord);
1093 return coord;
1094 break;
1095 case isea_addr_hex:
1096 isea_hex(g, tri, &out, &coord);
1097 return coord;
1098 break;
1099 default:
1100
1101 BOOST_GEOMETRY_ASSERT(false);
1102 break;
1103 }
1104
1105 return out;
1106 }
1107
1108
1109
1110
1111 template <typename T>
1112 struct par_isea
1113 {
1114 isea_dgg<T> dgg;
1115 };
1116
1117 template <typename T, typename Parameters>
1118 struct base_isea_spheroid
1119 {
1120 par_isea<T> m_proj_parm;
1121
1122
1123
1124 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
1125 {
1126 isea_pt<T> out;
1127 isea_geo<T> in;
1128
1129 in.lon = lp_lon;
1130 in.lat = lp_lat;
1131
1132 isea_dgg<T> copy = this->m_proj_parm.dgg;
1133 out = isea_forward(©, &in);
1134
1135 xy_x = out.x;
1136 xy_y = out.y;
1137 }
1138
1139 static inline std::string get_name()
1140 {
1141 return "isea_spheroid";
1142 }
1143
1144 };
1145
1146 template <typename T>
1147 inline void isea_orient_init(srs::detail::proj4_parameters const& params,
1148 par_isea<T>& proj_parm)
1149 {
1150 std::string opt = pj_get_param_s(params, "orient");
1151 if (! opt.empty()) {
1152 if (opt == std::string("isea")) {
1153 isea_orient_isea(&proj_parm.dgg);
1154 } else if (opt == std::string("pole")) {
1155 isea_orient_pole(&proj_parm.dgg);
1156 } else {
1157 BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) );
1158 }
1159 }
1160 }
1161
1162 template <typename T>
1163 inline void isea_orient_init(srs::dpar::parameters<T> const& params,
1164 par_isea<T>& proj_parm)
1165 {
1166 typename srs::dpar::parameters<T>::const_iterator
1167 it = pj_param_find(params, srs::dpar::orient);
1168 if (it != params.end()) {
1169 srs::dpar::value_orient o = static_cast<srs::dpar::value_orient>(it->template get_value<int>());
1170 if (o == srs::dpar::orient_isea) {
1171 isea_orient_isea(&proj_parm.dgg);
1172 } else if (o == srs::dpar::orient_pole) {
1173 isea_orient_pole(&proj_parm.dgg);
1174 } else {
1175 BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) );
1176 }
1177 }
1178 }
1179
1180 template <typename T>
1181 inline void isea_mode_init(srs::detail::proj4_parameters const& params,
1182 par_isea<T>& proj_parm)
1183 {
1184 std::string opt = pj_get_param_s(params, "mode");
1185 if (! opt.empty()) {
1186 if (opt == std::string("plane")) {
1187 proj_parm.dgg.output = isea_addr_plane;
1188 } else if (opt == std::string("di")) {
1189 proj_parm.dgg.output = isea_addr_q2di;
1190 } else if (opt == std::string("dd")) {
1191 proj_parm.dgg.output = isea_addr_q2dd;
1192 } else if (opt == std::string("hex")) {
1193 proj_parm.dgg.output = isea_addr_hex;
1194 } else {
1195 BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) );
1196 }
1197 }
1198 }
1199
1200 template <typename T>
1201 inline void isea_mode_init(srs::dpar::parameters<T> const& params,
1202 par_isea<T>& proj_parm)
1203 {
1204 typename srs::dpar::parameters<T>::const_iterator
1205 it = pj_param_find(params, srs::dpar::mode);
1206 if (it != params.end()) {
1207 srs::dpar::value_mode m = static_cast<srs::dpar::value_mode>(it->template get_value<int>());
1208 if (m == srs::dpar::mode_plane) {
1209 proj_parm.dgg.output = isea_addr_plane;
1210 } else if (m == srs::dpar::mode_di) {
1211 proj_parm.dgg.output = isea_addr_q2di;
1212 } else if (m == srs::dpar::mode_dd) {
1213 proj_parm.dgg.output = isea_addr_q2dd;
1214 } else if (m == srs::dpar::mode_hex) {
1215 proj_parm.dgg.output = isea_addr_hex;
1216 } else {
1217 BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) );
1218 }
1219 }
1220 }
1221
1222
1223 template <typename Params, typename T>
1224 inline void setup_isea(Params const& params, par_isea<T>& proj_parm)
1225 {
1226 std::string opt;
1227
1228 isea_grid_init(&proj_parm.dgg);
1229
1230 proj_parm.dgg.output = isea_addr_plane;
1231
1232
1233
1234 isea_orient_init(params, proj_parm);
1235
1236 pj_param_r<srs::spar::azi>(params, "azi", srs::dpar::azi, proj_parm.dgg.o_az);
1237 pj_param_r<srs::spar::lon_0>(params, "lon_0", srs::dpar::lon_0, proj_parm.dgg.o_lon);
1238 pj_param_r<srs::spar::lat_0>(params, "lat_0", srs::dpar::lat_0, proj_parm.dgg.o_lat);
1239
1240 pj_param_i<srs::spar::aperture>(params, "aperture", srs::dpar::aperture, proj_parm.dgg.aperture);
1241
1242 pj_param_i<srs::spar::resolution>(params, "resolution", srs::dpar::resolution, proj_parm.dgg.resolution);
1243
1244 isea_mode_init(params, proj_parm);
1245
1246
1247 if (pj_param_exists<srs::spar::rescale>(params, "rescale", srs::dpar::rescale)) {
1248 proj_parm.dgg.radius = isea_scale;
1249 }
1250
1251 if (pj_param_i<srs::spar::resolution>(params, "resolution", srs::dpar::resolution, proj_parm.dgg.resolution)) {
1252
1253 } else {
1254 proj_parm.dgg.resolution = 4;
1255 }
1256
1257 if (pj_param_i<srs::spar::aperture>(params, "aperture", srs::dpar::aperture, proj_parm.dgg.aperture)) {
1258
1259 } else {
1260 proj_parm.dgg.aperture = 3;
1261 }
1262 }
1263
1264 }}
1265 #endif
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287 template <typename T, typename Parameters>
1288 struct isea_spheroid : public detail::isea::base_isea_spheroid<T, Parameters>
1289 {
1290 template <typename Params>
1291 inline isea_spheroid(Params const& params, Parameters const& )
1292 {
1293 detail::isea::setup_isea(params, this->m_proj_parm);
1294 }
1295 };
1296
1297 #ifndef DOXYGEN_NO_DETAIL
1298 namespace detail
1299 {
1300
1301
1302 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_F(srs::spar::proj_isea, isea_spheroid)
1303
1304
1305 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_F(isea_entry, isea_spheroid)
1306
1307 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(isea_init)
1308 {
1309 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(isea, isea_entry)
1310 }
1311
1312 }
1313 #endif
1314
1315 }
1316
1317 }}
1318
1319 #endif
1320