def llh2xyz(lat, lon, ellht=0, ellipsoid=grs80): """ Converts Geographic Latitude, Longitude and Ellipsoid Height to Cartesian X, Y and Z Coordinates. Default Ellipsoid parameters used are GRS80. :param lat: Geographic Latitude :type lat: Float (Decimal Degrees), DMSAngle or DDMAngle :param lon: Geographic Longitude :type lon: Float (Decimal Degrees), DMSAngle or DDMAngle :param ellht: Ellipsoid Height (metres, default is 0m) :param ellipsoid: Ellipsoid Object :type ellipsoid: Ellipsoid :return: Cartesian X, Y, Z Coordinate in metres :rtype: tuple """ # Convert lat & long to radians lat = radians(angular_typecheck(lat)) lon = radians(angular_typecheck(lon)) # Calculate Ellipsoid Radius of Curvature in the Prime Vertical - nu if lat == 0: nu = grs80.semimaj else: nu = ellipsoid.semimaj / (sqrt(1 - ellipsoid.ecc1sq * (sin(lat)**2))) # Calculate x, y, z x = (nu + ellht) * cos(lat) * cos(lon) y = (nu + ellht) * cos(lat) * sin(lon) z = ((ellipsoid.semimin**2 / ellipsoid.semimaj**2) * nu + ellht) * sin(lat) return x, y, z
def test_angular_typecheck(self): class_exs = [deca_exs, hpa_exs, gona_exs, dms_exs, ddm_exs] for class_ex in class_exs: for num, ex in enumerate(class_ex): self.assertAlmostEqual(angular_typecheck(ex), dec_exs[num], 13) self.assertAlmostEqual(angular_typecheck(-ex), -dec_exs[num], 13) for ex in dec_exs: self.assertEqual(angular_typecheck(ex), ex) self.assertEqual(angular_typecheck(-ex), -ex)
def psfandgridconv(xi1, eta1, lat, lon, cm, conf_lat, ellipsoid=grs80, prj=utm): """ Calculates Point Scale Factor and Grid Convergence. Used in convert.geo2grid and convert.grid2geo :param xi1: Transverse Mercator Ratio Xi :param eta1: Transverse Mercator Ratio Eta :param lat: Latitude :type lat: Decimal Degrees, DMSAngle or DDMAngle :param lon: Longitude :type lon: Decimal Degrees, DMSAngle or DDMAngle :param cm: Central Meridian :param conf_lat: Conformal Latitude :param ellipsoid: Ellipsoid Object (default: GRS80) :return: Point Scale Factor, Grid Convergence (Decimal Degrees) :rtype: tuple """ lat = angular_typecheck(lat) lon = angular_typecheck(lon) A = rect_radius(ellipsoid) a = alpha_coeff(ellipsoid) lat = radians(lat) long_diff = radians(lon - cm) # Point Scale Factor p = 1 q = 0 for r in range(1, 9): p += 2 * r * a[r - 1] * cos(2 * r * xi1) * cosh(2 * r * eta1) q += 2 * r * a[r - 1] * sin(2 * r * xi1) * sinh(2 * r * eta1) q = -q psf = (float(prj.cmscale) * (A / ellipsoid.semimaj) * sqrt(q**2 + p**2) * ((sqrt(1 + (tan(lat)**2)) * sqrt(1 - ellipsoid.ecc1sq * (sin(lat)**2))) / sqrt((tan(conf_lat)**2) + (cos(long_diff)**2)))) # Grid Convergence grid_conv = degrees( atan(abs(q / p)) + atan(abs(tan(conf_lat) * tan(long_diff)) / sqrt(1 + tan(conf_lat)**2))) if cm > lon and lat < 0: grid_conv = -grid_conv elif cm < lon and lat > 0: grid_conv = -grid_conv return psf, grid_conv
def polar2rect(r, theta): """ Converts point in polar coordinates to corresponding rectangular coordinates Theta is degrees and is measured clockwise from the positive y axis (i.e. north) :param r: Radius :param theta: Angle (decimal degrees) :type theta: Float (decimal degrees), DMSAngle or DDMAngle :return: Rectangular Coordinates X, Y """ theta = angular_typecheck(theta) x = r * sin(radians(theta)) y = r * cos(radians(theta)) return x, y
def geo2grid(lat, lon, zone=0, ellipsoid=grs80): """ Takes a geographic co-ordinate (latitude, longitude) and returns its corresponding Hemisphere, Zone and Projection Easting and Northing, Point Scale Factor and Grid Convergence. Default Projection is Universal Transverse Mercator Projection using GRS80 Ellipsoid parameters. :param lat: Latitude :type lat: Float (Decimal Degrees), DMSAngle or DDMAngle :param lon: Longitude :type lon: Float (Decimal Degrees, DMSAngle or DDMAngle :param zone: Optional Zone Number - Only required if calculating grid co-ordinate outside zone boundaries :param ellipsoid: Ellipsoid Object :type ellipsoid: Ellipsoid :return: hemisphere, zone, east (m), north (m), Point Scale Factor, Grid Convergence (Decimal Degrees) :rtype: tuple """ # Convert DMSAngle and DDMAngle to Decimal Angle lat = angular_typecheck(lat) lon = angular_typecheck(lon) # Input Validation - UTM Extents and Values zone = int(zone) if zone < 0 or zone > 60: raise ValueError('Invalid Zone - Zones from 1 to 60') if lat < -80 or lat > 84: raise ValueError('Invalid Latitude - Latitudes from -80 to +84') if lon < -180 or lon > 180: raise ValueError('Invalid Longitude - Longitudes from -180 to +180') A = rect_radius(ellipsoid) a = alpha_coeff(ellipsoid) lat = radians(lat) # Calculate Zone if zone == 0: zone = int((float(lon) - (proj.initialcm - (1.5 * proj.zonewidth))) / proj.zonewidth) cm = float(zone * proj.zonewidth) + (proj.initialcm - proj.zonewidth) # Conformal Latitude sigx = (ellipsoid.ecc1 * tan(lat)) / sqrt(1 + (tan(lat)**2)) sig = sinh(ellipsoid.ecc1 * (0.5 * log((1 + sigx) / (1 - sigx)))) conf_lat = tan(lat) * sqrt(1 + sig**2) - sig * sqrt(1 + (tan(lat)**2)) conf_lat = atan(conf_lat) # Longitude Difference long_diff = radians(lon - cm) # Gauss-Schreiber Ratios xi1 = atan(tan(conf_lat) / cos(long_diff)) eta1x = sin(long_diff) / (sqrt(tan(conf_lat)**2 + cos(long_diff)**2)) eta1 = log(eta1x + sqrt(1 + eta1x**2)) # Transverse Mercator Ratios eta = eta1 xi = xi1 for r in range(1, 9): eta += a[r - 1] * cos(2 * r * xi1) * sinh(2 * r * eta1) xi += a[r - 1] * sin(2 * r * xi1) * cosh(2 * r * eta1) # Transverse Mercator Co-ordinates x = A * eta y = A * xi # Hemisphere-dependent UTM Projection Co-ordinates east = proj.cmscale * x + proj.falseeast if y < 0: hemisphere = 'South' north = proj.cmscale * y + proj.falsenorth else: hemisphere = 'North' falsenorth = 0 north = proj.cmscale * y + falsenorth # Point Scale Factor and Grid Convergence psf, grid_conv = psfandgridconv(xi1, eta1, degrees(lat), lon, cm, conf_lat) return (hemisphere, zone, round(float(east), 4), round(float(north), 4), round(psf, 8), grid_conv)