Случайные географические координаты (на суше, избегая океана) - PullRequest
31 голосов
/ 02 февраля 2012

Какие-нибудь умные идеи о том, как генерировать случайные координаты (широта / долгота) мест на Земле? Широта Долгота. Точность до 5 баллов и избегать водоемов.

    double minLat = -90.00;
    double maxLat = 90.00;      
    double latitude = minLat + (double)(Math.random() * ((maxLat - minLat) + 1));
    double minLon = 0.00;
    double maxLon = 180.00;     
    double longitude = minLon + (double)(Math.random() * ((maxLon - minLon) + 1));
    DecimalFormat df = new DecimalFormat("#.#####");        
    log.info("latitude:longitude --> " + df.format(latitude) + "," + df.format(longitude));

Может быть, я живу в мире грез, и тема воды неизбежна ... но, надеюсь, есть более приятный, чистый и эффективный способ сделать это?

EDIT

Некоторые фантастические ответы / идеи - однако, в масштабе, скажем, мне нужно сгенерировать 25 000 координат. Переход к внешнему поставщику услуг может быть не лучшим вариантом из-за задержки, стоимости и нескольких других факторов.

Ответы [ 16 ]

15 голосов
/ 17 февраля 2012

Решение проблемы водоема будет в значительной степени проблемой данных, например, вы просто хотите пропустить океаны или вам также нужно пропустить небольшие ручьи.Либо вам нужно использовать сервис с нужным вам качеством данных, либо вам нужно самим получать данные и запускать их локально.Исходя из ваших правок, звучит так, будто вы хотите пойти по локальному маршруту данных, поэтому я остановлюсь на способе сделать это.

Один из способов - получить шейп-файл для наземных или водных районов.Затем вы можете сгенерировать случайную точку и определить, пересекает ли она территорию суши (или, альтернативно, не пересекает акваторию).

Для начала вы можете получить некоторые данные низкого разрешения здесь а затем получите данные с более высоким разрешением здесь для случаев, когда вы хотите получить лучшие ответы на береговых линиях или на озерах / реках / и т. д.Вы упомянули, что вам нужна точность в ваших точках до 5 знаков после запятой, что составляет чуть более 1 метра.Помните, что если вы получите данные, соответствующие этой точности, у вас будет один гигантский набор данных.И, если вам нужны действительно хорошие данные, будьте готовы заплатить за них.

Когда у вас есть данные формы, вам понадобятся некоторые инструменты, которые помогут вам определить пересечение ваших случайных точек. Geotools - отличное место для начала и, вероятно, будет работать для ваших нужд.Вы также в конечном итоге посмотрите на код opengis (документы на сайте geotools - не уверены, использовали ли они их или что) и JTS для обработки геометрии.Используя это, вы можете быстро открыть шейп-файл и начать выполнять некоторые запросы на пересечение.

    File f = new File ( "world.shp" );
    ShapefileDataStore dataStore = new ShapefileDataStore ( f.toURI ().toURL () );
    FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = 
        dataStore.getFeatureSource ();
    String geomAttrName = featureSource.getSchema ()
        .getGeometryDescriptor ().getLocalName ();

    ResourceInfo resourceInfo = featureSource.getInfo ();
    CoordinateReferenceSystem crs = resourceInfo.getCRS ();
    Hints hints = GeoTools.getDefaultHints ();
    hints.put ( Hints.JTS_SRID, 4326 );
    hints.put ( Hints.CRS, crs );

    FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2 ( hints );
    GeometryFactory gf = JTSFactoryFinder.getGeometryFactory ( hints );

    Coordinate land = new Coordinate ( -122.0087, 47.54650 );
    Point pointLand = gf.createPoint ( land );
    Coordinate water = new Coordinate ( 0, 0 );
    Point pointWater = gf.createPoint ( water );

    Intersects filter = ff.intersects ( ff.property ( geomAttrName ), 
        ff.literal ( pointLand ) );
    FeatureCollection<SimpleFeatureType, SimpleFeature> features = featureSource
            .getFeatures ( filter );

    filter = ff.intersects ( ff.property ( geomAttrName ), 
        ff.literal ( pointWater ) );
    features = featureSource.getFeatures ( filter );

Быстрые объяснения:

  1. Предполагается, что полученный вами шейп-файл является данными многоугольника.Пересечение по линиям или точкам не даст вам того, что вы хотите.
  2. Первый раздел открывает шейп-файл - ничего интересного
  3. вам нужно выбрать имя свойства геометрии для данного файла
  4. материал системы координат - вы указали широту / долготу в своем посте, но ГИС может быть немного сложнее.В общем, данные, на которые я указал, географические, wgs84 , и это то, что я настроил здесь.Однако, если это не так, то вы должны быть уверены, что имеете дело с вашими данными в правильной системе координат.Если все это звучит как тарабарщина, поищите в Google учебник по ГИС / координатным системам / датуму / эллипсоиду.
  5. генерация геометрии координат и фильтров довольно понятны.Результирующий набор объектов будет либо пустым, что означает, что координата находится в воде, если ваши данные являются земным покровом, либо не пустым, что означает обратное.

Примечание: если вы делаете это с действительнослучайный набор очков, вы будете часто попадать в воду, и это может занять некоторое время, чтобы получить 25k очков.Возможно, вы захотите попытаться настроить генерацию точек лучше, чем действительно случайную (например, удалить большие куски Атлантического / Тихого / Индийского океанов).

Кроме того, вы можете обнаружить, что ваши запросы на пересечение слишком медленные.Если это так, вы можете захотеть взглянуть на создание индекса дерева квадрантов (qix) с помощью инструмента, подобного GDAL .Я не помню, какие типы индексов поддерживаются геотругами.

4 голосов
/ 16 декабря 2015

Об этом уже давно спрашивают, и теперь у меня такая же потребность.Я рассматриваю две возможности:

1.Определите диапазоны поверхности для генератора случайных чисел.

Здесь важно определить уровень точности, к которому вы стремитесь.Самый простой способ - очень расслабленный и приблизительный подход.В этом случае вы можете разделить карту мира на «коробки»:

enter image description here

Каждый ящик имеет свой диапазон широт.Затем вы сначала рандомизируете, чтобы получить случайный бокс, затем вы рандомизируете, чтобы получить случайный лат и случайный длинный в пределах границ этого бокса.

Точность, конечно, здесь не самая лучшая ... Хотя это зависит от того, :) Если вы хорошо выполняете свою домашнюю работу и определяете множество коробок, охватывающих самые сложные формы поверхности - с точностью вы можете быть в порядке.

2.Элемент списка

Некоторый API для возврата имени континента из координат ИЛИ адрес ИЛИ страна ИЛИ район = то, чего нет в ВОДЕ.API Карт Google могут помочь здесь.Я не исследовал этот вопрос глубже, но я думаю, что это возможно, хотя вам придется выполнить проверку каждой сгенерированной пары координат и повторно выполнить, если это неправильно.Таким образом, вы можете немного застрять, если генератор случайных чисел будет сбрасывать вас в океан.

Кроме того, немного воды принадлежит странам, районам ... так что да, не очень точно.

Для своих нужд - я использую «ящики», потому что я также хочу контролировать точные области, из которых взяты случайные координаты, и не против, если они приземляются на озере или реке, просто не в открытом океане:)

4 голосов
/ 13 февраля 2012
  1. Загрузите грузовик с файлами KML, содержащими только наземные местоположения.
  2. Извлеките все координаты из них это может помочь здесь .
  3. Выберите их наугад.
3 голосов
/ 21 марта 2012

Есть еще один способ подойти к этому с помощью API Google Планета Земля.Я знаю, что это javascript, но я подумал, что это новый способ решения проблемы.

В любом случае, я собрал полное рабочее решение - обратите внимание, что оно работает и для рек: http://www.msa.mmu.ac.uk/~fraser/ge/coord/

Основная идея, которую я использовал, заключается в реализации метода hiTest объекта GEView в API Google Планета Земля .

Взгляните на следующий пример хита от Google.http://earth -api-samples.googlecode.com / svn / trunk / examples / hittest.html

Метод hitTest предоставляет случайную точку на экране в (координаты пикселей) длякоторый возвращает объект GEHitTestResult, который содержит информацию о географическом местоположении, соответствующем точке.Если в методе используется режим GEPlugin.HIT_TEST_TERRAIN, можно ограничить результаты только сушей (рельефом), пока мы отображаем результаты в точках с высотой> 1 м

. Эта функция, которую я использую, реализуетhitTest:

var hitTestTerrain = function()
{
    var x = getRandomInt(0, 200); // same pixel size as the map3d div height
    var y = getRandomInt(0, 200); // ditto for width
    var result = ge.getView().hitTest(x, ge.UNITS_PIXELS, y, ge.UNITS_PIXELS, ge.HIT_TEST_TERRAIN);
    var success = result && (result.getAltitude() > 1);
    return { success: success, result: result };
};

Очевидно, вы также хотите получать случайные результаты из любой точки земного шара (а не только случайные точки, видимые с одной точки зрения).Для этого я перемещаю представление Земли после каждого успешного hitTestTerrain вызова.Это достигается с помощью небольшой вспомогательной функции.

var flyTo = function(lat, lng, rng)
{
    lookAt.setLatitude(lat);
    lookAt.setLongitude(lng);
    lookAt.setRange(rng);
    ge.getView().setAbstractView(lookAt);
};

Наконец, вот урезанная версия основного блока кода, который вызывает эти два метода.

var getRandomLandCoordinates = function()
{
    var test = hitTestTerrain();
    if (test.success)
    {
        coords[coords.length] = { lat: test.result.getLatitude(), lng: test.result.getLongitude() };
    }

    if (coords.length <= number)
    {
       getRandomLandCoordinates();
    }
    else
    {
       displayResults();
    }
};

Итак, земля движетсяслучайным образом до позиции

Другие функции - это просто помощники для генерации случайных чисел x, y и случайных чисел лат, lng, вывода результатов, а также для переключения элементов управления и т. д.

Я немного протестировал код, и результаты не на 100% идеальны, настройка altitude на что-то более высокое, например, 50 м решает это, но, очевидно, это уменьшает область возможных выбранных координат.

Очевидно, вы можете адаптировать идею к вашим потребностям.Может быть, запустить код несколько раз, чтобы заполнить базу данных или что-то в этом роде.

3 голосов
/ 13 февраля 2012

Определенно у вас должна быть карта в качестве ресурса. Вы можете взять его здесь: http://www.naturalearthdata.com/

Затем я подготовил бы 1-битный черно-белый растровый ресурс с 1-й отметкой земли и 0-кратной маркировкой воды.

Размер растрового изображения зависит от вашей требуемой точности. Если вам нужно 5 градусов, тогда ваше растровое изображение будет 360/5 x 180/5 = 72x36 пикселей = 2592 бит.

Затем я загружаю это растровое изображение в Java, генерирую случайное целое число в указанном выше диапазоне, считываю бит и регенерирую, если оно равно нулю.

P.S. Также вы можете покопать здесь http://geotools.org/ для некоторых готовых решений.

2 голосов
/ 06 февраля 2015

Как план B, возможно, вы можете выбрать случайную страну, а затем выбрать случайную координату внутри этой страны.Чтобы быть справедливым при выборе страны, вы можете использовать ее площадь в качестве веса.

2 голосов
/ 13 февраля 2012

Чтобы получить хорошее равномерное распределение по широтам и долготам, вы должны сделать что-то вроде этого, чтобы получить правильные углы:

double longitude = Math.random() * Math.PI * 2;
double latitude = Math.acos(Math.random() * 2 - 1);

Что касается обхода водоемов, у вас есть данные о том, где находится вода?уже?Ну, просто пересчитайте, пока не получите удар!Если у вас уже нет этих данных, то, похоже, у некоторых других есть лучшие предложения, чем у меня ...

Надеюсь, это поможет, ура.

1 голос
/ 18 февраля 2012
  1. Перейти туда http://wiki.openstreetmap.org/
  2. Попробуйте использовать API: http://wiki.openstreetmap.org/wiki/Databases_and_data_access_APIs
1 голос
/ 14 февраля 2012

Здесь есть библиотека , и вы можете использовать ее метод .random () для получения случайной координаты.Затем вы можете использовать GeoNames WebServices , чтобы определить, находится он на суше или нет.У них есть список веб-сервисов, и вам просто нужно использовать правильный.GeoNames является бесплатным и надежным.

0 голосов
/ 07 августа 2018

В дополнение к тому, что bsimic говорит о копании в веб-сервисах GeoNames, есть ярлык:
у них есть выделенный веб-сервис для запроса имени океана .

(Мне известно об ограничении OP на , а не при использовании общедоступных веб-служб из-за количества запросов. Тем не менее, я наткнулся на этот вопрос с тем же основным вопросом и считаю это полезным.)

Перейдите к http://www.geonames.org/export/web-services.html#astergdem и посмотрите на " Океан / обратное геокодирование ".Он доступен как XML и JSON.Создайте бесплатную учетную запись пользователя для предотвращения ежедневных ограничений на демо-счете.

Пример запроса по океану (Балтийское море, JSON-URL):

http://api.geonames.org/oceanJSON?lat=54.049889&lng=10.851388&username=demo

результатыв

{
  "ocean": {
    "distance": "0",
    "name": "Baltic Sea"
  }
}

, в то время как некоторые координаты на суше приводят к

{
  "status": {
    "message": "we are afraid we could not find an ocean for latitude and longitude :53.0,9.0",
    "value": 15
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...