Beispiel #1
0
def vincdir_utm(zone1,
                east1,
                north1,
                azimuth1to2,
                ell_dist,
                hemisphere1='south',
                ellipsoid=grs80):
    """
    Perform Vincentys Direct Computation using UTM Grid coordinates
    :param zone1: Point 1 Zone Number - 1 to 60
    :param east1: Point 1 Easting (m, within 3330km of Central Meridian)
    :param north1: Point 1 Northing (m, 0 to 10,000,000m)
    :param azimuth1to2: Azimuth from Point 1 to 2 (decimal degrees)
    :type azimuth1to2: float (decimal degrees), DMSAngle or DDMAngle
    :param ell_dist: Ellipsoidal Distance between Points 1 and 2 (metres)
    :param hemisphere1: Point 1 Hemisphere: String - 'North' or 'South'(default)
    :param ellipsoid: Ellipsoid Object (default: GRS80)
    :return: Hemisphere, zone, easting and northing of Point 2, Azimuth from
    Point 2 to 1 (decimal degrees)
    :rtype: tuple
    """

    # Convert angle to decimal degrees (if required)
    azimuth1to2 = angular_typecheck(azimuth1to2)

    # Convert utm to geographic
    pt1 = grid2geo(zone1, east1, north1, hemisphere1)
    # Use vincdir
    lat2, lon2, azimuth2to1 = vincdir(pt1[0], pt1[1], azimuth1to2, ell_dist,
                                      ellipsoid)
    # Convert geographic to utm
    hemisphere2, zone2, east2, north2, psf2, gc2 = geo2grid(lat2, lon2)
    return hemisphere2, zone2, east2, north2, azimuth2to1
Beispiel #2
0
def xyz2enu(lat, lon, x, y, z):
    """Convert a column vector in the Cartesian reference frame to a column
    vector in the local reference frame.
    :param lat: latitude in decimal degrees
    :param lon: longitude in decimal degrees
    :param x: in metres
    :param y: in metres
    :param z: in metres
    :return: east, north, up in metres
    """
    rot_matrix = rotation_matrix(angular_typecheck(lat), angular_typecheck(lon))
    xyz = np.array([[x], [y], [z]])
    enu = rot_matrix.transpose() @ xyz
    east = enu[0, 0]
    north = enu[1, 0]
    up = enu[2, 0]
    return east, north, up
Beispiel #3
0
def enu2xyz(lat, lon, east, north, up):
    """Convert a column vector in the local reference frame to a column vector
    in the Cartesian reference frame.
    :param lat: latitude in decimal degrees
    :param lon: longitude in decimal degrees
    :param east: in metres
    :param north: in metres
    :param up: in metres
    :return: x, y, z in metres
    """
    rot_matrix = rotation_matrix(angular_typecheck(lat), angular_typecheck(lon))
    enu = np.array([[east], [north], [up]])
    xyz = rot_matrix @ enu
    x = xyz[0, 0]
    y = xyz[1, 0]
    z = xyz[2, 0]
    return x, y, z
Beispiel #4
0
def vincdir_utm(zone1, east1, north1, grid1to2, grid_dist,
                hemisphere='south', ellipsoid=grs80):
    """
    Perform Vincenty's Direct Computation using UTM Grid Coordinates, a
    grid bearing and grid distance.
    Note: Point 2 UTM Coordinates use the Zone specified for Point 1, even if
    Point 2 would typically be computed in a different zone. This keeps the grid
    bearings and line scale factor all relative to the same UTM Zone.
    :param zone1: Point 1 Zone Number - 1 to 60
    :param east1: Point 1 Easting (m, within 3330km of Central Meridian)
    :param north1: Point 1 Northing (m, 0 to 10,000,000m)
    :param grid1to2: Grid Bearing from Point 1 to 2 (decimal degrees),
    :param grid_dist: UTM Grid Distance between Points 1 and 2 (m)
    :param hemisphere: String - 'North' or 'South'(default)
    :param ellipsoid: Ellipsoid Object (default: GRS80)
    :return: zone2: Point 2 Zone Number - 1 to 60
             east2: Point 2 Easting (m, within 3330km of Central Meridian)
             north2: Point 2 Northing (m, 0 to 10,000,000m)
             grid2to1: Grid Bearing from Point 2 to 1 (decimal degrees)
             lsf: Line Scale Factor (for Point 1 Zone)
    """
    # Convert angle to decimal degrees (if required)
    grid1to2 = angular_typecheck(grid1to2)

    # Convert UTM Coords to Geographic
    lat1, lon1, psf1, gridconv1 = grid2geo(zone1, east1, north1,
                                           hemisphere, ellipsoid)

    # Convert Grid Bearing to Geodetic Azimuth
    az1to2 = grid1to2 - gridconv1

    # Estimate Line Scale Factor (LSF)
    zone2, east2, north2 = (zone1, *radiations(east1, north1,
                                               grid1to2, grid_dist))
    lsf = line_sf(zone1, east1, north1, zone2, east2, north2)

    # Iteratively estimate Pt 2 Coordinates, refining LSF each time
    lsf_diff = 1
    max_iter = 10
    while lsf_diff > 1e-9:
        lsf_previous = lsf
        lat2, lon2, az2to1 = vincdir(lat1, lon1, az1to2,
                                     grid_dist / lsf, ellipsoid)
        (hemisphere2, zone2, east2,
         north2, psf2, gridconv2) = geo2grid(lat2, lon2,
                                             zone1, ellipsoid)
        lsf = line_sf(zone1, east1, north1,
                      zone2, east2, north2,
                      hemisphere, ellipsoid)
        lsf_diff = abs(lsf_previous - lsf)

    # Compute Grid Bearing for Station 2
    lat2, lon2, psf2, gridconv2 = grid2geo(zone2, east2, north2,
                                           hemisphere, ellipsoid)
    grid2to1 = az2to1 + gridconv2

    return zone2, east2, north2, grid2to1, lsf
Beispiel #5
0
def vincdir(lat1, lon1, azimuth1to2, ell_dist, ellipsoid=grs80):
    """
    Vincenty's Direct Formula
    :param lat1: Latitude of Point 1 (decimal degrees)
    :type lat1: float (decimal degrees), DMSAngle or DDMAngle
    :param lon1: Longitude of Point 1 (decimal degrees)
    :type lon1: float (decimal degrees), DMSAngle or DDMAngle
    :param azimuth1to2: Azimuth from Point 1 to 2 (decimal degrees)
    :type azimuth1to2: float (decimal degrees), DMSAngle or DDMAngle
    :param ell_dist: Ellipsoidal Distance between Points 1 and 2 (metres)
    :param ellipsoid: Ellipsoid Object
    :return: lat2: Latitude of Point 2 (Decimal Degrees),
             lon2: Longitude of Point 2 (Decimal Degrees),
             azimuth2to1: Azimuth from Point 2 to 1 (Decimal Degrees)

    Code review: 14-08-2018 Craig Harrison
    """

    # Convert Angles to Decimal Degrees (if required)
    lat1 = angular_typecheck(lat1)
    lon1 = angular_typecheck(lon1)
    azimuth1to2 = radians(angular_typecheck(azimuth1to2))

    # Equation numbering is from the GDA2020 Tech Manual v1.0

    # Eq. 88
    u1 = atan((1 - ellipsoid.f) * tan(radians(lat1)))

    # Eq. 89
    sigma1 = atan2(tan(u1), cos(azimuth1to2))

    # Eq. 90
    alpha = asin(cos(u1) * sin(azimuth1to2))

    # Eq. 91
    u_squared = cos(alpha)**2 \
        * (ellipsoid.semimaj**2 - ellipsoid.semimin**2) \
        / ellipsoid.semimin**2

    # Eq. 92
    a = 1 + (u_squared / 16384) \
        * (4096 + u_squared * (-768 + u_squared * (320 - 175 * u_squared)))

    # Eq. 93
    b = (u_squared / 1024) \
        * (256 + u_squared * (-128 + u_squared * (74 - 47 * u_squared)))

    # Eq. 94
    sigma = ell_dist / (ellipsoid.semimin * a)

    # Iterate until the change in sigma, delta_sigma, is insignificant (< 1e-9)
    # or after 1000 iterations have been completed
    two_sigma_m = 0
    for i in range(1000):

        # Eq. 95
        two_sigma_m = 2 * sigma1 + sigma

        # Eq. 96
        delta_sigma = b * sin(sigma) * (cos(two_sigma_m) + (b / 4) *
                                        (cos(sigma) *
                                         (-1 + 2 * cos(two_sigma_m)**2) -
                                         (b / 6) * cos(two_sigma_m) *
                                         (-3 + 4 * sin(sigma)**2) *
                                         (-3 + 4 * cos(two_sigma_m)**2)))
        new_sigma = (ell_dist / (ellipsoid.semimin * a)) + delta_sigma
        sigma_change = new_sigma - sigma
        sigma = new_sigma

        if abs(sigma_change) < 1e-12:
            break

    # Calculate the Latitude of Point 2
    # Eq. 98
    lat2 = atan2(
        sin(u1) * cos(sigma) + cos(u1) * sin(sigma) * cos(azimuth1to2),
        (1 - ellipsoid.f) * sqrt(
            sin(alpha)**2 + (sin(u1) * sin(sigma) -
                             cos(u1) * cos(sigma) * cos(azimuth1to2))**2))
    lat2 = degrees(lat2)

    # Calculate the Longitude of Point 2
    # Eq. 99
    lon = atan2(
        sin(sigma) * sin(azimuth1to2),
        cos(u1) * cos(sigma) - sin(u1) * sin(sigma) * cos(azimuth1to2))

    # Eq. 100
    c = (ellipsoid.f/16)*cos(alpha)**2 \
        * (4 + ellipsoid.f*(4 - 3*cos(alpha)**2))

    # Eq. 101
    omega = lon - (1-c)*ellipsoid.f*sin(alpha) \
        * (sigma + c*sin(sigma)*(cos(two_sigma_m) + c*cos(sigma)
                                 * (-1 + 2*cos(two_sigma_m)**2)))

    # Eq. 102
    lon2 = float(lon1) + degrees(omega)

    # Calculate the Reverse Azimuth
    azimuth2to1 = degrees(
        atan2(sin(alpha), -sin(u1) * sin(sigma) +
              cos(u1) * cos(sigma) * cos(azimuth1to2))) + 180

    return round(lat2, 11), round(lon2, 11), round(azimuth2to1, 9)
Beispiel #6
0
def vincinv(lat1, lon1, lat2, lon2, ellipsoid=grs80):
    """
    Vincenty's Inverse Formula
    :param lat1: Latitude of Point 1 (decimal degrees)
    :type lat1: float (decimal degrees), DMSAngle or DDMAngle
    :param lon1: Longitude of Point 1 (decimal degrees)
    :type lon1: float (decimal degrees), DMSAngle or DDMAngle
    :param lat2: Latitude of Point 2 (decimal degrees)
    :type lat2: float (decimal degrees), DMSAngle or DDMAngle
    :param lon2: Longitude of Point 2 (decimal degrees)
    :type lon2: float (decimal degrees), DMSAngle or DDMAngle
    :param ellipsoid: Ellipsoid Object
    :return: ell_dist: Ellipsoidal Distance between Points 1 and 2 (m),
             azimuth1to2: Azimuth from Point 1 to 2 (Decimal Degrees),
             azimuth2to1: Azimuth from Point 2 to 1 (Decimal Degrees)
    Code review: 14-08-2018 Craig Harrison
    """

    # Convert Angles to Decimal Degrees (if required)
    lat1 = angular_typecheck(lat1)
    lon1 = angular_typecheck(lon1)
    lat2 = angular_typecheck(lat2)
    lon2 = angular_typecheck(lon2)

    # Exit if the two input points are the same
    if lat1 == lat2 and lon1 == lon2:
        return 0, 0, 0

    # Equation numbering is from the GDA2020 Tech Manual v1.0

    # Eq. 71
    u1 = atan((1 - ellipsoid.f) * tan(radians(lat1)))

    # Eq. 72
    u2 = atan((1 - ellipsoid.f) * tan(radians(lat2)))

    # Eq. 73; initial approximation
    lon = radians(lon2 - lon1)
    omega = lon

    # Iterate until the change in lambda, lambda_sigma, is insignificant
    # (< 1e-12) or after 1000 iterations have been completed
    alpha = 0
    sigma = 0
    cos_two_sigma_m = 0
    for i in range(1000):

        # Eq. 74
        sin_sigma = sqrt((cos(u2) * sin(lon))**2 +
                         (cos(u1) * sin(u2) - sin(u1) * cos(u2) * cos(lon))**2)

        # Eq. 75
        cos_sigma = sin(u1) * sin(u2) + cos(u1) * cos(u2) * cos(lon)

        # Eq. 76
        sigma = atan2(sin_sigma, cos_sigma)

        # Eq. 77
        alpha = asin((cos(u1) * cos(u2) * sin(lon)) / sin_sigma)

        # Eq. 78
        cos_two_sigma_m = cos(sigma) - (2 * sin(u1) * sin(u2) / cos(alpha)**2)

        # Eq. 79
        c = (ellipsoid.f / 16) * cos(alpha)**2 * (4 + ellipsoid.f *
                                                  (4 - 3 * cos(alpha)**2))

        # Eq. 80
        new_lon = omega + (1 - c) * ellipsoid.f * sin(alpha) * (
            sigma + c * sin(sigma) * (cos_two_sigma_m + c * cos(sigma) *
                                      (-1 + 2 * (cos_two_sigma_m**2))))

        delta_lon = new_lon - lon
        lon = new_lon

        if abs(delta_lon) < 1e-12:
            break

    # Eq. 81
    u_squared = cos(alpha)**2 \
        * (ellipsoid.semimaj**2 - ellipsoid.semimin**2) \
        / ellipsoid.semimin**2

    # Eq. 82
    a = 1 + (u_squared / 16384) \
        * (4096 + u_squared * (-768 + u_squared * (320 - 175 * u_squared)))

    # Eq. 83
    b = (u_squared / 1024) \
        * (256 + u_squared * (-128 + u_squared * (74 - 47 * u_squared)))

    # Eq. 84
    delta_sigma = b * sin(sigma) * (cos_two_sigma_m + (b / 4) *
                                    (cos(sigma) *
                                     (-1 + 2 * cos_two_sigma_m**2) -
                                     (b / 6) * cos_two_sigma_m *
                                     (-3 + 4 * sin(sigma)**2) *
                                     (-3 + 4 * cos_two_sigma_m**2)))

    # Calculate the ellipsoidal distance
    # Eq. 85
    ell_dist = ellipsoid.semimin * a * (sigma - delta_sigma)

    # Calculate the azimuth from point 1 to point 2
    azimuth1to2 = degrees(
        atan2((cos(u2) * sin(lon)),
              (cos(u1) * sin(u2) - sin(u1) * cos(u2) * cos(lon))))

    if azimuth1to2 < 0:
        azimuth1to2 = azimuth1to2 + 360

    # Calculate the azimuth from point 2 to point 1
    azimuth2to1 = degrees(
        atan2(
            cos(u1) * sin(lon),
            (-sin(u1) * cos(u2) + cos(u1) * sin(u2) * cos(lon)))) + 180

    # Meridian Critical Case Tests
    #if lon1 == lon2 and lat1 > lat2:
    #    azimuth1to2 = 180
    #    azimuth2to1 = 0
    #elif lon1 == lon2 and lat1 < lat2:
    #    azimuth1to2 = 0
    #    azimuth2to1 = 180

    return round(ell_dist, 3), round(azimuth1to2, 9), round(azimuth2to1, 9)