python 确定一个地方(给定坐标)是在陆地上还是在海洋上

dffbzjpn  于 2023-04-19  发布在  Python
关注(0)|答案(4)|浏览(225)

我有一些来自ISS(国际空间站)的坐标,我想知道当坐标被记录时,ISS是在陆地还是海洋上,我应该离线完成这一点,但我不确定使用什么方法。来自Python标准库的一部分,我仅限于使用这些库:

numpy
scipy
tensorflow
pandas
opencv-python
opencv-contrib-python
evdev
matplotlib
logzero
pyephem
scikit-image
scikit-learn
reverse-geocoder

如果您知道如何使用其他库来实现这一点,无论如何都是很好的。
通过这段代码,我得到坐标并将其写入文件:

import logging
import logzero
from logzero import logger
import os
import ephem
import time

dir_path = os.path.dirname(os.path.realpath(__file__))
logzero.logfile(dir_path+"/coordinates.csv")

# Set a custom formatter
formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s');
logzero.formatter(formatter)

name = "ISS (ZARYA)"
line1 = "1 25544U 98067A   18282.18499736  .00001222  00000-0  25998-4 0  9992"
line2 = "2 25544  51.6418 170.6260 0003545 261.4423 234.4561 15.53790940136242"
iss = ephem.readtle(name, line1, line2)

iss.compute()

latitude = iss.sublat
longitude = iss.sublong

# Save the data to the file
logger.info("%s,%s", latitude, longitude )

你们有什么想法吗?先谢了。

ngynwnxp

ngynwnxp1#

来自Karin托德的global-land-mask非常易于使用和高效:

from global_land_mask import globe
print(globe.is_land(49.22, -2.23))
# → True
print(globe.is_land(49.22, -2.25))
# → False

它可以通过pip获得,它唯一的依赖项是numpy

zbwhf8kr

zbwhf8kr2#

mpl_toolkits.basemap可能会有帮助。

from mpl_toolkits.basemap import Basemap
bm = Basemap()   # default: projection='cyl'
print(bm.is_land(99.0, 13.0))  #True
print(bm.is_land(0.0, 0.0)) # False

文档:此处及相关方法如下:

**is_land(xpt,ypt)**如果给定的x,y点(投影坐标)在陆地上,则返回True,否则返回False。陆地的定义基于与类示例关联的GSHHS海岸线多边形。陆地区域内湖泊上的点不计为陆地点。
**注意:**您可能需要小心底图对象使用的投影。

axr492tv

axr492tv3#

最后,我只能使用这些库来解决我的问题。我使用这个网站geoplaner来获得海洋形状的粗略轮廓(它真的很粗糙,因为我是手工做的,但它对我的目的很好,我认为网上应该有一些更精确的多边形,但我不知道如何使用它们)。
我对每一个海洋都这样做,得到了这个(注意我使用的坐标并没有完全覆盖海洋,例如我避开了南大洋):

atlanticOcean = [(-24.6,68.5), (25.3,69.8), (5.7,61.4), (4.6,52.2), (-6.3,48.4),
            (-9.45,43.5), (-9.63,37.6), (-6.3,35.5), (-10.5,31.1), (-10.5,28.4),
            (-16.1,24.5), (-17.2,14.7), (-8.2,4.1), (6.3,3.6), (9.9,3.4),
            (9,-1.7), (13.8,-12.6), (11.7,-16.5), (14.5,-22.3), (16.1,-28.67),
            (18.9,-34.5), (18.9,-55.7), (-66,-55.7), (-68.5,-50.4), (-58.6,-39.3), (-48.1,-28.2),
            (-48.1,-25.7), (-41.6,-22.7), (-38.7,-17.4), (-39.5,-13.7), (-36.9,-12.5),
            (-34.9,-10.4), (-35.0,-5.5), (-50,-0.1), (-53,5.5), (-57.2,6.1),
            (-62.8,10.9), (-67.8,10.9), (-74.2,10.8), (-76.9,8.5), (-81.6,9.4),
            (-82.7,14), (-87.4,16.1), (-86.3,21.6), (-90.2,21.7), (-91.2,19.2),
            (-95.7,18.8), (-97.1,25.5), (-91.0,28.9), (-84,29.7), (-82.9,27.3),
            (-80.9,24.9), (-79.3,26.7), (-81.1,31.3), (-75.4,35.2), (-73.8,40.3),
            (-69.6,41.4), (-65.1,43.5), (-60,45.8), (-52.2,47.1), (-54.9,52.9),
            (-44.5,60.1), (-38.8,65.1)]

indianOcean =  [(21.40,-34.15), (27.37,-33.71), (40.03,-15.61), (39.68,-3.50), (51.80,10.16), 
                (58.84,22.26), (65.69,25.18), (71.32,19.83), (77.47,6.86), (80.24,12.53),
                (80.90,15.85), (89.05,22.12), (91.38,22.08), (94.54,17.74), (94.02,16.02),
                (97.00,16.82), (98.19,8.33), (100.78,3.18), (94.98,6.29), (105.0,-6.52),
                (118.16,-9.26), (123.52,-11.25), (129.93,-11.08), (128.62,-14.51), (125.89,-3.57),
                 (118.51,-20.37), (113.06,-22.18), (115.26,-34.44), (123.52,-34.88), (130.99,-32.09),
                (137.23,-36.59), (137.50,-66.47), (102.26,-65.79), (85.65,-66.22), (75.01,-69.50),
                (69.04,-67.67), (54.18,-65.76), (37.48,-68.65)]

现在,太平洋更复杂,因为它延伸到Map的两边,你可以有两个连续的点,经度分别为-179和179,这导致这个多边形在xy平面上表现不好。我所做的是将它一分为二,所以我得到了这个:

pacificEast = [(149.9,-37.8),(153.9,-28.5),(143.2,-11.5),(152.1,-0.9),(127.9,5.7),
                (122.9,23.8),(123.4,31),(128.9,33.7),(129.8,29.4),(141.6,35),
                (142.8,41),(148,43.3),(144.6,45.5),(146.2,49.3),(144.9,54.2),
                (136.8,55.2),(143.1,59.1),(153.7,59.2),(159.4,61.6),(160.3,60.5),
                (161.4,60.3),(155.4,57),(156.6,50.3),(160.8,52.8),(164.1,55.8),
                (163.8,58.1),(167.3,60.1),(170.7,59.8), (179.9,-77.1),
                (166.4,-77.1), (173.8,-71.8), (142.9,-66.8), (146.9,-44.8)]

pacificWest = [(-179.9,62.2),(-179.7,64.7),
                (-177.3,65.3),(-173.6,63.4),(-166,62.2),(-165.8,60.9),(-168.4,60.4),
                (-166.6,58.9),(-158.5,57.8),(-153.1,57),(-144.8,59.9),(-136.1,56.9),
                (-131.7,51.9),(-125.2,48.4),(-124.5,44.6),(-124.4,40.7),(-117.6,32.7),
                (-110.7,23.2),(-105.8,19.7),(-96.1,15.3),(-87.9,12.4),(-83.7,7.3),
                (-78.7,6.1),(-80.2,0.9),(-82.2,-0.6),(-81.2,-6.3),(-76.7,-14.4),
                (-70.4,-18.9),(-73.7,-36.7),(-76,-46.2),(-75.1,-53),(-73.4,-55.1),
                (-66.6,-56.3),(-64.6,-55),(-59.6,-63.4),(-68.4,-65.7),(-75.8,-72.2),
                (-98.6,-71.8),(-126.8,-73.2),(-146.8,-75.7),(-162.6,-78.4),(-179.9,-77.1)]

据我所知,使用matplotlib,你可以用path从顶点(坐标列表)创建多边形,然后你可以使用contains_point()函数来检查点是否在多边形中(因此它在“海洋”中)或不在“陆地”中:

p1 = path.Path(atlanticOcean)
    p2 = path.Path(indianOcean)
    p3 = path.Path(pacificEast)
    p4 = path.Path(pacificWest)

    target = [(lon, lat)]

    result1 = p1.contains_points(target)
    result2 = p2.contains_points(target)
    result3 = p3.contains_points(target)
    result4 = p4.contains_points(target)

    # if target is in one of the polygons, it is in ocean
    if result1==True or result2==True or result3==True or result4==True: 
        print("In Ocean")     
    else:
        print("Land")

经度和纬度的变量,我用我的问题中的程序计算的国际空间站的变量。

mwyxok5s

mwyxok5s4#

在尝试将风车分为陆上和海上时,我无意中遇到了这个问题。这里给出的所有解决方案对我的情况来说都太不准确了,因为位于海岸线附近或荷兰艾瑟尔湖(IJsselmeer)等湖泊中的风车往往会被错误分类。所以我想出了一个自己的解决方案,基于立交桥:它在OSM中搜索给定国家的所有不同类型的水体,并将给定的坐标与它们匹配(或不)。它比这里提出的其他解决方案慢得多,你必须知道你想分类的东西所在国家的osmid,但从好的方面来说,它要准确得多。areaID是OSM-ID加上3600000000,由于某种原因才能作为立交桥的搜索区域

from geopy.geocoders import Nominatim
countries = {}

def getAreaID(_country_name, asArea=True):    
    # Geocoding request via Nominatim
    geolocator = Nominatim(user_agent="country_compare")    
        
    try:
        geo_results = geolocator.geocode(_country_name, exactly_one=False, limit=3)
    except:
        raise Exception("got an error from Nominatim while getting AreaID of current Country.")

    # Searching for relation in result set
    for r in geo_results:
        if r.raw.get("osm_type") == "relation":
            country = r
            break
    
    # Calculating area id
    area_id = int(country.raw.get("osm_id"))
    if asArea:
        area_id += 3600000000
    
    return area_id

def getCountriesWaterBodies(_countryName):
    if _countryName in countries:
        return countries[_countryName]
    else:
        areaID = getAreaID(_countryName, True)
        eezAreaId = getEEZAreaID(_countryName, True)
        print("load water bodies of {0}".format(_countryName))

        if eezAreaId is not None:
            request = '''            
                [out:json][timeout:10000];  
                area({0})->.country;
                area({1})->.eez;    // exclusive economic zone  
                (            
                   way["natural"="water"](area.country);
                   way["natural"="water"](area.eez);
                   relation["natural"="water"](area.country);  
                   relation["natural"="water"](area.eez);  
                   way["boundary"="maritime"](area.country);
                   way["boundary"="maritime"](area.eez);
                   relation["boundary"="maritime"](area.country);
                   relation["boundary"="maritime"](area.eez);
                   relation["place"="sea"](area.eez);
                   relation["place"="sea"](area.country);
                );        
               out geom;
            '''.format(areaID, eezAreaId)
        else:
            request = '''            
                [out:json][timeout:10000];  
                area({0})->.country;                
                (            
                   way["natural"="water"](area.country);
                   relation["natural"="water"](area.country);                       
                   way["boundary"="maritime"](area.country);
                   relation["boundary"="maritime"](area.country);                   
                   relation["place"="sea"](area.country);
                );        
               out geom;
            '''.format(areaID)

        overpass_url = "http://overpass-api.de/api/interpreter"
        response = requests.get(overpass_url, params={'data': request})
        if response.status_code == 200:
            # convert result to GeoDataFrame
            data = response.json()
            geojson = osm2geojson.json2geojson(data)
            geojsonDF = gpd.GeoDataFrame.from_features(geojson)
            countries[_countryName] = geojsonDF
            return geojsonDF
        else:
            return None

def isCoordinateInWater(_lat, _lon, _country):
    countryGDF = getCountriesWaterBodies(_country)
    if countryGDF is None:
        raise Exception("The Countries water bodies could not be loaded")

    # store the coordinate in question into a dataframe
    df = pd.DataFrame({'y': [_lat], 'x': [_lon]})
    pointGDF = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['x'], df['y']))

    # search for water bodies at this point
    pointInPolys = sjoin(pointGDF, countryGDF, how='left')
    intersectingWaterBodies = pointInPolys[~pointInPolys['index_right'].isnull()]
    isInWater = intersectingWaterBodies.shape[0] > 0
    return isInWater
    
def getEEZAreaID(_countryName, asAreaID=True):
    id = None

    if _countryName == "netherlands":
        id = 3893531
    elif _countryName == "belgium":
        id = 7645548
    elif _countryName == "italy":
        id = 4769816
    elif _countryName == "germany":
        id = 3649463
    elif _countryName == "poland":
        id = 9942670
    elif _countryName == "norway":
        id = 13955915
    elif _countryName == "france":
        id = 2500903

    if id is not None and asAreaID:
        id += 3600000000
    return id

相关问题