/usr/include/boost/geometry/srs/projections/proj
NameSizeModeActions
aea.hpp141000644editdlrm
aeqd.hpp221450644editdlrm
airy.hpp91360644editdlrm
aitoff.hpp133390644editdlrm
august.hpp50650644editdlrm
bacon.hpp82090644editdlrm
bipc.hpp114520644editdlrm
boggs.hpp57150644editdlrm
bonne.hpp102760644editdlrm
cass.hpp96730644editdlrm
cc.hpp52070644editdlrm
cea.hpp86090644editdlrm
chamb.hpp121450644editdlrm
collg.hpp59020644editdlrm
crast.hpp55130644editdlrm
denoy.hpp53630644editdlrm
eck1.hpp50580644editdlrm
eck2.hpp59180644editdlrm
eck3.hpp102250644editdlrm
eck4.hpp62790644editdlrm
eck5.hpp51480644editdlrm
eqc.hpp56560644editdlrm
eqdc.hpp86450644editdlrm
etmerc.hpp191940644editdlrm
fahey.hpp52220644editdlrm
fouc_s.hpp68030644editdlrm
gall.hpp51800644editdlrm
geocent.hpp51650644editdlrm
geos.hpp155620644editdlrm
gins8.hpp50840644editdlrm
gnom.hpp92330644editdlrm
gn_sinu.hpp144700644editdlrm
goode.hpp74010644editdlrm
gstmerc.hpp71770644editdlrm
hammer.hpp68820644editdlrm
hatano.hpp71580644editdlrm
healpix.hpp362460644editdlrm
igh.hpp189290644editdlrm
imw_p.hpp129420644editdlrm
isea.hpp487110644editdlrm
krovak.hpp116880644editdlrm
labrd.hpp107340644editdlrm
laea.hpp171120644editdlrm
lagrng.hpp69940644editdlrm
larr.hpp46650644editdlrm
lask.hpp52760644editdlrm
latlong.hpp61270644editdlrm
lcc.hpp112290644editdlrm
lcca.hpp93770644editdlrm
loxim.hpp71260644editdlrm
lsat.hpp151610644editdlrm
mbtfpp.hpp66290644editdlrm
mbtfpq.hpp70680644editdlrm
mbt_fps.hpp62550644editdlrm
merc.hpp88810644editdlrm
mill.hpp50870644editdlrm
mod_ster.hpp186250644editdlrm
moll.hpp93720644editdlrm
natearth.hpp82270644editdlrm
nell.hpp55510644editdlrm
nell_h.hpp56920644editdlrm
nocol.hpp60920644editdlrm
nsper.hpp131200644editdlrm
nzmg.hpp86970644editdlrm
ob_tran.hpp266080644editdlrm
ocea.hpp91730644editdlrm
oea.hpp78560644editdlrm
omerc.hpp150180644editdlrm
ortho.hpp94100644editdlrm
poly.hpp109200644editdlrm
putp2.hpp61800644editdlrm
putp3.hpp66140644editdlrm
putp4p.hpp70210644editdlrm
putp5.hpp67370644editdlrm
putp6.hpp79460644editdlrm
qsc.hpp242090644editdlrm
robin.hpp119250644editdlrm
rouss.hpp97430644editdlrm
rpoly.hpp60180644editdlrm
sconics.hpp196840644editdlrm
somerc.hpp82410644editdlrm
stere.hpp210520644editdlrm
sterea.hpp68810644editdlrm
sts.hpp100330644editdlrm
tcc.hpp48880644editdlrm
tcea.hpp51740644editdlrm
tmerc.hpp146210644editdlrm
tpeqd.hpp94830644editdlrm
urm5.hpp60180644editdlrm
urmfps.hpp75730644editdlrm
vandg.hpp93760644editdlrm
vandg2.hpp72850644editdlrm
vandg4.hpp62920644editdlrm
wag2.hpp52860644editdlrm
wag3.hpp56910644editdlrm
wag7.hpp47540644editdlrm
wink1.hpp55180644editdlrm
wink2.hpp61930644editdlrm
Edit: /usr/include/boost/geometry/srs/projections/proj/isea.hpp (48711B)
// Boost.Geometry - gis-projections (based on PROJ4) // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017, 2018, 2019. // Modifications copyright (c) 2017-2019, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // This file is converted from PROJ4, http://trac.osgeo.org/proj // PROJ4 is originally written by Gerald Evenden (then of the USGS) // PROJ4 is maintained by Frank Warmerdam // PROJ4 is converted to Boost.Geometry by Barend Gehrels // Last updated version of proj: 5.0.0 // Original copyright notice: // This code was entirely written by Nathan Wagner // and is in the public domain. // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. #ifndef BOOST_GEOMETRY_PROJECTIONS_ISEA_HPP #define BOOST_GEOMETRY_PROJECTIONS_ISEA_HPP #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { namespace projections { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace isea { static const double epsilon = std::numeric_limits::epsilon(); /* sqrt(5)/M_PI */ static const double isea_scale = 0.8301572857837594396028083; /* 26.565051177 degrees */ static const double v_lat = 0.46364760899944494524; /* 52.62263186 */ static const double e_rad = 0.91843818702186776133; /* 10.81231696 */ static const double f_rad = 0.18871053072122403508; /* R tan(g) sin(60) */ static const double table_g = 0.6615845383; /* H = 0.25 R tan g = */ static const double table_h = 0.1909830056; //static const double RPRIME = 0.91038328153090290025; static const double isea_std_lat = 1.01722196792335072101; static const double isea_std_lon = .19634954084936207740; template inline T deg30_rad() { return T(30) * geometry::math::d2r(); } template inline T deg120_rad() { return T(120) * geometry::math::d2r(); } template inline T deg72_rad() { return T(72) * geometry::math::d2r(); } template inline T deg90_rad() { return geometry::math::half_pi(); } template inline T deg144_rad() { return T(144) * geometry::math::d2r(); } template inline T deg36_rad() { return T(36) * geometry::math::d2r(); } template inline T deg108_rad() { return T(108) * geometry::math::d2r(); } template inline T deg180_rad() { return geometry::math::pi(); } inline bool downtri(int tri) { return (((tri - 1) / 5) % 2 == 1); } /* * Proj 4 provides its own entry points into * the code, so none of the library functions * need to be global */ struct hex { int iso; int x, y, z; }; /* y *must* be positive down as the xy /iso conversion assumes this */ inline int hex_xy(struct hex *h) { if (!h->iso) return 1; if (h->x >= 0) { h->y = -h->y - (h->x+1)/2; } else { /* need to round toward -inf, not toward zero, so x-1 */ h->y = -h->y - h->x/2; } h->iso = 0; return 1; } inline int hex_iso(struct hex *h) { if (h->iso) return 1; if (h->x >= 0) { h->y = (-h->y - (h->x+1)/2); } else { /* need to round toward -inf, not toward zero, so x-1 */ h->y = (-h->y - (h->x)/2); } h->z = -h->x - h->y; h->iso = 1; return 1; } template inline int hexbin2(T const& width, T x, T y, int *i, int *j) { T z, rx, ry, rz; T abs_dx, abs_dy, abs_dz; int ix, iy, iz, s; struct hex h; static const T cos_deg30 = cos(deg30_rad()); x = x / cos_deg30; /* rotated X coord */ y = y - x / 2.0; /* adjustment for rotated X */ /* adjust for actual hexwidth */ x /= width; y /= width; z = -x - y; rx = floor(x + 0.5); ix = (int)rx; ry = floor(y + 0.5); iy = (int)ry; rz = floor(z + 0.5); iz = (int)rz; s = ix + iy + iz; if (s) { abs_dx = fabs(rx - x); abs_dy = fabs(ry - y); abs_dz = fabs(rz - z); if (abs_dx >= abs_dy && abs_dx >= abs_dz) { ix -= s; } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) { iy -= s; } else { iz -= s; } } h.x = ix; h.y = iy; h.z = iz; h.iso = 1; hex_xy(&h); *i = h.x; *j = h.y; return ix * 100 + iy; } //enum isea_poly { isea_none = 0, isea_icosahedron = 20 }; //enum isea_topology { isea_hexagon=6, isea_triangle=3, isea_diamond=4 }; enum isea_address_form { /*isea_addr_geo,*/ isea_addr_q2di, isea_addr_seqnum, /*isea_addr_interleave,*/ isea_addr_plane, isea_addr_q2dd, isea_addr_projtri, isea_addr_vertex2dd, isea_addr_hex }; template struct isea_dgg { T o_lat, o_lon, o_az; /* orientation, radians */ T radius; /* radius of the earth in meters, ignored 1.0 */ unsigned long serial; //int pole; /* true if standard snyder */ int aperture; /* valid values depend on partitioning method */ int resolution; int triangle; /* triangle of last transformed point */ int quad; /* quad of last transformed point */ //isea_poly polyhedron; /* ignored, icosahedron */ //isea_topology topology; /* ignored, hexagon */ isea_address_form output; /* an isea_address_form */ }; template struct isea_pt { T x, y; }; template struct isea_geo { T lon, lat; }; template struct isea_address { T x,y; /* or i,j or lon,lat depending on type */ int type; /* enum isea_address_form */ int number; }; /* ENDINC */ enum snyder_polyhedron { snyder_poly_hexagon = 0, snyder_poly_pentagon = 1, snyder_poly_tetrahedron = 2, snyder_poly_cube = 3, snyder_poly_octahedron = 4, snyder_poly_dodecahedron = 5, snyder_poly_icosahedron = 6 }; template struct snyder_constants { T g, G, theta, ea_w, ea_a, ea_b, g_w, g_a, g_b; }; template inline const snyder_constants * constants() { /* TODO put these in radians to avoid a later conversion */ static snyder_constants result[] = { {23.80018260, 62.15458023, 60.0, 3.75, 1.033, 0.968, 5.09, 1.195, 1.0}, {20.07675127, 55.69063953, 54.0, 2.65, 1.030, 0.983, 3.59, 1.141, 1.027}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {37.37736814, 36.0, 30.0, 17.27, 1.163, 0.860, 13.14, 1.584, 1.0} }; return result; } template inline const isea_geo * vertex() { static isea_geo result[] = { { 0.0, deg90_rad()}, { deg180_rad(), v_lat}, {-deg108_rad(), v_lat}, {-deg36_rad(), v_lat}, { deg36_rad(), v_lat}, { deg108_rad(), v_lat}, {-deg144_rad(), -v_lat}, {-deg72_rad(), -v_lat}, { 0.0, -v_lat}, { deg72_rad(), -v_lat}, { deg144_rad(), -v_lat}, { 0.0, -deg90_rad()} }; return result; } /* TODO make an isea_pt array of the vertices as well */ 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}; /* triangle Centers */ template inline const isea_geo * icostriangles() { static isea_geo result[] = { { 0.0, 0.0}, {-deg144_rad(), e_rad}, {-deg72_rad(), e_rad}, { 0.0, e_rad}, { deg72_rad(), e_rad}, { deg144_rad(), e_rad}, {-deg144_rad(), f_rad}, {-deg72_rad(), f_rad}, { 0.0, f_rad}, { deg72_rad(), f_rad}, { deg144_rad(), f_rad}, {-deg108_rad(), -f_rad}, {-deg36_rad(), -f_rad}, { deg36_rad(), -f_rad}, { deg108_rad(), -f_rad}, { deg180_rad(), -f_rad}, {-deg108_rad(), -e_rad}, {-deg36_rad(), -e_rad}, { deg36_rad(), -e_rad}, { deg108_rad(), -e_rad}, { deg180_rad(), -e_rad}, }; return result; } template inline T az_adjustment(int triangle) { T adj; isea_geo v; isea_geo c; v = vertex()[tri_v1[triangle]]; c = icostriangles()[triangle]; /* TODO looks like the adjustment is always either 0 or 180 */ /* at least if you pick your vertex carefully */ adj = atan2(cos(v.lat) * sin(v.lon - c.lon), cos(c.lat) * sin(v.lat) - sin(c.lat) * cos(v.lat) * cos(v.lon - c.lon)); return adj; } template inline isea_pt isea_triangle_xy(int triangle) { isea_pt c; T Rprime = 0.91038328153090290025; triangle = (triangle - 1) % 20; c.x = table_g * ((triangle % 5) - 2) * 2.0; if (triangle > 9) { c.x += table_g; } switch (triangle / 5) { case 0: c.y = 5.0 * table_h; break; case 1: c.y = table_h; break; case 2: c.y = -table_h; break; case 3: c.y = -5.0 * table_h; break; default: /* should be impossible */ BOOST_THROW_EXCEPTION( projection_exception() ); }; c.x *= Rprime; c.y *= Rprime; return c; } /* snyder eq 14 */ template inline T sph_azimuth(T const& f_lon, T const& f_lat, T const& t_lon, T const& t_lat) { T az; az = atan2(cos(t_lat) * sin(t_lon - f_lon), cos(f_lat) * sin(t_lat) - sin(f_lat) * cos(t_lat) * cos(t_lon - f_lon) ); return az; } /* coord needs to be in radians */ template inline int isea_snyder_forward(isea_geo * ll, isea_pt * out) { static T const two_pi = detail::two_pi(); static T const d2r = geometry::math::d2r(); int i; /* * spherical distance from center of polygon face to any of its * vertexes on the globe */ T g; /* * spherical angle between radius vector to center and adjacent edge * of spherical polygon on the globe */ T G; /* * plane angle between radius vector to center and adjacent edge of * plane polygon */ T theta; /* additional variables from snyder */ T q, Rprime, H, Ag, Azprime, Az, dprime, f, rho, x, y; /* variables used to store intermediate results */ T cot_theta, tan_g, az_offset; /* how many multiples of 60 degrees we adjust the azimuth */ int Az_adjust_multiples; snyder_constants c; /* * TODO by locality of reference, start by trying the same triangle * as last time */ /* TODO put these constants in as radians to begin with */ c = constants()[snyder_poly_icosahedron]; theta = c.theta * d2r; g = c.g * d2r; G = c.G * d2r; for (i = 1; i <= 20; i++) { T z; isea_geo center; center = icostriangles()[i]; /* step 1 */ z = acos(sin(center.lat) * sin(ll->lat) + cos(center.lat) * cos(ll->lat) * cos(ll->lon - center.lon)); /* not on this triangle */ if (z > g + 0.000005) { /* TODO DBL_EPSILON */ continue; } Az = sph_azimuth(center.lon, center.lat, ll->lon, ll->lat); /* step 2 */ /* This calculates "some" vertex coordinate */ az_offset = az_adjustment(i); Az -= az_offset; /* TODO I don't know why we do this. It's not in snyder */ /* maybe because we should have picked a better vertex */ if (Az < 0.0) { Az += two_pi; } /* * adjust Az for the point to fall within the range of 0 to * 2(90 - theta) or 60 degrees for the hexagon, by * and therefore 120 degrees for the triangle * of the icosahedron * subtracting or adding multiples of 60 degrees to Az and * recording the amount of adjustment */ Az_adjust_multiples = 0; while (Az < 0.0) { Az += deg120_rad(); Az_adjust_multiples--; } while (Az > deg120_rad() + epsilon) { Az -= deg120_rad(); Az_adjust_multiples++; } /* step 3 */ cot_theta = 1.0 / tan(theta); tan_g = tan(g); /* TODO this is a constant */ /* Calculate q from eq 9. */ /* TODO cot_theta is cot(30) */ q = atan2(tan_g, cos(Az) + sin(Az) * cot_theta); /* not in this triangle */ if (z > q + 0.000005) { continue; } /* step 4 */ /* Apply equations 5-8 and 10-12 in order */ /* eq 5 */ /* Rprime = 0.9449322893 * R; */ /* R' in the paper is for the truncated */ Rprime = 0.91038328153090290025; /* eq 6 */ H = acos(sin(Az) * sin(G) * cos(g) - cos(Az) * cos(G)); /* eq 7 */ /* Ag = (Az + G + H - deg180_rad) * M_PI * R * R / deg180_rad; */ Ag = Az + G + H - deg180_rad(); /* eq 8 */ Azprime = atan2(2.0 * Ag, Rprime * Rprime * tan_g * tan_g - 2.0 * Ag * cot_theta); /* eq 10 */ /* cot(theta) = 1.73205080756887729355 */ dprime = Rprime * tan_g / (cos(Azprime) + sin(Azprime) * cot_theta); /* eq 11 */ f = dprime / (2.0 * Rprime * sin(q / 2.0)); /* eq 12 */ rho = 2.0 * Rprime * f * sin(z / 2.0); /* * add back the same 60 degree multiple adjustment from step * 2 to Azprime */ Azprime += deg120_rad() * Az_adjust_multiples; /* calculate rectangular coordinates */ x = rho * sin(Azprime); y = rho * cos(Azprime); /* * TODO * translate coordinates to the origin for the particular * hexagon on the flattened polyhedral map plot */ out->x = x; out->y = y; return i; } /* * should be impossible, this implies that the coordinate is not on * any triangle */ //fprintf(stderr, "impossible transform: %f %f is not on any triangle\n", // ll->lon * geometry::math::r2d(), ll->lat * geometry::math::r2d()); std::stringstream ss; ss << "impossible transform: " << ll->lon * geometry::math::r2d() << " " << ll->lat * geometry::math::r2d() << " is not on any triangle."; BOOST_THROW_EXCEPTION( projection_exception(ss.str()) ); /* not reached */ return 0; /* supresses a warning */ } /* * return the new coordinates of any point in orginal coordinate system. * Define a point (newNPold) in orginal coordinate system as the North Pole in * new coordinate system, and the great circle connect the original and new * North Pole as the lon0 longitude in new coordinate system, given any point * in orginal coordinate system, this function return the new coordinates. */ /* formula from Snyder, Map Projections: A working manual, p31 */ /* * old north pole at np in new coordinates * could be simplified a bit with fewer intermediates * * TODO take a result pointer */ template inline isea_geo snyder_ctran(isea_geo * np, isea_geo * pt) { static T const pi = detail::pi(); static T const two_pi = detail::two_pi(); isea_geo npt; T alpha, phi, lambda, lambda0, beta, lambdap, phip; T sin_phip; T lp_b; /* lambda prime minus beta */ T cos_p, sin_a; phi = pt->lat; lambda = pt->lon; alpha = np->lat; beta = np->lon; lambda0 = beta; cos_p = cos(phi); sin_a = sin(alpha); /* mpawm 5-7 */ sin_phip = sin_a * sin(phi) - cos(alpha) * cos_p * cos(lambda - lambda0); /* mpawm 5-8b */ /* use the two argument form so we end up in the right quadrant */ lp_b = atan2(cos_p * sin(lambda - lambda0), (sin_a * cos_p * cos(lambda - lambda0) + cos(alpha) * sin(phi))); lambdap = lp_b + beta; /* normalize longitude */ /* TODO can we just do a modulus ? */ lambdap = fmod(lambdap, two_pi); while (lambdap > pi) lambdap -= two_pi; while (lambdap < -pi) lambdap += two_pi; phip = asin(sin_phip); npt.lat = phip; npt.lon = lambdap; return npt; } template inline isea_geo isea_ctran(isea_geo * np, isea_geo * pt, T const& lon0) { static T const pi = detail::pi(); static T const two_pi = detail::two_pi(); isea_geo npt; np->lon += pi; npt = snyder_ctran(np, pt); np->lon -= pi; npt.lon -= (pi - lon0 + np->lon); /* * snyder is down tri 3, isea is along side of tri1 from vertex 0 to * vertex 1 these are 180 degrees apart */ npt.lon += pi; /* normalize longitude */ npt.lon = fmod(npt.lon, two_pi); while (npt.lon > pi) npt.lon -= two_pi; while (npt.lon < -pi) npt.lon += two_pi; return npt; } /* in radians */ /* fuller's at 5.2454 west, 2.3009 N, adjacent at 7.46658 deg */ template inline int isea_grid_init(isea_dgg * g) { if (!g) return 0; //g->polyhedron = isea_icosahedron; g->o_lat = isea_std_lat; g->o_lon = isea_std_lon; g->o_az = 0.0; g->aperture = 4; g->resolution = 6; g->radius = 1.0; //g->topology = isea_hexagon; return 1; } template inline int isea_orient_isea(isea_dgg * g) { if (!g) return 0; g->o_lat = isea_std_lat; g->o_lon = isea_std_lon; g->o_az = 0.0; return 1; } template inline int isea_orient_pole(isea_dgg * g) { static T const half_pi = detail::half_pi(); if (!g) return 0; g->o_lat = half_pi; g->o_lon = 0.0; g->o_az = 0; return 1; } template inline int isea_transform(isea_dgg * g, isea_geo * in, isea_pt * out) { isea_geo i, pole; int tri; pole.lat = g->o_lat; pole.lon = g->o_lon; i = isea_ctran(&pole, in, g->o_az); tri = isea_snyder_forward(&i, out); out->x *= g->radius; out->y *= g->radius; g->triangle = tri; return tri; } template inline void isea_rotate(isea_pt * pt, T const& degrees) { static T const d2r = geometry::math::d2r(); static T const two_pi = detail::two_pi(); T rad; T x, y; rad = -degrees * d2r; while (rad >= two_pi) rad -= two_pi; while (rad <= -two_pi) rad += two_pi; x = pt->x * cos(rad) + pt->y * sin(rad); y = -pt->x * sin(rad) + pt->y * cos(rad); pt->x = x; pt->y = y; } template inline int isea_tri_plane(int tri, isea_pt *pt, T const& radius) { isea_pt tc; /* center of triangle */ if (downtri(tri)) { isea_rotate(pt, 180.0); } tc = isea_triangle_xy(tri); tc.x *= radius; tc.y *= radius; pt->x += tc.x; pt->y += tc.y; return tri; } /* convert projected triangle coords to quad xy coords, return quad number */ template inline int isea_ptdd(int tri, isea_pt *pt) { int downtri, quad; downtri = (((tri - 1) / 5) % 2 == 1); quad = ((tri - 1) % 5) + ((tri - 1) / 10) * 5 + 1; isea_rotate(pt, downtri ? 240.0 : 60.0); if (downtri) { pt->x += 0.5; /* pt->y += cos(30.0 * M_PI / 180.0); */ pt->y += .86602540378443864672; } return quad; } template inline int isea_dddi_ap3odd(isea_dgg *g, int quad, isea_pt *pt, isea_pt *di) { static T const pi = detail::pi(); isea_pt v; T hexwidth; T sidelength; /* in hexes */ int d, i; int maxcoord; hex h; /* This is the number of hexes from apex to base of a triangle */ sidelength = (math::pow(T(2), g->resolution) + T(1)) / T(2); /* apex to base is cos(30deg) */ hexwidth = cos(pi / 6.0) / sidelength; /* TODO I think sidelength is always x.5, so * (int)sidelength * 2 + 1 might be just as good */ maxcoord = (int) (sidelength * 2.0 + 0.5); v = *pt; hexbin2(hexwidth, v.x, v.y, &h.x, &h.y); h.iso = 0; hex_iso(&h); d = h.x - h.z; i = h.x + h.y + h.y; /* * you want to test for max coords for the next quad in the same * "row" first to get the case where both are max */ if (quad <= 5) { if (d == 0 && i == maxcoord) { /* north pole */ quad = 0; d = 0; i = 0; } else if (i == maxcoord) { /* upper right in next quad */ quad += 1; if (quad == 6) quad = 1; i = maxcoord - d; d = 0; } else if (d == maxcoord) { /* lower right in quad to lower right */ quad += 5; d = 0; } } else if (quad >= 6) { if (i == 0 && d == maxcoord) { /* south pole */ quad = 11; d = 0; i = 0; } else if (d == maxcoord) { /* lower right in next quad */ quad += 1; if (quad == 11) quad = 6; d = maxcoord - i; i = 0; } else if (i == maxcoord) { /* upper right in quad to upper right */ quad = (quad - 4) % 5; i = 0; } } di->x = d; di->y = i; g->quad = quad; return quad; } template inline int isea_dddi(isea_dgg *g, int quad, isea_pt *pt, isea_pt *di) { isea_pt v; T hexwidth; int sidelength; /* in hexes */ hex h; if (g->aperture == 3 && g->resolution % 2 != 0) { return isea_dddi_ap3odd(g, quad, pt, di); } /* todo might want to do this as an iterated loop */ if (g->aperture >0) { sidelength = (int) (math::pow(T(g->aperture), T(g->resolution / T(2))) + T(0.5)); } else { sidelength = g->resolution; } hexwidth = 1.0 / sidelength; v = *pt; isea_rotate(&v, -30.0); hexbin2(hexwidth, v.x, v.y, &h.x, &h.y); h.iso = 0; hex_iso(&h); /* we may actually be on another quad */ if (quad <= 5) { if (h.x == 0 && h.z == -sidelength) { /* north pole */ quad = 0; h.z = 0; h.y = 0; h.x = 0; } else if (h.z == -sidelength) { quad = quad + 1; if (quad == 6) quad = 1; h.y = sidelength - h.x; h.z = h.x - sidelength; h.x = 0; } else if (h.x == sidelength) { quad += 5; h.y = -h.z; h.x = 0; } } else if (quad >= 6) { if (h.z == 0 && h.x == sidelength) { /* south pole */ quad = 11; h.x = 0; h.y = 0; h.z = 0; } else if (h.x == sidelength) { quad = quad + 1; if (quad == 11) quad = 6; h.x = h.y + sidelength; h.y = 0; h.z = -h.x; } else if (h.y == -sidelength) { quad -= 4; h.y = 0; h.z = -h.x; } } di->x = h.x; di->y = -h.z; g->quad = quad; return quad; } template inline int isea_ptdi(isea_dgg *g, int tri, isea_pt *pt, isea_pt *di) { isea_pt v; int quad; v = *pt; quad = isea_ptdd(tri, &v); quad = isea_dddi(g, quad, &v, di); return quad; } /* q2di to seqnum */ template inline int isea_disn(isea_dgg *g, int quad, isea_pt *di) { int sidelength; int sn, height; int hexes; if (quad == 0) { g->serial = 1; return g->serial; } /* hexes in a quad */ hexes = (int) (math::pow(T(g->aperture), T(g->resolution)) + T(0.5)); if (quad == 11) { g->serial = 1 + 10 * hexes + 1; return g->serial; } if (g->aperture == 3 && g->resolution % 2 == 1) { height = (int) (math::pow(T(g->aperture), T((g->resolution - 1) / T(2)))); sn = ((int) di->x) * height; sn += ((int) di->y) / height; sn += (quad - 1) * hexes; sn += 2; } else { sidelength = (int) (math::pow(T(g->aperture), T(g->resolution / T(2))) + T(0.5)); sn = (int) ((quad - 1) * hexes + sidelength * di->x + di->y + 2); } g->serial = sn; return sn; } /* TODO just encode the quad in the d or i coordinate * quad is 0-11, which can be four bits. * d' = d << 4 + q, d = d' >> 4, q = d' & 0xf */ /* convert a q2di to global hex coord */ template inline int isea_hex(isea_dgg *g, int tri, isea_pt *pt, isea_pt *hex) { isea_pt v; #ifdef BOOST_GEOMETRY_PROJECTIONS_FIXME int sidelength; int d, i, x, y; #endif // BOOST_GEOMETRY_PROJECTIONS_FIXME int quad; quad = isea_ptdi(g, tri, pt, &v); hex->x = ((int)v.x << 4) + quad; hex->y = v.y; return 1; #ifdef BOOST_GEOMETRY_PROJECTIONS_FIXME d = (int)v.x; i = (int)v.y; /* Aperture 3 odd resolutions */ if (g->aperture == 3 && g->resolution % 2 != 0) { int offset = (int)(pow(T(3.0), T(g->resolution - 1)) + 0.5); d += offset * ((g->quad-1) % 5); i += offset * ((g->quad-1) % 5); if (quad == 0) { d = 0; i = offset; } else if (quad == 11) { d = 2 * offset; i = 0; } else if (quad > 5) { d += offset; } x = (2*d - i) /3; y = (2*i - d) /3; hex->x = x + offset / 3; hex->y = y + 2 * offset / 3; return 1; } /* aperture 3 even resolutions and aperture 4 */ sidelength = (int) (pow(T(g->aperture), T(g->resolution / 2.0)) + 0.5); if (g->quad == 0) { hex->x = 0; hex->y = sidelength; } else if (g->quad == 11) { hex->x = sidelength * 2; hex->y = 0; } else { hex->x = d + sidelength * ((g->quad-1) % 5); if (g->quad > 5) hex->x += sidelength; hex->y = i + sidelength * ((g->quad-1) % 5); } return 1; #endif // BOOST_GEOMETRY_PROJECTIONS_FIXME } template inline isea_pt isea_forward(isea_dgg *g, isea_geo *in) { int tri; isea_pt out, coord; tri = isea_transform(g, in, &out); if (g->output == isea_addr_plane) { isea_tri_plane(tri, &out, g->radius); return out; } /* convert to isea standard triangle size */ out.x = out.x / g->radius * isea_scale; out.y = out.y / g->radius * isea_scale; out.x += 0.5; out.y += 2.0 * .14433756729740644112; switch (g->output) { case isea_addr_projtri: /* nothing to do, already in projected triangle */ break; case isea_addr_vertex2dd: g->quad = isea_ptdd(tri, &out); break; case isea_addr_q2dd: /* Same as above, we just don't print as much */ g->quad = isea_ptdd(tri, &out); break; case isea_addr_q2di: g->quad = isea_ptdi(g, tri, &out, &coord); return coord; break; case isea_addr_seqnum: isea_ptdi(g, tri, &out, &coord); /* disn will set g->serial */ isea_disn(g, g->quad, &coord); return coord; break; case isea_addr_hex: isea_hex(g, tri, &out, &coord); return coord; break; default: // isea_addr_plane handled above BOOST_GEOMETRY_ASSERT(false); break; } return out; } /* * Proj 4 integration code follows */ template struct par_isea { isea_dgg dgg; }; template struct base_isea_spheroid { par_isea m_proj_parm; // FORWARD(s_forward) // Project coordinates from geographic (lon, lat) to cartesian (x, y) inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const { isea_pt out; isea_geo in; in.lon = lp_lon; in.lat = lp_lat; isea_dgg copy = this->m_proj_parm.dgg; out = isea_forward(©, &in); xy_x = out.x; xy_y = out.y; } static inline std::string get_name() { return "isea_spheroid"; } }; template inline void isea_orient_init(srs::detail::proj4_parameters const& params, par_isea& proj_parm) { std::string opt = pj_get_param_s(params, "orient"); if (! opt.empty()) { if (opt == std::string("isea")) { isea_orient_isea(&proj_parm.dgg); } else if (opt == std::string("pole")) { isea_orient_pole(&proj_parm.dgg); } else { BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) ); } } } template inline void isea_orient_init(srs::dpar::parameters const& params, par_isea& proj_parm) { typename srs::dpar::parameters::const_iterator it = pj_param_find(params, srs::dpar::orient); if (it != params.end()) { srs::dpar::value_orient o = static_cast(it->template get_value()); if (o == srs::dpar::orient_isea) { isea_orient_isea(&proj_parm.dgg); } else if (o == srs::dpar::orient_pole) { isea_orient_pole(&proj_parm.dgg); } else { BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) ); } } } template inline void isea_mode_init(srs::detail::proj4_parameters const& params, par_isea& proj_parm) { std::string opt = pj_get_param_s(params, "mode"); if (! opt.empty()) { if (opt == std::string("plane")) { proj_parm.dgg.output = isea_addr_plane; } else if (opt == std::string("di")) { proj_parm.dgg.output = isea_addr_q2di; } else if (opt == std::string("dd")) { proj_parm.dgg.output = isea_addr_q2dd; } else if (opt == std::string("hex")) { proj_parm.dgg.output = isea_addr_hex; } else { BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) ); } } } template inline void isea_mode_init(srs::dpar::parameters const& params, par_isea& proj_parm) { typename srs::dpar::parameters::const_iterator it = pj_param_find(params, srs::dpar::mode); if (it != params.end()) { srs::dpar::value_mode m = static_cast(it->template get_value()); if (m == srs::dpar::mode_plane) { proj_parm.dgg.output = isea_addr_plane; } else if (m == srs::dpar::mode_di) { proj_parm.dgg.output = isea_addr_q2di; } else if (m == srs::dpar::mode_dd) { proj_parm.dgg.output = isea_addr_q2dd; } else if (m == srs::dpar::mode_hex) { proj_parm.dgg.output = isea_addr_hex; } else { BOOST_THROW_EXCEPTION( projection_exception(error_ellipsoid_use_required) ); } } } // Icosahedral Snyder Equal Area template inline void setup_isea(Params const& params, par_isea& proj_parm) { std::string opt; isea_grid_init(&proj_parm.dgg); proj_parm.dgg.output = isea_addr_plane; /* proj_parm.dgg.radius = par.a; / * otherwise defaults to 1 */ /* calling library will scale, I think */ isea_orient_init(params, proj_parm); pj_param_r(params, "azi", srs::dpar::azi, proj_parm.dgg.o_az); pj_param_r(params, "lon_0", srs::dpar::lon_0, proj_parm.dgg.o_lon); pj_param_r(params, "lat_0", srs::dpar::lat_0, proj_parm.dgg.o_lat); // TODO: this parameter is set below second time pj_param_i(params, "aperture", srs::dpar::aperture, proj_parm.dgg.aperture); // TODO: this parameter is set below second time pj_param_i(params, "resolution", srs::dpar::resolution, proj_parm.dgg.resolution); isea_mode_init(params, proj_parm); // TODO: pj_param_exists -> pj_get_param_b ? if (pj_param_exists(params, "rescale", srs::dpar::rescale)) { proj_parm.dgg.radius = isea_scale; } if (pj_param_i(params, "resolution", srs::dpar::resolution, proj_parm.dgg.resolution)) { /* empty */ } else { proj_parm.dgg.resolution = 4; } if (pj_param_i(params, "aperture", srs::dpar::aperture, proj_parm.dgg.aperture)) { /* empty */ } else { proj_parm.dgg.aperture = 3; } } }} // namespace detail::isea #endif // doxygen /*! \brief Icosahedral Snyder Equal Area projection \ingroup projections \tparam Geographic latlong point type \tparam Cartesian xy point type \tparam Parameters parameter type \par Projection characteristics - Spheroid \par Projection parameters - orient (string) - azi: Azimuth (or Gamma) (degrees) - lon_0: Central meridian (degrees) - lat_0: Latitude of origin (degrees) - aperture (integer) - resolution (integer) - mode (string) - rescale \par Example \image html ex_isea.gif */ template struct isea_spheroid : public detail::isea::base_isea_spheroid { template inline isea_spheroid(Params const& params, Parameters const& ) { detail::isea::setup_isea(params, this->m_proj_parm); } }; #ifndef DOXYGEN_NO_DETAIL namespace detail { // Static projection BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_F(srs::spar::proj_isea, isea_spheroid) // Factory entry(s) BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_F(isea_entry, isea_spheroid) BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(isea_init) { BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(isea, isea_entry) } } // namespace detail #endif // doxygen } // namespace projections }} // namespace boost::geometry #endif // BOOST_GEOMETRY_PROJECTIONS_ISEA_HPP