def gdlComp(self, lons_lats, km_pts=20): """ Compute geodesic line lons_lats: input coordinates. (start longitude, start latitude, end longitude, end latitude) km_pts: compute one point each 20 km (default). """ try: lon_1, lat_1, lon_2, lat_2 = lons_lats pygd = Geod(ellps='WGS84') res = pygd.inv(lon_1, lat_1, lon_2, lat_2) dist = res[2] pts = int(math.ceil(dist) / (km_pts * 1000)) coords = pygd.npts(lon_1, lat_1, lon_2, lat_2, pts) coords_se = [(lon_1, lat_1)] + coords coords_se.append((lon_2, lat_2)) self.__logger.info("Geodesic line succesfully created!") self.__logger.info("Total points = {:,}".format(pts)) self.__logger.info("{:,.4f} km".format(dist / 1000.)) return coords_se except Exception as e: self.__logger.error("Error: {0}".format(e.message))
def caculate_line(self, startx, starty, endx, endy): geod = Geod(ellps="WGS84") forwardAngle, backwardAngle, distance = geod.inv( startx, starty, endx, endy) stationCount = math.floor(distance / self.courseline) wished_startx, wished_starty, tempAngle = geod.fwd( startx, starty, backwardAngle, self.courseline * self.courseExpand) print("wished start x,y:", wished_startx, wished_starty) wishedDistance = self.courseline * (stationCount + self.courseExpand * 2) wished_endx, wished_endy, tempAngle = geod.fwd( wished_startx, wished_starty, forwardAngle, wishedDistance) print("wished end x,y:", wished_endx, wished_endy) points = geod.npts(wished_startx, wished_starty, wished_endx, wished_endy, stationCount + self.courseExpand * 2) results = [] results.append((wished_startx, wished_starty)) results.extend(points) results.append((wished_endx, wished_endy)) self.courseAngle = forwardAngle print(results) return results, forwardAngle
def calc_geod_pts(point1, point2, num_pts): """ Calculates a number of points, num_pts, along a line defined by point1 & point2 Parameters ---------- point1 : tuple of floats First geographic coordinate pair Format: (lat, lon) point2 : tuple of floats Second geographic coordinate pair Format: (lat, lon) num_pts : int Number of coordinate pairs to calculate Returns ------- Yields a tuple of floats Format: (lon, lat) """ geod = Geod("+ellps=WGS84") points = geod.npts(lon1=point1[1], lat1=point1[0], lon2=point2[1], lat2=point2[0], npts=num_pts) for pt in points: yield pt
def build_great_circle(self, start_latlng, end_latlng, distance): num_points = int(distance / self.ARC_LENGTH_SPACING) geod = Geod(ellps='WGS84') start_lat, start_lon = start_latlng end_lat, end_lon = end_latlng lonlats = geod.npts(start_lon, start_lat, end_lon, end_lat, num_points) latlngs = util.swap_pairs(lonlats) return latlngs
def greatcircle( lat1: float, lon1: float, lat2: float, lon2: float, *args, **kwargs ) -> List[Tuple[float, float]]: geod = Geod(ellps="WGS84") return [ (lat, lon) for (lon, lat) in geod.npts(lon1, lat1, lon2, lat2, *args, **kwargs) ]
def vertical_cross(in_field, lon, lat, line_points, npts=100): """ Interpolate 2D or multiple dimensional grid data to vertical cross section. :param in_field: 2D or multiple dimensional grid data, the rightest dimension [..., lat, lon]. :param lon: grid data longitude. :param lat: grid data latitude. :param line_points: cross section line points, should be [n_points, 2] array. :param npts: the point number of great circle line. :return: cross section [..., n_points], points """ if np.ndim(in_field) < 2: raise ValueError("in_field must be at least 2 dimension") # reshape field to 3d array old_shape = in_field.shape if np.ndim(in_field) == 2: field = in_field.reshape(1, *old_shape) else: field = in_field.reshape(np.product(old_shape[0:-2]), *old_shape[-2:]) # get great circle points points = None n_line_points = line_points.shape[0] geod = Geod("+ellps=WGS84") for i in range(n_line_points - 1): seg_points = geod.npts(lon1=line_points[i, 0], lat1=line_points[i, 1], lon2=line_points[i + 1, 0], lat2=line_points[i + 1, 1], npts=npts) if points is None: points = np.array(seg_points) else: points = np.vstack((points, np.array(seg_points))) # convert to pixel coordinates x = np.interp(points[:, 0], lon, np.arange(len(lon))) y = np.interp(points[:, 1], lat, np.arange(len(lat))) # loop every level zdata = [] for i in range(field.shape[0]): zdata.append( ndimage.map_coordinates(np.transpose(field[i, :, :]), np.vstack((x, y)))) # reshape zdata zdata = np.array(zdata) if np.ndim(in_field) > 2: zdata = zdata.reshape(np.append(old_shape[0:-2], points.shape[0])) # return vertical cross section return zdata, points
def test_geod_inverse_transform(): gg = Geod(ellps="clrk66") lat1pt = 42.0 + (15.0 / 60.0) lon1pt = -71.0 - (7.0 / 60.0) lat2pt = 45.0 + (31.0 / 60.0) lon2pt = -123.0 - (41.0 / 60.0) """ distance between boston and portland, clrk66: -66.531 75.654 4164192.708 distance between boston and portland, WGS84: -66.530 75.654 4164074.239 testing pickling of Geod instance distance between boston and portland, clrk66 (from pickle): -66.531 75.654 4164192.708 distance between boston and portland, WGS84 (from pickle): -66.530 75.654 4164074.239 inverse transform from proj.4 invgeod: b'-66.531\t75.654\t4164192.708\n' """ print("from pyproj.Geod.inv:") az12, az21, dist = gg.inv(lon1pt, lat1pt, lon2pt, lat2pt) assert_almost_equal((az12, az21, dist), (-66.531, 75.654, 4164192.708), decimal=3) print("forward transform") print("from proj.4 geod:") endlon, endlat, backaz = gg.fwd(lon1pt, lat1pt, az12, dist) assert_almost_equal((endlon, endlat, backaz), (-123.683, 45.517, 75.654), decimal=3) print("intermediate points:") print("from geod with +lat_1,+lon_1,+lat_2,+lon_2,+n_S:") npts = 4 lonlats = gg.npts(lon1pt, lat1pt, lon2pt, lat2pt, npts) lonprev = lon1pt latprev = lat1pt print(dist / (npts + 1)) print("%6.3f %7.3f" % (lat1pt, lon1pt)) result_dists = ( (-66.53059478766238, 106.79071710136431, 832838.5416198927), (-73.20928289863558, 99.32289055927389, 832838.5416198935), (-80.67710944072617, 91.36325611787134, 832838.5416198947), (-88.63674388212858, 83.32809401477382, 832838.5416198922), ) for (lon, lat), (res12, res21, resdist) in zip(lonlats, result_dists): az12, az21, dist = gg.inv(lonprev, latprev, lon, lat) assert_almost_equal((az12, az21, dist), (res12, res21, resdist)) latprev = lat lonprev = lon az12, az21, dist = gg.inv(lonprev, latprev, lon2pt, lat2pt) assert_almost_equal((lat2pt, lon2pt, dist), (45.517, -123.683, 832838.542), decimal=3)
def test_geod_inverse_transform(): gg = Geod(ellps="clrk66") lat1pt = 42.0 + (15.0 / 60.0) lon1pt = -71.0 - (7.0 / 60.0) lat2pt = 45.0 + (31.0 / 60.0) lon2pt = -123.0 - (41.0 / 60.0) """ distance between boston and portland, clrk66: -66.531 75.654 4164192.708 distance between boston and portland, WGS84: -66.530 75.654 4164074.239 testing pickling of Geod instance distance between boston and portland, clrk66 (from pickle): -66.531 75.654 4164192.708 distance between boston and portland, WGS84 (from pickle): -66.530 75.654 4164074.239 inverse transform from proj.4 invgeod: b'-66.531\t75.654\t4164192.708\n' """ print("from pyproj.Geod.inv:") az12, az21, dist = gg.inv(lon1pt, lat1pt, lon2pt, lat2pt) assert_almost_equal((az12, az21, dist), (-66.531, 75.654, 4164192.708), decimal=3) print("forward transform") print("from proj.4 geod:") endlon, endlat, backaz = gg.fwd(lon1pt, lat1pt, az12, dist) assert_almost_equal((endlon, endlat, backaz), (-123.683, 45.517, 75.654), decimal=3) print("intermediate points:") print("from geod with +lat_1,+lon_1,+lat_2,+lon_2,+n_S:") npts = 4 lonlats = gg.npts(lon1pt, lat1pt, lon2pt, lat2pt, npts) lonprev = lon1pt latprev = lat1pt print(dist / (npts + 1)) print("%6.3f %7.3f" % (lat1pt, lon1pt)) result_dists = ( (-66.53059478766238, 106.79071710136431, 832838.5416198927), (-73.20928289863558, 99.32289055927389, 832838.5416198935), (-80.67710944072617, 91.36325611787134, 832838.5416198947), (-88.63674388212858, 83.32809401477382, 832838.5416198922), ) for (lon, lat), (res12, res21, resdist) in zip(lonlats, result_dists): az12, az21, dist = gg.inv(lonprev, latprev, lon, lat) assert_almost_equal((az12, az21, dist), (res12, res21, resdist)) latprev = lat lonprev = lon az12, az21, dist = gg.inv(lonprev, latprev, lon2pt, lat2pt) assert_almost_equal( (lat2pt, lon2pt, dist), (45.517, -123.683, 832838.542), decimal=3 )
def get_line(start, end): x1 = start[Location.X.value] y1 = start[Location.Y.value] x2 = end[Location.X.value] y2 = end[Location.Y.value] geod = Geod("+ellps=WGS84") points = geod.npts(x1, y1, x2, y2, npts=100) return points
class GeodeticPath: """Calculate the geodetic path between two points using pyproj Geod""" def __init__(self, lon0, lat0, lon1, lat1, ellps='WGS84', radians=False): """Initialize with the start and stop points.""" self.geod = Geod(ellps=ellps) self.lon0 = lon0 self.lat0 = lat0 self.lon1 = lon1 self.lat1 = lat1 # Get the forward and backward azimuths and distance between the two points self.azimuth0, self.back_azimuth1, self.distance = self.geod.inv( lon0, lat0, lon1, lat1) def get_path_lonlats(self, separation): """Get the latitude and longitude of the path points, given a point separation in meters.""" self.npts = int(self.distance / separation + 0.5) self.lonlats = np.array( self.geod.npts(self.lon0, self.lat0, self.lon1, self.lat1, self.npts)) self.lon = self.lonlats[:, 0] self.lat = self.lonlats[:, 1] def get_path(self, separation=None): """Get the path latitude, longitude, heading, and distance. If separation is None, assume get_path_lon_lats has already been called.""" if separation != None: self.get_path_lonlats(separation) # Declare heading and distance arrays self.heading = np.zeros(len(self.lat), dtype=self.lat.dtype) self.along_track_distance = np.zeros(len(self.lat), dtype=self.lat.dtype) for i in range(len(self.lat) - 1): self.heading[i], back_azimuth, d = self.geod.inv( self.lon[i], self.lat[i], self.lon[i + 1], self.lat[i + 1]) self.along_track_distance[i + 1] = self.along_track_distance[i] + d if back_azimuth < 0: self.heading[-1] = 180 + back_azimuth else: self.heading[-1] = back_azimuth - 180.
def midpoint_utm(self,p1,p2): """ calculates midpoint between 2 points on earths surface input: p1,p2 location in the form (lon,lat) return: m midpoint in the form (lon,lat) """ g = Geod(ellps='WGS84') l = g.npts(p1[0],p1[0],p1[1],p1[1],1) m = l[0] # print 'm: ', m return m
def midpoint_utm(self, p1, p2): """ calculates midpoint between 2 points on earths surface input: p1,p2 location in the form (lon,lat) return: m midpoint in the form (lon,lat) """ g = Geod(ellps='WGS84') l = g.npts(p1[0], p1[0], p1[1], p1[1], 1) m = l[0] # print 'm: ', m return m
def geodesic(crs, start, end, steps): r"""Construct a geodesic path between two points. This function acts as a wrapper for the geodesic construction available in `pyproj`. Parameters ---------- crs: `cartopy.crs` Cartopy Coordinate Reference System to use for the output start: (2, ) array_like A latitude-longitude pair designating the start point of the geodesic (units are degrees north and degrees east). end: (2, ) array_like A latitude-longitude pair designating the end point of the geodesic (units are degrees north and degrees east). steps: int, optional The number of points along the geodesic between the start and the end point (including the end points). Returns ------- `numpy.ndarray` The list of x, y points in the given CRS of length `steps` along the geodesic. See Also -------- cross_section """ import cartopy.crs as ccrs from pyproj import Geod # Geod.npts only gives points *in between* the start and end, and we want to include # the endpoints. g = Geod(crs.proj4_init) geodesic = np.concatenate([ np.array(start[::-1])[None], np.array(g.npts(start[1], start[0], end[1], end[0], steps - 2)), np.array(end[::-1])[None] ]).transpose() points = crs.transform_points(ccrs.Geodetic(), *geodesic)[:, :2] return points
def test_integrate(lat1, lon1, lat2, lon2): g = Geod(ellps='sphere') distance1 = g.inv(lon1, lat1, lon2, lat2)[2] / 1000.0 points = g.npts(lon1, lat1, lon2, lat2, int(distance1) // 1) distance2 = 0 distance3 = 0 res = 0 for i in range(len(points) - 1): lo1, la1, lo2, la2 = points[i] + points[i + 1] p1 = sphere2cartesian(90 - la1, 180 - lo1) * 6371 p2 = sphere2cartesian(90 - la2, 180 - lo2) * 6371 distance2 += np.linalg.norm(p1 - p2) az, baz, d = g.inv(lo1, la1, lo2, la2) distance3 += d res += abs(abs(az - baz) - 180) distance3 /= 1000.0 res /= len(points) print(distance1, distance2, distance3) print(res)
def ctr_generator(lons, lats, outfname, d = 10.): if lons.size != lats.size: raise ValueError('Size of longitude and latitude list must be the same') g = Geod(ellps='WGS84') N = lons.size lonlats = [] for i in range(N): lon1 = lons[i] lat1 = lats[i] if i < N-1: lon2 = lons[i+1] lat2 = lats[i+1] else: lon2 = lons[0] lat2 = lats[0] az, baz, dist = g.inv(lon1, lat1, lon2, lat2) dist = dist/1000. if d < dist: d = dist/float(int(dist/d)) Nd = int(dist/d) lonlats += [(lon1, lat1)] lonlats += g.npts(lon1, lat1, lon2, lat2, npts=Nd-1) else: lonlats += [(lon1, lat1)] with open(outfname, 'w') as fid: npts = len(lonlats) fid.writelines('0. 0. \n') fid.writelines('%g \n' %npts) for lonlat in lonlats: if lonlat[0] < 0.: outlon = lonlat[0]+360. else: outlon = lonlat[0] outlat = lonlat[1] fid.writelines('%g %g\n' %(outlon, outlat)) fid.writelines('%g \n' %npts) for i in range(npts): if i < npts-1: fid.writelines('%g %g\n' %(i+1, i+2)) else: fid.writelines('%g %g\n' %(i+1, 1))
def gdlComp(self, lons_lats, km_pts=20): """ Compute geodesic line lons_lats: input coordinates. (start longitude, start latitude, end longitude, end latitude) km_pts: compute one point each 20 km (default). """ try: lon_1, lat_1, lon_2, lat_2 = lons_lats pygd = Geod(ellps='WGS84') res = pygd.inv(lon_1, lat_1, lon_2, lat_2) dist = res[2] pts = int(math.ceil(dist) / (km_pts * 1000)) coords = pygd.npts(lon_1, lat_1, lon_2, lat_2, pts) coords_se = [(lon_1, lat_1)] + coords coords_se.append((lon_2, lat_2)) self.__distances.append({ "id": len(self.__distances), "distance": dist, "coords": lons_lats }) self.__logger.info("Geodesic line succesfully created!") self.__logger.info("Total points = {:,}".format(pts)) self.__logger.info("{:,.4f} km".format(dist / 1000.)) return coords_se except Exception as e: self.__logger.error("Error: {0}".format(e)) raise ComputeGeodesicLineError(e)
def get_gc_path(lon1,lat1,lon2,lat2,res): """Calculate great circle paths for all station pairs Parameter: lon1, lat1 -- longitude and latitude for the starting point lon2, lat2 -- longitude and latitude for the ending point res -- resolution in km Return: gc_path -- list containing longitudes and latitudes of points along the great circle dist -- distance between the starting and ending points along the great circle """ g = Geod(ellps='WGS84') (az,baz,dist) = g.inv(lon1,lat1,lon2,lat2) dist /= 1000. # convert to km gc_path = g.npts(lon1,lat1,lon2,lat2,1+int(dist/res)) gc_path.insert(0,(lon1,lat1)) gc_path.append((lon2,lat2)) gc_path_out = [] for i in range(len(gc_path)): lon_out = gc_path[i][0] if lon_out < 0.: lon_out += 360. gc_path_out.append((lon_out, gc_path[i][1])) return gc_path_out,dist
def split_at_idl(self): """ use when a line crosses the international dateline -> divides the line into two segments that meet at -180/180 degrees longitude """ # discretize line along ellipsoid and find where it gets closest to idl g = Geod(ellps='sphere') lonlats = g.npts(self.plo[0], self.pla[0], self.plo[1], self.pla[1], 10000) modlons = numpy.array(lonlats) mdlo1 = abs(modlons[:, 0] - 180.) indlo1 = numpy.argmin(mdlo1) # create two lines/subsegments of original line that meet idl linplo1 = [-180., self.plo[0]] linpla1 = [lonlats[indlo1][1], self.pla[0]] linplo2 = [self.plo[1], 180] linpla2 = [self.pla[1], lonlats[indlo1][1]] line1 = Line([Point(lo, la) for lo, la in zip(linplo1, linpla1)]) line2 = Line([Point(lo, la) for lo, la in zip(linplo2, linpla2)]) return line1, line2, lonlats[indlo1][1]
def parse_request(): wktP1 = request.args.get('param1') wktP2 = request.args.get('param2') pointNum = request.args.get('param3') point1 = ogr.CreateGeometryFromWkt(wktP1) point2 = ogr.CreateGeometryFromWkt(wktP2) # print ("%d,%d" % (point1.GetX(), point1.GetY())) geoid = Geod(ellps="WGS84") extra_points = geoid.npts(point1.GetY(), point1.GetX(), point2.GetY(), point2.GetX(), int(pointNum)) list_of_lists = [list(elem) for elem in extra_points] # К extra_points надо добавить первую и последнюю точки, а то их там нет list_of_lists.insert(0, [point1.GetY(), point1.GetX()]); list_of_lists.append([point2.GetY(), point2.GetX()]); print (list_of_lists) for i in list_of_lists: f = i[0]; i[0] = i[1]; i[1] = f; print(i) return str(list_of_lists)
def syn_ray(ray, model): """ compute travel time along given ray :param ray: (lat1, lon1, lat2, lon2) :param model: function(lat, lon), return model :return: travel time, velocity """ g = Geod(ellps='sphere') distance = g.inv(ray[1], ray[0], ray[3], ray[2])[2] / 1000.0 points = g.npts(ray[1], ray[0], ray[3], ray[2], int(distance) // 1) time = 0 for i in range(len(points) - 1): lo1, la1, lo2, la2 = points[i] + points[i + 1] az, baz, d = g.inv(lo1, la1, lo2, la2) d /= 1000.0 if az < 0: az += 180 phi = az * pi / 180 m = model(la1, lo1) c = m[0] c += m[1] * cos(2*phi) + m[2] * sin(2*phi) +\ m[3] * cos(4*phi) + m[4] * sin(4*phi) time += d / c return time, distance / time
def greatcircle(lat1, lon1, lat2, lon2, *args, **kwargs): geod = Geod(ellps="WGS84") return geod.npts(lon1, lat1, lon2, lat2, *args, **kwargs)
) origLng, origLat = -transform(inProj, outProj, -180, 0)[0], -transform( inProj, outProj, 0, 90)[1] cc = 0 for i in liens: tmp = Image.new('RGBA', im.size, (0, 0, 0, 0)) cc += 1 g = Geod(ellps='WGS84') startlong, startlat, endlong, endlat = -73.5673, 45.5017, i[ 2], i[1] (az12, az21, dist) = g.inv(startlong, startlat, endlong, endlat) lonlats = g.npts(startlong, startlat, endlong, endlat, 1 + int(dist / 50000)) lonlats.insert(0, (startlong, startlat)) lonlats.append((endlong, endlat)) c = 0 for ll in lonlats: if c > 0: x, y = transform(inProj, outProj, ll[0], ll[1]) x0C = int((x0 + origLng) * (w / (2 * origLng))) y0C = int((y0 + origLat) * (h / (2 * origLat))) xC = int((x + origLng) * (w / (2 * origLng))) yC = int((y + origLat) * (h / (2 * origLat))) if abs(x0C - xC) < 1633: # draw = ImageDraw.Draw(img, 'RGBA')
az12,az21,dist = g.inv(lon1pt,lat1pt,lon2pt,lat2pt) print "%7.3f %6.3f %12.3f" % (az12,az21,dist) print 'forward transform' print 'from proj.4 geod:' print commands.getoutput('echo "42d15\'N 71d07\'W -66d31\'50.141 4164192.708" | geod +ellps=clrk66 -f "%.3f"') endlon,endlat,backaz = g.fwd(lon1pt,lat1pt,az12,dist) print 'from pyproj.Geod.fwd:' print "%6.3f %6.3f %13.3f" % (endlat,endlon,backaz) print 'intermediate points:' print 'from geod with +lat_1,+lon_1,+lat_2,+lon_2,+n_S:' points = '+lon_1=%s +lat_1=%s +lon_2=%s +lat_2=%s' % (lon1pt,lat1pt,lon2pt,lat2pt,) print points print commands.getoutput('geod +ellps=clrk66 -f "%.3f" +n_S=5 '+points) print 'from pyproj.Geod.npts:' npts = 4 lonlats = g.npts(lon1pt,lat1pt,lon2pt,lat2pt,npts) lonprev = lon1pt latprev = lat1pt print dist/(npts+1) print '%6.3f %7.3f' % (lat1pt, lon1pt) for lon, lat in lonlats: az12,az21,dist = g.inv(lonprev,latprev,lon,lat) print '%6.3f %7.3f %11.3f' % (lat, lon, dist) latprev = lat; lonprev = lon az12,az21,dist = g.inv(lonprev,latprev,lon2pt,lat2pt) print '%6.3f %7.3f %11.3f' % (lat2pt, lon2pt, dist) # specify the lat/lons of some cities. boston_lat = 42.+(15./60.); boston_lon = -71.-(7./60.) portland_lat = 45.+(31./60.); portland_lon = -123.-(41./60.) newyork_lat = 40.+(47./60.); newyork_lon = -73.-(58./60.)
def test_geod_inverse_transform(): gg = Geod(ellps="clrk66") lat1pt = 42.0 + (15.0 / 60.0) lon1pt = -71.0 - (7.0 / 60.0) lat2pt = 45.0 + (31.0 / 60.0) lon2pt = -123.0 - (41.0 / 60.0) """ distance between boston and portland, clrk66: -66.531 75.654 4164192.708 distance between boston and portland, WGS84: -66.530 75.654 4164074.239 testing pickling of Geod instance distance between boston and portland, clrk66 (from pickle): -66.531 75.654 4164192.708 distance between boston and portland, WGS84 (from pickle): -66.530 75.654 4164074.239 inverse transform from proj.4 invgeod: b'-66.531\t75.654\t4164192.708\n' """ true_az12 = -66.5305947876623 true_az21 = 75.65363415556968 print("from pyproj.Geod.inv:") az12, az21, dist = gg.inv(lon1pt, lat1pt, lon2pt, lat2pt) assert_almost_equal((az12, az21, dist), (true_az12, true_az21, 4164192.708), decimal=3) print("forward transform") print("from proj.4 geod:") endlon, endlat, backaz = gg.fwd(lon1pt, lat1pt, az12, dist) assert_almost_equal((endlon, endlat, backaz), (lon2pt, lat2pt, true_az21), decimal=3) inc_exc = ["excluding", "including"] res_az12_az21_dists_all = [ (180.0, 0.0, 0.0), (-66.53059478766238, 106.79071710136431, 832838.5416198927), (-73.20928289863558, 99.32289055927389, 832838.5416198935), (-80.67710944072617, 91.36325611787134, 832838.5416198947), (-88.63674388212858, 83.32809401477382, 832838.5416198922), (-96.67190598522616, 75.65363415556973, 832838.5416198926), ] point_count = len(res_az12_az21_dists_all) for include_initial, include_terminus in itertools.product((False, True), (False, True)): initial_idx = int(not include_initial) terminus_idx = int(not include_terminus) npts = point_count - initial_idx - terminus_idx print("intermediate points:") print("from geod with +lat_1,+lon_1,+lat_2,+lon_2,+n_S:") print( f"{lat1pt:6.3f} {lon1pt:7.3f} {lat2pt:6.3f} {lon2pt:7.3f} {npts}") lonlats = gg.npts( lon1pt, lat1pt, lon2pt, lat2pt, npts, initial_idx=initial_idx, terminus_idx=terminus_idx, ) assert len(lonlats) == npts npts1 = npts + initial_idx + terminus_idx - 1 del_s = dist / npts1 print( f"Total distnace is {dist}, " f"Points count: {npts}, " f"{inc_exc[include_initial]} initial point, " f"{inc_exc[include_terminus]} terminus point. " f"The distance between successive points is {dist}/{npts1} = {del_s}" ) from_idx = initial_idx to_idx = point_count - terminus_idx res_az12_az21_dists = res_az12_az21_dists_all[from_idx:to_idx] lonprev = lon1pt latprev = lat1pt for (lon, lat), (res12, res21, resdist) in zip(lonlats, res_az12_az21_dists): o_az12, o_az21, o_dist = gg.inv(lonprev, latprev, lon, lat) if resdist == 0: assert_almost_equal(o_dist, 0) else: assert_almost_equal((o_az12, o_az21, o_dist), (res12, res21, resdist)) latprev = lat lonprev = lon if not include_terminus: o_az12, o_az21, o_dist = gg.inv(lonprev, latprev, lon2pt, lat2pt) assert_almost_equal((lat2pt, lon2pt, o_dist), (45.517, -123.683, 832838.542), decimal=3) if include_initial and include_terminus: lons, lats, azis12, azis21, dists = np.hstack( (lonlats, res_az12_az21_dists)).transpose() del_s = dist / (point_count - 1) lons_a = np.empty(point_count) lats_a = np.empty(point_count) azis_a = np.empty(point_count) print("test inv_intermediate (by npts) with azi output") res = gg.inv_intermediate( out_lons=lons_a, out_lats=lats_a, out_azis=azis_a, lon1=lon1pt, lat1=lat1pt, lon2=lon2pt, lat2=lat2pt, npts=point_count, initial_idx=0, terminus_idx=0, ) assert res.npts == point_count assert_almost_equal(res.del_s, del_s) assert_almost_equal(res.dist, dist) assert_almost_equal(res.lons, lons) assert_almost_equal(res.lats, lats) assert_almost_equal(res.azis[:-1], azis12[1:]) assert res.lons is lons_a assert res.lats is lats_a assert res.azis is azis_a for flags in (GeodIntermediateFlag.AZIS_DISCARD, GeodIntermediateFlag.AZIS_KEEP): print("test inv_intermediate (by npts) without azi output, no buffers") res = gg.inv_intermediate( lon1=lon1pt, lat1=lat1pt, lon2=lon2pt, lat2=lat2pt, npts=point_count, initial_idx=0, terminus_idx=0, flags=flags, ) assert res.npts == point_count assert_almost_equal(res.del_s, del_s) assert_almost_equal(res.dist, dist) assert_almost_equal(res.lons, lons_a) assert_almost_equal(res.lats, lats_a) if flags == GeodIntermediateFlag.AZIS_DISCARD: assert res.azis is None else: assert_almost_equal(res.azis, azis_a) lons_b = np.empty(point_count) lats_b = np.empty(point_count) azis_b = np.empty(point_count) print("test inv_intermediate (by npts) without azi output") res = gg.inv_intermediate( out_lons=lons_b, out_lats=lats_b, out_azis=None, lon1=lon1pt, lat1=lat1pt, lon2=lon2pt, lat2=lat2pt, npts=point_count, initial_idx=0, terminus_idx=0, flags=flags, ) assert res.npts == point_count assert_almost_equal(res.del_s, del_s) assert_almost_equal(res.dist, dist) assert_almost_equal(res.lons, lons_a) assert_almost_equal(res.lats, lats_a) assert res.lons is lons_b assert res.lats is lats_b if flags == GeodIntermediateFlag.AZIS_DISCARD: assert res.azis is None else: assert_almost_equal(res.azis, azis_a) print("test fwd_intermediate") res = gg.fwd_intermediate( out_lons=lons_b, out_lats=lats_b, out_azis=azis_b, lon1=lon1pt, lat1=lat1pt, azi1=true_az12, npts=point_count, del_s=del_s, initial_idx=0, terminus_idx=0, ) assert res.npts == point_count assert_almost_equal(res.del_s, del_s) assert_almost_equal(res.dist, dist) assert_almost_equal(res.lons, lons_a) assert_almost_equal(res.lats, lats_a) assert_almost_equal(res.azis, azis_a) assert res.lons is lons_b assert res.lats is lats_b assert res.azis is azis_b print("test inv_intermediate (by del_s)") for del_s_fact, flags in ( (1, GeodIntermediateFlag.NPTS_ROUND), ((point_count - 0.5) / point_count, GeodIntermediateFlag.NPTS_TRUNC), ((point_count + 0.5) / point_count, GeodIntermediateFlag.NPTS_CEIL), ): res = gg.inv_intermediate( out_lons=lons_b, out_lats=lats_b, out_azis=azis_b, lon1=lon1pt, lat1=lat1pt, lon2=lon2pt, lat2=lat2pt, del_s=del_s * del_s_fact, initial_idx=0, terminus_idx=0, flags=flags, ) assert res.npts == point_count assert_almost_equal(res.del_s, del_s) assert_almost_equal(res.dist, dist) assert_almost_equal(res.lons, lons_a) assert_almost_equal(res.lats, lats_a) assert_almost_equal(res.azis, azis_a) assert res.lons is lons_b assert res.lats is lats_b assert res.azis is azis_b
class TestRadians(unittest.TestCase): """Tests issue #84""" def setUp(self): self.g = Geod(ellps='clrk66') self.boston_d = (-71. - (7. / 60.), 42. + (15. / 60.)) self.boston_r = (math.radians(self.boston_d[0]), math.radians(self.boston_d[1])) self.portland_d = (-123. - (41. / 60.), 45. + (31. / 60.)) self.portland_r = (math.radians(self.portland_d[0]), math.radians(self.portland_d[1])) def test_inv_radians(self): # Get bearings and distance from Boston to Portland in degrees az12_d, az21_d, dist_d = self.g.inv( self.boston_d[0], self.boston_d[1], self.portland_d[0], self.portland_d[1], radians=False) # Get bearings and distance from Boston to Portland in radians az12_r, az21_r, dist_r = self.g.inv( self.boston_r[0], self.boston_r[1], self.portland_r[0], self.portland_r[1], radians=True) # Check they are equal self.assertAlmostEqual(az12_d, math.degrees(az12_r)) self.assertAlmostEqual(az21_d, math.degrees(az21_r)) self.assertAlmostEqual(dist_d, dist_r) def test_fwd_radians(self): # Get bearing and distance to Portland az12_d, az21_d, dist = self.g.inv( self.boston_d[0], self.boston_d[1], self.portland_d[0], self.portland_d[1], radians=False) # Calculate Portland's lon/lat from bearing and distance in degrees endlon_d, endlat_d, backaz_d = self.g.fwd( self.boston_d[0], self.boston_d[1], az12_d, dist, radians=False) # Calculate Portland's lon/lat from bearing and distance in radians endlon_r, endlat_r, backaz_r = self.g.fwd( self.boston_r[0], self.boston_r[1], math.radians(az12_d), dist, radians=True) # Check they are equal self.assertAlmostEqual(endlon_d, math.degrees(endlon_r)) self.assertAlmostEqual(endlat_d, math.degrees(endlat_r)) self.assertAlmostEqual(backaz_d, math.degrees(backaz_r)) # Check to make sure we're back in Portland self.assertAlmostEqual(endlon_d, self.portland_d[0]) self.assertAlmostEqual(endlat_d, self.portland_d[1]) def test_npts_radians(self): # Calculate 10 points between Boston and Portland in degrees points_d = self.g.npts( lon1=self.boston_d[0], lat1=self.boston_d[1], lon2=self.portland_d[0], lat2=self.portland_d[1], npts=10, radians=False) # Calculate 10 points between Boston and Portland in radians points_r = self.g.npts( lon1=self.boston_r[0], lat1=self.boston_r[1], lon2=self.portland_r[0], lat2=self.portland_r[1], npts=10, radians=True) # Check they are equal for index, dpoint in enumerate(points_d): self.assertAlmostEqual(dpoint[0], math.degrees(points_r[index][0])) self.assertAlmostEqual(dpoint[1], math.degrees(points_r[index][1]))
class GCMapper: def __init__(self, width=800, height=None, bgcol=DEFAULT_BG, proj='eqc', cols=DEFAULT_COLS, line_width=1, gc_resolution=100): ''' Create an object for turning coordinate pairs into an image. Parameters height the height of the resultant image width the width of the resultant image bgcol the background color of the image, as an (r,g,b) triple proj the projection name as a string (passed to pyproj) cols a function which takes one fractional argument and returns a color (r,g,b) triple line_width the width of lines drawn gc_resolution the number of straight line segments used to approximate each great-circle curve Once the object is initialized, call set_data to add data. ''' if height is None: height = width / 2 self.height = height self.width = width self.bgcol = bgcol self.proj = proj self.line_width = line_width self.gc_resolution = gc_resolution self.cols = cols self.geo = Geod(a=1) def set_data(self, lon1, lat1, lon2, lat2, count=None): ''' Set the coordinate pairs to be drawn. The pairs are given as equal-length lists of longitudes and latitudes of each point in the pair, giving four lists total. A fifth list, count, optionally gives the frequency at which each pair occurred in the source data. Parameters: lon1 the longitudes of the source points lat1 the latitudes of the source points lon2 the longitudes of the destination points lat2 the latitudes of the destination points count the frequency of each pair Once the data is set, call draw() to render the image. ''' self.data = np.array((lon1, lat1, lon2, lat2)).T self.data_size = self.data.shape[0] # calculate great-circle distances between each coordinate # pair. This will be used for determining which order to # draw the lines in. _, _, dist = self.geo.inv(np.array(lon1), np.array(lat1), np.array(lon2), np.array(lat2)) # if a frequency count is given, take it into account when # creating weights. Weights determine the coloring and # drawing order of each line. if count is not None: self.weight = np.array(count) / dist else: self.weight = 1 / dist self.order = np.argsort(self.weight) def draw(self): ''' Render the image. Assumes that set_data has already been called. Returns a Python Image Library (PIL) Image object. ''' img = Image.new('RGB', (self.width, self.height), self.bgcol) canvas = Draw(img) # create the projection. Here we use an equidistant cylindrical projection, # but others may work with tweaking of the parameters. proj = Proj(proj=self.proj, a=self.width/(2*pi), # set the radius of the earth such that our # projections work x_0=self.width/2, # center horizontally on the image y_0=self.height/2) # center verticallly on the image # two branches below will use the same sequence of commands to # draw a great-circle on the map, so the common elements are wrapped # up into a locally defined function. Given a matrix of points and # a pen, draw the path through the points. def draw_(pts, pen): lons, lats = pts.T x, y = proj(lons, lats) y = self.height - y path = reduce(operator.add, zip(x, y)) canvas.line(path, pen) # loop over every coordinate pair for i, (lon1, lat1, lon2, lat2) in enumerate(self.data[self.order]): # calculate the fraction of the paths already drawn, and use # it to create a pen of the appropriate color frac = i / float(self.data_size) pen = Pen(self.cols(frac), self.line_width) # find the intermediate coordinates along a line between the two # coordinates pts = self.geo.npts(lon1, lat1, lon2, lat2, self.gc_resolution) pts = np.array(pts) # if the longitudinal distance between the two points (travelling # through the prime meridian) is more than 180 degrees, it's faster # to *not* travel through the prime meridian, so we have to special- # case the drawing of the lines. if abs(lon1 - lon2) >= HALF_ROTATION: # find the index of the path where the line wraps around the image (cut_point,), = np.where(np.abs(np.diff(pts[:,0])) > HALF_ROTATION) # draw the two resultant lines separately pts1 = pts[:cut_point+1,:] pts2 = pts[cut_point+1:,:] # plot one point after the break on each sides so that the # paths go to the edge of the screen x1, y1 = pts[cut_point+2, :] x2, y2 = pts[cut_point+1, :] if x1 > 0: pts1 = np.vstack((pts1, [-HALF_ROTATION, y1])) pts2 = np.vstack(([HALF_ROTATION, y2], pts2)) else: pts1 = np.vstack((pts1, [HALF_ROTATION, y1])) pts2 = np.vstack(([-HALF_ROTATION, y2], pts2)) draw_(pts1, pen) draw_(pts2, pen) else: # the path does not wrap the image, so we can simply draw # it as-is draw_(pts, pen) canvas.flush() return img
length = 500 #km, size of the DEM g = Geod(ellps='WGS84') # Use Clarke WGS84 ellipsoid total_pixels = (width * 1000 / pixels) * (length * 1000 / pixels) endlon1, urcrnrlat, backaz = g.fwd(centerlon, centerlat, 0, width / 2) urcrnrlon, endlat2, backaz = g.fwd(centerlon, centerlat, 90, width / 2) endlon3, llcrnrlat, backaz = g.fwd(centerlon, centerlat, 180, width / 2) llcrnrlon, endlat4, backaz = g.fwd(centerlon, centerlat, 270, width / 2) pixel_id = list(range((width * 1000 / pixels))) intermediate_pixels = width * 1000 / pixels - 2 lonlats = [] elevations = [] lonlats.append((llcrnrlon, llcrnrlat)) lonlats += g.npts(llcrnrlon, llcrnrlat, urcrnrlon, llcrnrlat, intermediate_pixels) lonlats.append((urcrnrlon, llcrnrlat)) el = srtm.get_data() for i in range(len(lonlats)): elevation = el.get_elevation(lonlats[i][1], lonlats[i][0]) elevations.append(elevation) data = {'id': pixel_id, 'coordinates': lonlats, 'elevation': elevations} df = pd.DataFrame(data, columns=['id', 'coordinates', 'elevation']) pickle.dump(df, open("DEM.pickle", "wb")) print(df.ix[1, 'elevation']) #print (total_pixels) print len((lonlats)) #print len(pixel_id) #el = srtm.get_data() #elevation = el.get_elevation(latitude,longitude)
endlon, endlat, backaz = g.fwd(lon1pt, lat1pt, az12, dist) print 'from pyproj.Geod.fwd:' print "%6.3f %6.3f %13.3f" % (endlat, endlon, backaz) print 'intermediate points:' print 'from geod with +lat_1,+lon_1,+lat_2,+lon_2,+n_S:' points = '+lon_1=%s +lat_1=%s +lon_2=%s +lat_2=%s' % ( lon1pt, lat1pt, lon2pt, lat2pt, ) print points print commands.getoutput('geod +ellps=clrk66 -f "%.3f" +n_S=5 ' + points) print 'from pyproj.Geod.npts:' npts = 4 lonlats = g.npts(lon1pt, lat1pt, lon2pt, lat2pt, npts) lonprev = lon1pt latprev = lat1pt print dist / (npts + 1) print '%6.3f %7.3f' % (lat1pt, lon1pt) for lon, lat in lonlats: az12, az21, dist = g.inv(lonprev, latprev, lon, lat) print '%6.3f %7.3f %11.3f' % (lat, lon, dist) latprev = lat lonprev = lon az12, az21, dist = g.inv(lonprev, latprev, lon2pt, lat2pt) print '%6.3f %7.3f %11.3f' % (lat2pt, lon2pt, dist) # specify the lat/lons of some cities. boston_lat = 42. + (15. / 60.) boston_lon = -71. - (7. / 60.)
def interpolate(x1, y1, x2, y2, n): geoid = Geod(ellps="WGS84") return geoid.npts(x1, y1, x2, y2, n)
def interpolate_great_circle(start, stop, N=30): geoid = Geod(ellps="WGS84") middle = geoid.npts(*start[::-1], *stop[::-1], N) pts = [tuple(start)] + [pt[::-1] for pt in middle] + [tuple(stop)] return np.array(pts)
def get_mesh(pfs, rfi, sd, idl): """ From a set of profiles creates the mesh in the forward direction from the reference profile. :param pfs: List of :class:`openquake.hazardlib.geo.line.Line` instances :param rfi: Index of the reference profile :param sd: Sampling distance [km] for the edges :param idl: Boolean indicating the need to account for the IDL :returns: An updated list of the profiles i.e. a list of :class:`openquake.hazardlib.geo.line.Line` instances """ g = Geod(ellps='WGS84') # Residual distance, last index rdist = [0 for _ in range(0, len(pfs[0]))] laidx = [0 for _ in range(0, len(pfs[0]))] # New profiles npr = list([copy.copy(pfs[rfi])]) # Run for all the profiles 'after' the reference one for i in range(rfi, len(pfs) - 1): # Profiles pr = pfs[i + 1] pl = pfs[i] # Fixing IDL case if idl: for ii in range(0, len(pl)): ptmp = pl[ii][0] ptmp = ptmp + 360 if ptmp < 0 else ptmp pl[ii][0] = ptmp # Point in common on the two profiles cmm = np.logical_and(np.isfinite(pr[:, 2]), np.isfinite(pl[:, 2])) cmmi = np.nonzero(cmm)[0].astype(int) # Update last profile index mxx = 0 for ll in laidx: if ll is not None: mxx = max(mxx, ll) # Loop over the points in the right profile for x in range(0, len(pr[:, 2])): # This edge is in common between the last and the current profiles if x in cmmi and laidx[x] is None: iii = [] for li, lv in enumerate(laidx): if lv is not None: iii.append(li) iii = np.array(iii) minidx = np.argmin(abs(iii - x)) laidx[x] = mxx rdist[x] = rdist[minidx] elif x not in cmmi: laidx[x] = None rdist[x] = 0 # Loop over profiles for k in list(np.nonzero(cmm)[0]): # Compute distance and azimuth between the corresponding points # on the two profiles az12, _, hdist = g.inv(pl[k, 0], pl[k, 1], pr[k, 0], pr[k, 1]) hdist /= 1e3 vdist = pr[k, 2] - pl[k, 2] tdist = (vdist**2 + hdist**2)**.5 ndists = int(np.floor((tdist + rdist[k]) / sd)) ll = g.npts(pl[k, 0], pl[k, 1], pr[k, 0], pr[k, 1], np.ceil(tdist) * 20) ll = np.array(ll) lll = np.ones_like(ll) lll[:, 0] = pl[k, 0] lll[:, 1] = pl[k, 1] _, _, hdsts = g.inv(lll[:, 0], lll[:, 1], ll[:, 0], ll[:, 1]) hdsts /= 1e3 deps = np.linspace(pl[k, 2], pr[k, 2], ll.shape[0], endpoint=True) tdsts = (hdsts**2 + (pl[k, 2] - deps)**2)**0.5 assert len(deps) == ll.shape[0] # Compute distance between consecutive profiles dd = distance(pl[k, 0], pl[k, 1], pl[k, 2], pr[k, 0], pr[k, 1], pr[k, 2]) # Check distance if abs(dd - tdist) > 0.1 * tdist: print('dd:', dd) tmps = 'Error while building the mesh' tmps += '\nDistances: {:f} {:f}' raise ValueError(tmps.format(dd, tdist)) # Adding new points along the edge with index k for j in range(ndists): # Add new profile if len(npr) - 1 < laidx[k] + 1: npr = add_empty_profile(npr) # Compute the coordinates of intermediate points along the # current edge tmp = (j + 1) * sd - rdist[k] lo, la, _ = g.fwd(pl[k, 0], pl[k, 1], az12, tmp * hdist / tdist * 1e3) tidx = np.argmin(abs(tdsts - tmp)) lo = ll[tidx, 0] la = ll[tidx, 1] # Fix longitudes if idl: lo = lo + 360 if lo < 0 else lo # Computing depths de = pl[k, 2] + tmp * vdist / hdist de = deps[tidx] npr[laidx[k] + 1][k] = [lo, la, de] if (k > 0 and np.all(np.isfinite(npr[laidx[k] + 1][k])) and np.all(np.isfinite(npr[laidx[k]][k]))): p1 = npr[laidx[k]][k] p2 = npr[laidx[k] + 1][k] d = distance(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]) # Check if abs(d - sd) > 0.1 * sd: tmpf = 'd: {:f} diff: {:f} tol: {:f} sd:{:f}' tmpf += '\nresidual: {:f}' tmps = tmpf.format(d, d - sd, TOL * sd, sd, rdist[k]) raise ValueError(tmps) laidx[k] += 1 rdist[k] = tdist - sd * ndists + rdist[k] assert rdist[k] < sd return npr
def get_mesh(pfs, rfi, sd, idl): """ :param pfs: List of :class:`openquake.hazardlib.geo.line.Line` instances :param rfi: Index of the reference profile :param sd: Sampling distance :param idl: Boolean indicating the need to account for IDL presence :returns: Profiles """ g = Geod(ellps='WGS84') # # residual distance, last index rdist = [0 for _ in range(0, len(pfs[0]))] laidx = [0 for _ in range(0, len(pfs[0]))] # # new profiles npr = list([copy.deepcopy(pfs[rfi])]) # # run for all the profiles 'after' the reference one for i in range(rfi, len(pfs) - 1): # # profiles pr = pfs[i + 1] pl = pfs[i] # # fixing IDL case if idl: for ii in range(0, len(pl)): ptmp = pl[ii][0] ptmp = ptmp + 360 if ptmp < 0 else ptmp pl[ii][0] = ptmp # # point in common on the two profiles cmm = np.logical_and(np.isfinite(pr[:, 2]), np.isfinite(pl[:, 2])) cmmi = np.nonzero(cmm)[0].astype(int) # # update last profile index mxx = 0 for ll in laidx: if ll is not None: mxx = max(mxx, ll) # # loop over the points in the right profile for x in range(0, len(pr[:, 2])): # # this edge is in common between the last and the current profiles if x in cmmi and laidx[x] is None: iii = [] for li, lv in enumerate(laidx): if lv is not None: iii.append(li) iii = np.array(iii) minidx = np.argmin(abs(iii - x)) laidx[x] = mxx rdist[x] = rdist[minidx] elif x not in cmmi: laidx[x] = None rdist[x] = 0 # # loop over profiles for k in list(np.nonzero(cmm)[0]): # # compute distance and azimuth between the corresponding points # on the two profiles az12, _, hdist = g.inv(pl[k, 0], pl[k, 1], pr[k, 0], pr[k, 1]) hdist /= 1e3 vdist = pr[k, 2] - pl[k, 2] tdist = (vdist**2 + hdist**2)**.5 ndists = int(np.floor((tdist + rdist[k]) / sd)) ll = g.npts(pl[k, 0], pl[k, 1], pr[k, 0], pr[k, 1], np.ceil(tdist) * 20) ll = np.array(ll) lll = np.ones_like(ll) lll[:, 0] = pl[k, 0] lll[:, 1] = pl[k, 1] _, _, hdsts = g.inv(lll[:, 0], lll[:, 1], ll[:, 0], ll[:, 1]) hdsts /= 1e3 deps = np.linspace(pl[k, 2], pr[k, 2], ll.shape[0], endpoint=True) tdsts = (hdsts**2 + (pl[k, 2] - deps)**2)**0.5 assert len(deps) == ll.shape[0] # # checking distance calculation dd = distance(pl[k, 0], pl[k, 1], pl[k, 2], pr[k, 0], pr[k, 1], pr[k, 2]) # >>> TOLERANCE if abs(dd - tdist) > 0.1 * tdist: print('dd:', dd) tmps = 'Error while building the mesh' tmps += '\nDistances: {:f} {:f}' raise ValueError(tmps.format(dd, tdist)) # # adding new points along the edge with index k for j in range(ndists): # # add new profile if len(npr) - 1 < laidx[k] + 1: npr = add_empy_profile(npr) # # compute the coordinates of intermediate points along the # current edge tmp = (j + 1) * sd - rdist[k] lo, la, _ = g.fwd(pl[k, 0], pl[k, 1], az12, tmp * hdist / tdist * 1e3) # --------------------------------------------- tidx = np.argmin(abs(tdsts - tmp)) lo = ll[tidx, 0] la = ll[tidx, 1] # # fix longitudes if idl: lo = lo + 360 if lo < 0 else lo # # computing depths de = pl[k, 2] + tmp * vdist / hdist # --------------------------------------------- de = deps[tidx] npr[laidx[k] + 1][k] = [lo, la, de] if (k > 0 and np.all(np.isfinite(npr[laidx[k] + 1][k])) and np.all(np.isfinite(npr[laidx[k]][k]))): p1 = npr[laidx[k]][k] p2 = npr[laidx[k] + 1][k] d = distance(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]) # >>> TOLERANCE # if abs(d-sd) > TOL*sd: if abs(d - sd) > 0.1 * sd: tmpf = 'd: {:f} diff: {:f} tol: {:f} sd:{:f}' tmpf += '\nresidual: {:f}' tmps = tmpf.format(d, d - sd, TOL * sd, sd, rdist[k]) logging.warning(tmps) # # plotting if False: fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection='3d') for ipro, pro in enumerate(pfs): tmp = [[p[0], p[1], p[2]] for p in pro] tmp = np.array(tmp) tmplon = tmp[:, 0] if idl: tmplon = ([ x + 360 if x < 0 else x for x in tmplon ]) tmplon0 = tmplon[0] ax.plot(tmplon, tmp[:, 1], tmp[:, 2], 'x--b', markersize=2) ax.text(tmplon0, tmp[0, 1], tmp[0, 2], '{:d}'.format(ipro)) for pro in npr: tmp = [[p[0], p[1], p[2]] for p in pro] tmp = np.array(tmp) tmplon = tmp[:, 0] if idl: tmplon = ([ x + 360 if x < 0 else x for x in tmplon ]) ax.plot(tmplon, tmp[:, 1], tmp[:, 2], 'x--r', markersize=2) if idl: p1[0] = p1[0] + 360 if p1[0] < 0 else p1[0] p2[0] = p2[0] + 360 if p2[0] < 0 else p2[0] ax.plot([p1[0]], [p1[1]], [p1[2]], 'og') ax.plot([p2[0]], [p2[1]], [p2[2]], 'og') ax.invert_zaxis() ax.view_init(50, 55) plt.show() # raise ValueError('') laidx[k] += 1 rdist[k] = tdist - sd * ndists + rdist[k] assert rdist[k] < sd return npr
def get_mesh(pfs, rfi, sd, idl): """ From a set of profiles creates the mesh in the forward direction from the reference profile. :param pfs: List of :class:`openquake.hazardlib.geo.line.Line` instances :param rfi: Index of the reference profile :param sd: Sampling distance [km] for the edges :param idl: Boolean indicating the need to account for the IDL :returns: An updated list of the profiles i.e. a list of :class:`openquake.hazardlib.geo.line.Line` instances """ g = Geod(ellps='WGS84') # Instantiate lists with the residual distance and the last profile index # with a finite value at a given depth rdist = [0 for _ in range(0, len(pfs[0]))] laidx = [0 for _ in range(0, len(pfs[0]))] angle = [0 for _ in range(0, len(pfs[0]))] # Creating a new list used to collect the new profiles which will describe # the mesh. We start with the initial profile i.e. the one identified by # the reference index rfi npr = list([copy.copy(pfs[rfi])]) # Run for all the profiles 'after' the reference one for i in range(rfi, len(pfs) - 1): # Profiles: left and right pr = pfs[i + 1] pl = pfs[i] # Fixing IDL case if idl: for ii in range(0, len(pl)): ptmp = pl[ii][0] ptmp = ptmp + 360 if ptmp < 0 else ptmp pl[ii][0] = ptmp # Points in common on the two profiles i.e. points with finite # coordinates on both of them cmm = np.logical_and(np.isfinite(pr[:, 2]), np.isfinite(pl[:, 2])) cmmi = np.nonzero(cmm)[0].astype(int) # Find the index of the profiles previously analysed and with at least # a node in common with the current profile (i.e. with a continuity in # the mesh) mxx = 0 for ll in laidx: if ll is not None: mxx = max(mxx, ll) # Loop over the points in the right profile for x in range(0, len(pr[:, 2])): # If true this edge connects the right and left profiles if x in cmmi and laidx[x] is None: iii = [] for li, lv in enumerate(laidx): if lv is not None: iii.append(li) iii = np.array(iii) minidx = np.argmin(abs(iii - x)) laidx[x] = mxx rdist[x] = rdist[minidx] angle[x] = angle[minidx] elif x not in cmmi: laidx[x] = None rdist[x] = 0 angle[x] = None # Loop over the indexes of the edges in common for the two profiles # starting from the top and going down for k in list(np.nonzero(cmm)[0]): # Compute distance [km] and azimuth between the corresponding # points on the two consecutive profiles az12, _, hdist = g.inv(pl[k, 0], pl[k, 1], pr[k, 0], pr[k, 1]) hdist /= 1e3 # Vertical distance vdist = pr[k, 2] - pl[k, 2] # Total distance tdist = (vdist**2 + hdist**2)**.5 # Update rdist new_rdist = rdist[k] if rdist[k] > 0 and abs(az12 - angle[k] > 2): new_rdist = update_rdist(rdist[k], az12, angle[k], sd) # Number of grid points # ndists = int(np.floor((tdist+rdist[k])/sd)) ndists = int(np.floor((tdist + new_rdist) / sd)) # Calculate points between the corresponding nodes on the # two profiles ll = g.npts(pl[k, 0], pl[k, 1], pr[k, 0], pr[k, 1], np.ceil(tdist) * 20) ll = np.array(ll) lll = np.ones_like(ll) lll[:, 0] = pl[k, 0] lll[:, 1] = pl[k, 1] _, _, hdsts = g.inv(lll[:, 0], lll[:, 1], ll[:, 0], ll[:, 1]) hdsts /= 1e3 deps = np.linspace(pl[k, 2], pr[k, 2], ll.shape[0], endpoint=True) tdsts = (hdsts**2 + (pl[k, 2] - deps)**2)**0.5 assert len(deps) == ll.shape[0] # Compute distance between nodels at depth 'k' on the two # consecutive profiles dd = distance(pl[k, 0], pl[k, 1], pl[k, 2], pr[k, 0], pr[k, 1], pr[k, 2]) # Check that the actual distance between these nodes is similar to # the one originally defined if abs(dd - tdist) > 0.1 * tdist: print('dd:', dd) tmps = 'Error while building the mesh' tmps += '\nDistances: {:f} {:f}' raise ValueError(tmps.format(dd, tdist)) # Adding new points along the edge with index k for j in range(ndists): # Add new profile to 'npr' i.e. the list containing the new # set of profiles if len(npr) - 1 < laidx[k] + 1: npr = add_empty_profile(npr) # Compute the coordinates of intermediate points along the # current edge. 'tmp' is the distance between the node on the # left edge and the j-th node on the edge. 'lo' and 'la' are # the coordinates of this new node # tmp = (j+1)*sd - rdist[k] tmp = (j + 1) * sd - new_rdist # lo, la, _ = g.fwd(pl[k, 0], pl[k, 1], az12, # tmp*hdist/tdist*1e3) # Find the index of the closest node in the vector sampled at # high frequency tidx = np.argmin(abs(tdsts - tmp)) lo = ll[tidx, 0] la = ll[tidx, 1] # Fix longitudes in proximity of the IDL if idl: lo = lo + 360 if lo < 0 else lo # Computing depths de = pl[k, 2] + tmp * vdist / hdist de = deps[tidx] # Updating the new profile npr[laidx[k] + 1][k] = [lo, la, de] if (k > 0 and np.all(np.isfinite(npr[laidx[k] + 1][k])) and np.all(np.isfinite(npr[laidx[k]][k]))): # Computing the distance between consecutive points on # one edge p1 = npr[laidx[k]][k] p2 = npr[laidx[k] + 1][k] d = distance(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]) # Check if the distance between consecutive points on one # edge (with index k) is within a tolerance limit of the # mesh distance defined by the user if abs(d - sd) > TOL * sd: tmpf = '\ndistance: {:f} difference: {:f} ' tmpf += '\ntolerance dist: {:f} sampling dist: {:f}' tmpf += '\nresidual distance: {:f}' tmps = tmpf.format(d, d - sd, TOL * sd, sd, new_rdist) raise ValueError(tmps) laidx[k] += 1 # Check that the residual distance along each edge is lower than # the sampling distance rdist[k] = tdist - sd * ndists + new_rdist angle[k] = az12 assert rdist[k] < sd return npr
# compute forward and back azimuths, plus distance # between Boston and Portland. az12, az21, dist = g.inv(boston_lon, boston_lat, portland_lon, portland_lat) print("%7.3f %6.3f %12.3f" % (az12, az21, dist)) # compute latitude, longitude and back azimuth of Portland, # given Boston lat/lon, forward azimuth and distance to Portland. endlon, endlat, backaz = g.fwd(boston_lon, boston_lat, az12, dist) print("%6.3f %6.3f %13.3f" % (endlat, endlon, backaz)) # compute the azimuths, distances from New York to several # cities (pass a list) lons1 = 3 * [newyork_lon] lats1 = 3 * [newyork_lat] lons2 = [boston_lon, portland_lon, london_lon] lats2 = [boston_lat, portland_lat, london_lat] az12, az21, dist = g.inv(lons1, lats1, lons2, lats2) for faz, baz, d in zip(az12, az21, dist): print("%7.3f %7.3f %9.3f" % (faz, baz, d)) ############################################################################### ############################################################################### g = Geod(ellps='clrk66') ############################################################################### boston_lat = 42. + (15. / 60.) boston_lon = -71. - (7. / 60.) portland_lat = 45. + (31. / 60.) portland_lon = -123. - (41. / 60.) ############################################################################### lonlats = g.npts(boston_lon, boston_lat, portland_lon, portland_lat, 10) for lon, lat in lonlats: print('%6.3f %7.3f' % (lat, lon))
def get_bounding_box_lonlats(self, npts=100): """Returns array of lon/lats along the bounding Arcs :Parameters: npts: int Number of points to return along each line :Returns: (top, right, bottom, left) : 4 tuples containing lists of len npts of lons/lats retval = (list(tplons),list(tplats)), (list(rtlons),list(rtlats)), (list(btlons),list(btlats)), (list(ltlons),list(ltlats)) eg for n=3 ([tplon0,tplon1,tplon2],[tplat0,tplat1,tplat2]), ([rtlon0,rtlon1,rtlon2],[rtlat0,rtlat1,rtlat2]), ([btlon0,btlon1,btlon2],[btlat0,btlat1,btlat2]), ([ltlon0,ltlon1,ltlon2],[ltlat0,ltlat1,ltlat2]), """ g = Geod(ellps='WGS84') # Top of bounding box # g.npts returns a list of tuples of lon/lat pairs # [(lon0,lat0),(lon1,lat1),(lon2,lat2)] # zip reformats that into 2 tuples of lons and lats # [(lon0,lon1,lon2),(lat0,lat1,lat2)] # list(tplons) returns list of lons # [lon0,lon1,lon2] # list(tplats) returns list of lats # [lat0,lat1,lat2] tplons, tplats = zip(*g.npts(self.corners[0].lon, self.corners[0].lat, self.corners[1].lon, self.corners[1].lat, npts, radians=True)) # Right side of bounding box rtlons, rtlats = zip(*g.npts(self.corners[1].lon, self.corners[1].lat, self.corners[2].lon, self.corners[2].lat, npts, radians=True)) # Bottom of bounding box btlons, btlats = zip(*g.npts(self.corners[2].lon, self.corners[2].lat, self.corners[3].lon, self.corners[3].lat, npts, radians=True)) # Left side of bounding box ltlons, ltlats = zip(*g.npts(self.corners[3].lon, self.corners[3].lat, self.corners[0].lon, self.corners[0].lat, npts, radians=True)) retval = [(list(tplons), list(tplats)), (list(rtlons), list(rtlats)), (list(btlons), list(btlats)), (list(ltlons), list(ltlats))] return retval
#!/usr/bin/env python3 # -*- coding: utf-8 -*- ############################################################################### from pyproj import Geod g = Geod(ellps='krass') ############################################################################### miniearth = Geod(a=2, b=1.97) ############################################################################### ############################################################################### g.fwd(91, 29.6, 52.88778703659133, 3419167.0426993747) ############################################################################### ############################################################################### g.inv(91, 29.6, 125.35, 43.88333) ############################################################################### ############################################################################### g = Geod(ellps='krass') lasa_lat = 29.6 lasa_lon = 91 cc_lat = 43.88333 cc_lon = 125.35 ############################################################################### lonlats = g.npts(lasa_lon, lasa_lat, cc_lon, cc_lat, 4) for lon, lat in lonlats: print('%6.3f %7.3f' % (lat, lon))