def csea(a=1, e=0): r""" Return a function object that wraps the ISEA projection and its inverse of an ellipsoid with major radius `a` and eccentricity `e`. OUTPUT: - A function object of the form f(u, v, radians=False, inverse=False). """ R_A = auth_rad(a, e) def f(u, v, radians=False, inverse=False): if not inverse: lam, phi = u, v if not radians: # Convert to radians. lam, phi = deg2rad([lam, phi]) return tuple(R_A * array(csea_ellipsoid(lam, phi, e=e))) else: # Scale down to R_A = 1. x, y = array((u, v)) / R_A lam, phi = array(csea_ellipsoid_inverse(x, y, e=e)) if not radians: # Convert to degrees. lam, phi = rad2deg([lam, phi]) return lam, phi return f
def test_rhealpix(self): inputs = [(-pi, pi / 3), (0, pi / 4), (pi / 2, -pi / 6)] # Should agree with rhealpix_ellipsoid and rhealpix_ellipsoid_inverse. e = 0.5 a = 7 R_A = auth_rad(a, e) f = pjr.rhealpix(a=a, e=e) for p in inputs: get = f(*p, radians=True) expect = tuple(R_A * array(pjr.rhealpix_ellipsoid(*p, e=e))) for i in range(len(expect)): self.assertAlmostEqual(get[i], expect[i]) get = f(*get, radians=True, inverse=True) expect = tuple(array(expect) / R_A) expect = pjr.rhealpix_ellipsoid_inverse(*expect, e=e) for i in range(len(expect)): self.assertAlmostEqual(get[i], expect[i]) # Should work in degrees mode. for p in inputs: get = f(*rad2deg(p), radians=False) expect = f(*p, radians=True) for i in range(len(expect)): self.assertAlmostEqual(get[i], expect[i])
def test_rhealpix_ellipsoid(self): # Ellipsoid parameters. a = 5 e = 0.8 R_A = auth_rad(a, e=e) # Forward projection should be correct on test points. print '='*80 print 'rHEALPix forward projection, ellipsoid with major radius a = %s and eccentricity e = %s' % (a, e) print 'input (radians) / expected output (meters) / received output' print '='*80 given = inputs # Fuzz to allow for rounding errors: error = 1e-12 for (ns, ss) in product(range(4), repeat=2): print '_____ north_square = %s, south_square = %s' % (ns, ss) expect = [] g = Proj(proj='rhealpix', R=R_A, north_square=ns, south_square=ss) for p in given: lam, phi = p beta = auth_lat(phi, e=e, radians=True) q = g(lam, beta, radians=True) expect.append(tuple(q)) f = Proj(proj='rhealpix', a=a, e=e, north_square=ns, south_square=ss) get = [f(*p, radians=True) for p in given] for i in range(len(given)): print given[i], expect[i], get[i] self.assertTrue(rel_err(get[i], expect[i]) < error) # Inverse of projection of point a p should yield p. # Fuzz for rounding errors based on the error of the approximation to # the inverse authalic latitude function: alpha = pi/4 alpha_ = auth_lat(auth_lat(alpha, e, radians=True), e, radians=True, inverse=True) error = 10*rel_err(alpha_, alpha) print '='*80 print 'HEALPix inverse projection, ellipsoid with major radius a = %s and eccentricity e = %s' % (a, e) print 'input (meters) / expected output (radians) / received output' print '='*80 # The inverse of the projection of a point p should yield p. for (ns, ss) in product(range(4), repeat=2): print '_____ north_square = %s, south_square = %s' % (ns, ss) f = Proj(proj='rhealpix', a=a, e=e, north_square=ns, south_square=ss) for p in inputs: expect = p q = f(*p, radians=True) get = f(*q, radians=True, inverse=True) print q, expect, get self.assertTrue(rel_err(get, expect) < error)
def rhealpix(a=1, e=0, north_square=0, south_square=0): r""" Return a function object that wraps the rHEALPix projection and its inverse of an ellipsoid with major radius `a` and eccentricity `e`. EXAMPLES:: >>> f = rhealpix(a=2, e=0, north_square=1, south_square=2) >>> print(f(0, pi/3, radians=True)) (-0.57495135977821477, 2.1457476865731113) >>> p = (0, 60) >>> q = f(*p, radians=False); print(q) (-0.57495135977821477, 2.1457476865731113) >>> print(f(*q, radians=False, inverse=True), p) (6.3611093629270335e-15, 59.999999999999986) (0, 60) OUTPUT: - A function object of the form f(u, v, radians=False, inverse=False). """ R_A = auth_rad(a, e) def f(u, v, radians=False, inverse=False): if not inverse: lam, phi = u, v if not radians: # Convert to radians. lam, phi = deg2rad([lam, phi]) return tuple(R_A * array( rhealpix_ellipsoid(lam, phi, e=e, north_square=north_square, south_square=south_square))) else: # Scale down to R_A = 1. x, y = array((u, v)) / R_A lam, phi = array( rhealpix_ellipsoid_inverse(x, y, e=e, north_square=north_square, south_square=south_square)) if not radians: # Convert to degrees. lam, phi = rad2deg([lam, phi]) return lam, phi return f
def __init__(self, R=None, a=WGS84_A, b=None, e=None, f=WGS84_F, lon_0=0, lat_0=0, radians=False): self.lon_0 = lon_0 self.lat_0 = lat_0 self.radians = radians if R is not None: # The ellipsoid is a sphere. # Override the other geometric parameters. self.sphere = True self.R = R self.a = R self.b = R self.e = 0 self.f = 0 self.R_A = R else: self.sphere = False self.a = a if b is not None: # Derive the other geometric parameters from a and b. self.b = b self.e = sqrt(1 - (b / a)**2) self.f = (a - b) / a elif e is not None: # Derive the other geometric parameters from a and e. self.e = e self.b = a * sqrt(1 - e**2) self.f = 1 - sqrt(1 - e**2) else: self.f = f self.b = self.a * (1 - f) self.e = sqrt(f * (1 - f)) self.R_A = auth_rad(self.a, self.e) self.phi_0 = auth_lat(arcsin(2.0 / 3), e=self.e, radians=True, inverse=True) if not self.radians: # Convert to degrees. self.phi_0 = rad2deg(self.phi_0)
def test_healpix_ellipsoid(self): # Ellipsoid parameters. a = 5 e = 0.8 R_A = auth_rad(a, e=e) # Expected output of healpix_ellipsoid() applied to inputs. healpix_ellipsoid_outputs = [] g = Proj(proj='healpix', R=R_A) for p in inputs: lam, phi = p beta = auth_lat(phi, e=e, radians=True) q = g(lam, beta, radians=True) healpix_ellipsoid_outputs.append(q) # Forward projection should be correct on test points. f = Proj(proj='healpix', a=a, e=e) given = inputs get = [f(*p, radians=True) for p in given] expect = healpix_ellipsoid_outputs # Fuzz to allow for rounding errors: error = 1e-12 print '='*80 print 'HEALPix forward projection, ellipsoid with major radius a = %s and eccentricity e = %s' % (a, e) print 'input (radians) / expected output (meters) / received output' print '='*80 for i in range(len(get)): print given[i], expect[i], get[i] self.assertTrue(rel_err(get[i], expect[i]) < error) # Inverse of projection of a point p should yield p. given = get get = [f(*q, radians=True, inverse=True) for q in given] expect = inputs # Fuzz for rounding errors based on the error of the approximation to # the inverse authalic latitude function: alpha = pi/4 alpha_ = auth_lat(auth_lat(alpha, e, radians=True), e, radians=True, inverse=True) error = 10*rel_err(alpha_, alpha) print '='*80 print 'HEALPix inverse projection, ellipsoid with major radius a = %s and eccentricity e = %s' % (a, e) print 'input (meters) / expected output (radians) / received output' print '='*80 for i in range(len(get)): print given[i], expect[i], get[i] self.assertTrue(rel_err(get[i], expect[i]) < error)
def isea(a=1, e=0): r""" Return a function object that wraps the ISEA projection and its inverse of an ellipsoid with major radius `a` and eccentricity `e`. EXAMPLES:: >>> f = isea(a=2, e=0) >>> print f(0, pi/3, radians=True) (-4.7097959155097699, 2.9195761776404252) >>> g = isea(a=2, e=0.1) >>> print g(0, 60, radians=False) (-4.6978889550868494, 2.9179977608222689) OUTPUT: - A function object of the form f(u, v, radians=False, inverse=False). """ R_A = auth_rad(a, e) def f(u, v, radians=False, inverse=False): if not inverse: lam, phi = u, v if not radians: # Convert to radians. lam, phi = deg2rad([lam, phi]) return tuple(R_A * array(isea_ellipsoid(lam, phi, e=e))) else: # Scale down to R_A = 1. x, y = array((u, v)) / R_A lam, phi = array(isea_ellipsoid_inverse(x, y, e=e)) if not radians: # Convert to degrees. lam, phi = rad2deg([lam, phi]) return lam, phi return f
def rhealpix_diagram(a=1, e=0, north_square=0, south_square=0, shade_polar_region=True): r""" Return a Sage Graphics object diagramming the rHEALPix projection boundary and polar triangles for the ellipsoid with major radius `a` and eccentricity `e`. Inessential graphics method. Requires Sage graphics methods. """ from sage.all import Graphics, line2d, point, polygon, text, RealNumber, Integer # Make Sage types compatible with Numpy. RealNumber = float Integer = int R = auth_rad(a, e) g = Graphics() color = 'black' # Boundary color. shade_color = 'blue' # Polar triangles color. north = north_square south = south_square south_sq = [(-R * pi + R * south * pi / 2, -R * pi / 4), (-R * pi + R * south * pi / 2, -R * 3 * pi / 4), (-R * pi + R * (south + 1) * pi / 2, -R * 3 * pi / 4), (-R * pi + R * (south + 1) * pi / 2, -R * pi / 4)] north_sq = [(-R * pi + R * north * pi / 2, R * pi / 4), (-R * pi + R * north * pi / 2, R * 3 * pi / 4), (-R * pi + R * (north + 1) * pi / 2, R * 3 * pi / 4), (-R * pi + R * (north + 1) * pi / 2, R * pi / 4)] # Outline. g += line2d(south_sq, linestyle='--', color=color) g += line2d(north_sq, linestyle='--', color=color) g += line2d([(R * pi, -R * pi / 4), (R * pi, R * pi / 4)], linestyle='--', color=color) g += line2d([ north_sq[0], (-R * pi, R * pi / 4), (-R * pi, -R * pi / 4), south_sq[0] ], color=color) g += line2d([south_sq[3], (R * pi, -R * pi / 4)], color=color) g += line2d([north_sq[3], (R * pi, R * pi / 4)], color=color) g += point([south_sq[0], south_sq[3]], size=20, zorder=3, color=color) g += point([north_sq[0], north_sq[3]], size=20, zorder=3, color=color) g += point([(R * pi, -R * pi / 4), (R * pi, R * pi / 4)], size=20, zorder=3, color=color) g += point([(R * pi, -R * pi / 4), (R * pi, R * pi / 4)], size=10, color='white', zorder=3) if shade_polar_region: # Shade. g += polygon(south_sq, alpha=0.1, color=shade_color) g += polygon(north_sq, alpha=0.1, color=shade_color) # Slice square into polar triangles. g += line2d([south_sq[0], south_sq[2]], color='lightgray') g += line2d([south_sq[1], south_sq[3]], color='lightgray') g += line2d([north_sq[0], north_sq[2]], color='lightgray') g += line2d([north_sq[1], north_sq[3]], color='lightgray') # Label polar triangles. sp = south_sq[0] + R * array((pi / 4, -pi / 4)) np = north_sq[0] + R * array((pi / 4, pi / 4)) shift = R * 3 * pi / 16 g += text(str(south), sp + array((0, shift)), color='red', fontsize=20) g += text(str((south + 1) % 4), sp + array((shift, 0)), color='red', rotation=90, fontsize=20) g += text(str((south + 2) % 4), sp + array((0, -shift)), color='red', rotation=180, fontsize=20) g += text(str((south + 3) % 4), sp + array((-shift, 0)), color='red', rotation=270, fontsize=20) g += text(str(north), np + array((0, -shift)), color='red', fontsize=20) g += text(str((north + 1) % 4), np + array((shift, 0)), color='red', rotation=90, fontsize=20) g += text(str((north + 2) % 4), np + array((0, shift)), color='red', rotation=180, fontsize=20) g += text(str((north + 3) % 4), np + array((-shift, 0)), color='red', rotation=270, fontsize=20) return g
def healpix_diagram(a=1, e=0, shade_polar_region=True): r""" Return a Sage Graphics object diagramming the HEALPix projection boundary and polar triangles for the ellipsoid with major radius `a` and eccentricity `e`. Inessential graphics method. Requires Sage graphics methods. """ from sage.all import Graphics, line2d, point, polygon, text, RealNumber, Integer # Make Sage types compatible with Numpy. RealNumber = float Integer = int R = auth_rad(a, e) g = Graphics() color = 'black' # Boundary color. shade_color = 'blue' # Polar triangles color. dl = array((R * pi / 2, 0)) lu = [(-R * pi, R * pi / 4), (-R * 3 * pi / 4, R * pi / 2)] ld = [(-R * 3 * pi / 4, R * pi / 2), (-R * pi / 2, R * pi / 4)] g += line2d([(-R * pi, -R * pi / 4), (-R * pi, R * pi / 4)], color=color) g += line2d([(R * pi, R * pi / 4), (R * pi, -R * pi / 4)], linestyle='--', color=color) for k in range(4): g += line2d([array(p) + k * dl for p in lu], color=color) g += line2d([array(p) + k * dl for p in ld], linestyle='--', color=color) g += line2d([ array(p) + array((k * R * pi / 2 - R * pi / 4, -R * 3 * pi / 4)) for p in ld ], color=color) g += line2d([ array(p) + array((k * R * pi / 2 + R * pi / 4, -R * 3 * pi / 4)) for p in lu ], linestyle='--', color=color) pn = array((-R * 3 * pi / 4, R * pi / 2)) ps = array((-R * 3 * pi / 4, -R * pi / 2)) g += point([pn + k * dl for k in range(4)] + [ps + k * dl for k in range(4)], size=20, color=color) g += point([pn + k * dl for k in range(1, 4)] + [ps + k * dl for k in range(1, 4)], color='white', size=10, zorder=3) npp = [(-R * pi, R * pi / 4), (-R * 3 * pi / 4, R * pi / 2), (-R * pi / 2, R * pi / 4)] spp = [(-R * pi, -R * pi / 4), (-R * 3 * pi / 4, -R * pi / 2), (-R * pi / 2, -R * pi / 4)] if shade_polar_region: for k in range(4): g += polygon([array(p) + k * dl for p in npp], alpha=0.1, color=shade_color) g += text(str(k), array((-R * 3 * pi / 4, R * 5 * pi / 16)) + k * dl, color='red', fontsize=20) g += polygon([array(p) + k * dl for p in spp], alpha=0.1, color=shade_color) g += text(str(k), array((-R * 3 * pi / 4, -R * 5 * pi / 16)) + k * dl, color='red', fontsize=20) return g