web-dev-qa-db-ja.com

ランダムな地理座標(陸上、海を避けます)

地球上の場所のランダムな座標(緯度/経度)を生成する方法についての賢いアイデアはありますか?緯度/経度。 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));

多分私は夢の世界に住んでいて、水の話題は避けられません...しかしうまくいけば、これを行うためのより良い、よりクリーンでより効率的な方法がありますか?

[〜#〜]編集[〜#〜]

いくつかの素晴らしい答え/アイデア-ただし、大規模な場合、25,000の座標を生成する必要があるとしましょう。遅延、コスト、その他のいくつかの要因により、外部のサービスプロバイダーに行くのは最善の選択肢ではない場合があります。

32
sdolgy

水域の問題に対処することは、主にデータの問題になるでしょう。あなたは海を逃したいだけですか、それとも小さな小川も逃したいですか?必要なデータ品質のサービスを使用する必要があるか、または自分でデータを取得してローカルで実行する必要があります。編集から、ローカルデータルートに移動したいようです。そのための方法に焦点を当てます。

1つの方法は、陸域または水域のいずれかのシェープファイルを取得することです。次に、ランダムなポイントを生成し、それが陸域と交差する(または、水域と交差しない)かどうかを判断できます。

はじめに、低解像度のデータ ここ を取得してから、高解像度のデータ ここ を取得して、海岸線や湖/川/でより良い回答を得たい場合に使用します。等小数点以下5桁、つまり1m強の精度が必要だとおっしゃっていました。その精度に一致するデータを取得すると、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. 座標系のもの-投稿で緯度/経度を指定しましたが、GISはかなり複雑になる可能性があります。一般的に、私が指摘したデータは geographic、wgs84 であり、ここで設定します。ただし、これが当てはまらない場合は、正しい座標系でデータを処理していることを確認する必要があります。それがすべて意味不明なように聞こえる場合は、GIS /座標系/データム/楕円体に関するチュートリアルを探してみてください。
  5. 座標ジオメトリとフィルターの生成は、一目瞭然です。結果のフィーチャセットは空になります(データが土地被覆の場合は座標が水中にあることを意味します)、または空ではないことを意味します(その逆)。

注:非常にランダムなポイントのセットでこれを行うと、かなり頻繁に水に当たるようになり、25kポイントに到達するまでに時間がかかる場合があります。ポイント生成の範囲を、真にランダムなものよりも範囲を広げることをお勧めします(大西洋/太平洋/インド洋の大きなチャンクを削除するなど)。

また、交差クエリが遅すぎる場合もあります。もしそうなら、あなたは [〜#〜] gdal [〜#〜] のようなツールで四分木インデックス(qix)を作成することを検討したいと思うかもしれません。ただし、geotoolsでサポートされているインデックスタイプは覚えていません。

15
philwb

これはずっと前に尋ねられてきましたが、私は今同様のニーズを持っています。私が調べている可能性は2つあります。

1。ランダムジェネレーターのサーフェス範囲を定義します。

ここで、あなたが求めている精度のレベルを特定することが重要です。最も簡単な方法は、非常にリラックスしておおよそのアプローチをとることです。この場合、世界地図を「ボックス」に分割できます。

enter image description here

各ボックスには独自の緯度経度の範囲があります。次に、最初にランダム化してランダムなボックスを取得し、次にランダム化して、そのボックスの境界内でランダムな緯度と経度を取得します。

もちろん、ここでの精度は最高ではありません...状況によって異なりますが、宿題を上手に行い、最も複雑な表面形状をカバーする多くのボックスを定義すると、精度は大丈夫かもしれません。

2。リストアイテム

座標から大陸名を返すいくつかのAPI OR address OR country OR District = WATERにはないもの。ここではGoogle Maps APIが役立ちます。これについては詳しく調査しませんでしたが、生成された座標のペアごとにチェックを実行し、それが間違っている場合は再実行する必要があるので、可能であると考えています。ランダムジェネレーターはあなたを海に投げ続けます。

また、一部の国や地域に属する水もあります。

私のニーズのために-私は「ボックス」を使用します。ランダム座標が取得される正確な領域も制御し、それが外洋ではなく湖または川に着陸するかどうかを気にしないためです:)

4
GeekSince1982
  1. 陸上のみの場所を含むKMLファイルのトラックロードをダウンロードします。
  2. それらからすべての座標を抽出します これはここで役立つかもしれません
  3. ランダムに選んでください。
4
OldCurmudgeon

間違いなく、リソースとしてマップが必要です。ここでそれを取ることができます: http://www.naturalearthdata.com/

次に、1sのマーキングランドと0xのマーキングウォーターを含む1ビットの白黒ビットマップリソースを準備します。

ビットマップのサイズは、必要な精度によって異なります。 5度が必要な場合、ビットマップは360/5 x 180/5 = 72x36ピクセル= 2592ビットになります。

次に、このビットマップをJavaにロードし、上記の範囲のランダムな整数を生成し、ビットを読み取って、ゼロの場合は再生成します。

追伸また、ここで掘り下げることもできます http://geotools.org/ 既製のソリューションがあります。

3
Suzan Cioc

Google Earth APIを使用してこれに取り組む別の方法があります。私はそれがJavaScriptであることを知っていますが、問題を解決するための新しい方法だと思いました。

とにかく、私はここで完全に機能する解決策をまとめました-川でも機能することに注意してください: http://www.msa.mmu.ac.uk/~fraser/ge/coord/

私が使用した基本的なアイデアは、 GEViewオブジェクトhiTestメソッドGoogle Earth Api に実装することです。

次のGoogleで最もヒットした例を見てください。 http://earth-api-samples.googlecode.com/svn/trunk/examples/hittest.html

HitTestメソッドには、画面上のランダムなポイント(ピクセル座標)が提供され、そのポイントに対応する地理的位置に関する情報を含むGEHitTestResultオブジェクトを返します。メソッドでGEPlugin.HIT_TEST_TERRAINモードを使用する場合、結果を1 mを超える高度のポイントにスクリーニングする限り、結果を着陸(地形)にのみ制限できます。

これは、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);
};

最後に、これらの2つのメソッドを呼び出すメインコードブロックのストリップバージョンです。

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とランダムな緯度、経度の数値を生成し、結果を出力し、コントロールなどを切り替えるヘルパーです。

私はコードをかなりテストしましたが、結果は100%完全ではありません。altitudeを50mなどのより高い値に調整すると、これが解決しますが、選択可能な座標の領域が明らかに減少しています。

もちろん、アイデアをニーズに合わせて調整することもできます。おそらく、コードを複数回実行して、データベースなどにデータを入力します。

3
Fraser

緯度と経度でニースの均一な分布を得るには、次のようにして正しい角度を取得する必要があります。

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

水域の回避に関して、水がすでにある場所のデータはありますか?さて、ヒットするまでリサンプルしてください!このデータをまだ持っていない場合は、他の人が私よりも良い提案をしているようです...

よろしくお願いいたします。

2
Elias Vasylenko

プランBとして、ランダムな国を選択してから、この国内のランダムな座標を選択することができます。国を選ぶ際に公平にするために、その面積を重みとして使用できます。

2
cassioso

ライブラリ here があり、その.random()メソッドを使用してランダムな座標を取得できます。次に、 GeoNames WebServices を使用して、それが陸上にあるかどうかを判断できます。彼らはウェブサービスのリストを持っており、あなたはちょうど正しいものを使用する必要があります。 GeoNamesは無料で信頼できます。

1
bsimic
1
Kamil

GeoNamesのWebサービスの詳細について bsimic が述べたことの補足として、ここにショートカットがあります。
海の名前を要求するための専用WebServiceがあります。

(私は、リクエストの量が多いため、パブリックWebサービスを使用しないへのOPの制約を認識しています。それでも、同じ基本的な質問でこれに遭遇し、これは役に立ったと考えています。)

http://www.geonames.org/export/web-services.html#astergdem にアクセスし、「Ocean/reverse geocoding」を確認してください」 XMLとJSONで利用できます。無料のユーザーアカウントを作成して、デモアカウントの1日あたりの制限を回避します。

海域のリクエスト例(バルト海、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
  }
}
0
hennzen

また、青緑色のことを行い、すべての緑の点を保存して後で検索することもできます。これには、「段階的に」洗練されるという利点があります。ポイントのリストを作成するためのより良い方法を見つけたら、ランダムグラバーをより正確なポイントグループに向けることができます。

多分サービスプロバイダーはあなたの質問にすでに答えを持っています: https://www.google.com/enterprise/marketplace/viewListing?productListingId=3030+17310026046429031496&pli=1

標高API? http://code.google.com/apis/maps/documentation/elevation/ 海抜より上かそれとも下か? (オランダのポイントはありません!)

0
David Thornton

生成は簡単ですが、問題はそれらが水の上にあってはならないということです。たとえば、ここに「Open Streetmap」をインポートします http://ftp.ecki-netz.de/osm/ それをデータベースにインポートします(非常に簡単なデータ構造)。私はPostgreSQLをお勧めします。これにはいくつかのgeo関数が付属しています http://www.postgresql.org/docs/8.2/static/functions-geometry.html 。そのため、ポイントを「ポリゴン」列に保存する必要があります。その後、「&&」演算子を使用して、ポイントがウォーターポリゴンにあるかどうかを確認できます。 OpenStreetmap Way-Entryの属性については、 http://wiki.openstreetmap.org/wiki/Category:En:Keys をご覧ください。

0
wutzebaer

世界地図を使用し、その上にいくつかのポイントを定義してほとんどの水域を区切ることができ、polygon.containsメソッドを使用して座標を検証できると思います。

より高速なアルゴリズムは、このマップを使用し、ランダムな点を取り、その下の色をチェックすることです。青の場合は水、次に座標があれば、それらを緯度/経度に変換します。

0
Snicolas