def test_m_to_ft(self): """Performs a data-driven test of the conversion.""" cases = [ # (m, ft_actual) ( 0, 0), ( 1, 3.28084), ( 1.5, 4.92126), (100, 328.084), ] # yapf: disable for (km, ft_actual) in cases: self.assertAlmostEqual(ft_actual, units.meters_to_feet(km), delta=5)
def distance_to_line(start, end, point, utm): """Compute the closest distance from point to a line segment. Based on the point-line distance derived in: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html (l_1 - p) dot (l_2 - p) t = - ----------------------- |l_2 - l_1|^2 We clamp t to 0 <= t <= 1 to ensure we calculate distance to a point on the line segment. The closest point can be determined using t: p_c = l_1 + t * (l_2 - l_1) And the distance is: d = |p - p_c| Arguments are points in the form (lat, lon, alt MSL (ft)). Args: start: Defines the start of the line. end: Defines the end of the line. point: Free point to compute distance from. utm: The UTM Proj projection to project into. If start, end, or point are well outside of this projection, this function returns infinite. Returns: Closest distance in ft from point to the line. """ try: # Convert points to UTM projection. # We need a cartesian coordinate system to perform the calculation. lat, lon, ftmsl = start x, y = pyproj.transform(wgs84, utm, lon, lat) l1 = np.array([x, y, units.feet_to_meters(ftmsl)]) lat, lon, ftmsl = end x, y = pyproj.transform(wgs84, utm, lon, lat) l2 = np.array([x, y, units.feet_to_meters(ftmsl)]) lat, lon, ftmsl = point x, y = pyproj.transform(wgs84, utm, lon, lat) p = np.array([x, y, units.feet_to_meters(ftmsl)]) except RuntimeError: # pyproj throws RuntimeError if the coordinates are grossly beyond the # bounds of the projection. We simplify this to "infinite" distance. return float("inf") d1 = l1 - p d2 = l2 - l1 num = np.dot(d1, d2) dem = np.linalg.norm(l2 - l1)**2 t = -num / dem if t < 0: t = 0 elif t > 1: t = 1 p_c = l1 + t * (l2 - l1) dist = np.linalg.norm(p - p_c) return units.meters_to_feet(dist)