webentwicklung-frage-antwort-db.com.de

Zufällige geographische Koordinaten (an Land, Meere meiden)

Irgendeine clevere Idee, wie man zufällige Koordinaten (Breitengrad/Längengrad) von Orten auf der Erde generiert? Breitengrad/Längengrad Präzision auf 5 Punkte und vermeiden Sie Gewässer. 

    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));

Vielleicht lebe ich in einer Traumwelt und das Thema Wasser ist unvermeidlich ... aber hoffentlich gibt es eine schönere, sauberere und effizientere Möglichkeit, dies zu tun?

EDIT

Einige fantastische Antworten/Ideen - aber im großen Maßstab, ich muss 25.000 Koordinaten generieren. Ein Wechsel zu einem externen Dienstanbieter ist aufgrund von Latenz, Kosten und einigen anderen Faktoren möglicherweise nicht die beste Option. 

29
sdolgy

Das Problem des Wasserkörpers zu lösen, wird weitgehend ein Datenproblem sein, z. Möchten Sie nur die Ozeane vermissen, oder müssen Sie auch kleine Bäche vermissen. Entweder müssen Sie einen Dienst mit der Datenqualität verwenden, den Sie benötigen, oder Sie müssen die Daten selbst abrufen und lokal ausführen. In Ihrer Bearbeitung klingt das so, als wollten Sie die lokale Datenroute gehen, also konzentriere ich mich auf einen Weg, dies zu tun.

Eine Methode besteht darin, ein Shapefile für Landbereiche oder Wassergebiete zu erhalten. Sie können dann einen zufälligen Punkt generieren und bestimmen, ob er eine Landfläche schneidet (oder alternativ keine Wasserfläche schneidet).

Um zu beginnen, erhalten Sie möglicherweise Daten mit niedriger Auflösung hier und dann Daten mit höherer Auflösung hier , wenn Sie bessere Antworten an Küstenlinien oder mit Seen/Flüssen/etc erhalten möchten. Sie haben erwähnt, dass Sie eine Genauigkeit von 5 Dezimalstellen in Ihren Punkten wünschen, etwas mehr als 1 Meter. Seien Sie sich bewusst, dass, wenn Sie Daten erhalten, die dieser Genauigkeit entsprechen, ein riesiger Datensatz vorhanden ist. Und wenn Sie wirklich gute Daten haben wollen, seien Sie bereit, dafür zu bezahlen.

Sobald Sie Ihre Formdaten haben, benötigen Sie einige Tools, mit denen Sie den Schnittpunkt Ihrer zufälligen Punkte bestimmen können. Geotools ist ein großartiger Startplatz und wird wahrscheinlich für Ihre Bedürfnisse funktionieren. Am Ende werden Sie auch Opengis-Code (Dokumente unter der Geotools-Site - nicht sicher, ob sie diese konsumiert haben oder was verwendet haben) und JTS für die Geometriebehandlung betrachten. Damit können Sie das Shapefile schnell öffnen und einige Kreuzungsabfragen starten.

    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 );

Kurze Erklärungen:

  1. Dies setzt voraus, dass das Shapefile Polygondaten ist. Überschneidungen von Linien oder Punkten geben Ihnen nicht das, was Sie wollen.
  2. Erster Abschnitt öffnet das Shapefile - nichts Interessantes
  3. sie müssen den Namen der Geometrieeigenschaft für die angegebene Datei abrufen
  4. koordinatensystem - Du hast lat/long in deinem Beitrag angegeben, aber GIS kann etwas komplizierter sein. Im Allgemeinen sind die Daten, auf die ich Sie hingewiesen habe, geographic, wgs84 , und das ist, was ich hier einrichte. Wenn dies jedoch nicht der Fall ist, müssen Sie sicherstellen, dass Sie Ihre Daten im richtigen Koordinatensystem verwenden. Wenn das alles nach Kauderwelsch klingt, suchen Sie nach einem Tutorial zu GIS/Koordinatensystemen/Datum/Ellipsoid.
  5. das Erzeugen der Koordinatengeometrien und der Filter ist ziemlich selbsterklärend. Der resultierende Satz von Features ist entweder leer, dh die Koordinate befindet sich im Wasser, wenn Ihre Daten Landbedeckung haben, oder nicht leer, was das Gegenteil bedeutet.

Hinweis: Wenn Sie dies mit einer wirklich zufälligen Anzahl von Punkten tun, werden Sie ziemlich oft auf Wasser treffen und es kann eine Weile dauern, bis Sie 25.000 Punkte erreicht haben. Vielleicht möchten Sie versuchen, Ihre Punktgenerierung besser als wirklich zufällig zu erfassen (z. B. große Brocken des Atlantik/Pazifik/Indischen Ozeans entfernen).

Möglicherweise stellen Sie außerdem fest, dass Ihre Kreuzungsabfragen zu langsam sind. Wenn ja, möchten Sie vielleicht mit einem Tool wie GDAL einen quadtree-Index (qix) erstellen. Ich kann mich jedoch nicht erinnern, welche Indextypen von Geotools unterstützt werden.

14
philwb

Das wurde vor langer Zeit gefragt und ich habe jetzt das gleiche Bedürfnis. Es gibt zwei Möglichkeiten, die ich untersuche:

1. Definieren Sie die Flächenbereiche für den Zufallsgenerator.

Hier ist es wichtig, die Genauigkeit zu bestimmen, die Sie anstreben. Der einfachste Weg wäre ein sehr entspannter und angenehmer Ansatz. In diesem Fall können Sie die Weltkarte in "Boxen" unterteilen:

 enter image description here

Jede Box hat ein eigenes Sortiment. Dann werden Sie zuerst zufällig ausgewählt, um eine zufällige Box zu erhalten, und dann zufällig, um eine zufällige Länge und eine zufällige Länge innerhalb der Grenzen dieser Box zu erhalten. 

Präzision ist hier natürlich nicht die beste ... Obwohl es darauf ankommt :) Wenn Sie Ihre Hausaufgaben gut machen und viele Kästchen definieren, die die komplexesten Oberflächenformen abdecken, sind Sie mit der Genauigkeit möglicherweise in Ordnung.

2. Listeneintrag

Einige API, um den Kontinentnamen aus den Koordinaten OR Adresse OR Land OR Bezirk = etwas zurückzugeben, das WASSER nicht hat. Google Maps APIs können hier helfen. Ich habe hier nicht weiter recherchiert, aber ich denke, es ist möglich, obwohl Sie die Überprüfung für jedes generierte Koordinatenpaar durchführen müssen und IF erneut ausführen, wenn es falsch ist. So können Sie ein bisschen stecken bleiben, wenn der Zufallsgenerator Sie weiter in den Ozean wirft.

Auch - etwas Wasser gehört zu Ländern, Bezirken ... also ja, nicht sehr präzise. 

Für meine Bedürfnisse - ich gehe mit "Boxen", weil ich auch genaue Bereiche kontrollieren möchte, aus denen die zufälligen Koordinaten entnommen werden, und es macht nichts aus, wenn sie an einem See oder Fluss landen, nur nicht am offenen Meer :)

4
GeekSince1982
  1. Laden Sie eine Vielzahl von KML-Dateien mit Landstandorten herunter.
  2. Extrahieren Sie alle Koordinaten dies könnte hier helfen .
  3. Wähle sie zufällig aus.
4
OldCurmudgeon

Auf jeden Fall sollten Sie eine Karte als Ressource haben. Sie können es hier nehmen: http://www.naturalearthdata.com/

Dann würde ich 1-Bit-Schwarzweiß-Bitmap-Ressource mit 1s Markierungsland und 0x Markierungswasser vorbereiten.

Die Größe der Bitmap hängt von Ihrer erforderlichen Genauigkeit ab. Wenn Sie 5 Grad benötigen, ist Ihre Bitmap 360/5 x 180/5 = 72x36 Pixel = 2592 Bit. 

Dann würde ich diese Bitmap in Java laden, eine zufällige ganze Zahl mit einem oberen Bereich erzeugen, das Bit lesen und neu generieren, wenn es Null wäre.

P.S. Sie können auch hier http://geotools.org/ nach ein paar fertigen Lösungen suchen.

3
Suzan Cioc

Es gibt eine andere Möglichkeit, dies mithilfe der Google Earth-API zu erreichen. Ich weiß, dass es Javascript ist, aber ich dachte, es sei eine neuartige Möglichkeit, das Problem zu lösen.

Wie auch immer, ich habe hier eine voll funktionsfähige Lösung zusammengestellt - beachte, dass es auch für Flüsse funktioniert: http://www.msa.mmu.ac.uk/~fraser/ge/coord/

Die Grundidee, die ich verwendet habe, ist das Implementieren der hiTest-Methode des GEView-Objekts in der Google Earth-API

Schauen Sie sich das folgende Beispiel für den Hitest von Google an: http://earth-api-samples.googlecode.com/svn/trunk/examples/hittest.html

Der hitTest-Methode wird ein zufälliger Punkt auf dem Bildschirm in (Pixelkoordinaten) bereitgestellt, für den ein GEHitTestResult-Objekt zurückgegeben wird, das Informationen zu dem geografischen Ort enthält, der dem Punkt entspricht. Wenn Sie den Modus GEPlugin.HIT_TEST_TERRAIN mit der Methode verwenden, können Sie die Ergebnisse nur auf Land (Gelände) beschränken, solange wir die Ergebnisse auf Punkte mit einer Höhe> 1m überprüfen

Diese Funktion verwende ich für 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 };
};

Natürlich möchten Sie auch willkürliche Ergebnisse von überall auf der Welt haben (nicht nur zufällige Punkte, die von einem einzigen Standpunkt aus sichtbar sind). Dazu verschiebe ich die Erdansicht nach jedem erfolgreichen Aufruf von hitTestTerrain. Dies wird mit einer kleinen Hilfsfunktion erreicht.

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

Schließlich ist hier eine abgespeckte Version des Hauptcodeblocks, der diese beiden Methoden aufruft.

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();
    }
};

Die Erde bewegt sich also zufällig zu einer Position

Die anderen Funktionen sind nur Hilfsmittel, um die Zufallszahlen x, y und zufällig lat, lng zu generieren, die Ergebnisse auszugeben und auch die Steuerelemente umzuschalten usw.

Ich habe den Code ziemlich getestet und die Ergebnisse sind nicht 100% ig perfekt. Ich ändere den altitude auf etwas Höheres, wie 50m, löst dies aber offensichtlich verringert es den Bereich der möglichen ausgewählten Koordinaten. 

Natürlich können Sie die Idee an Ihre Bedürfnisse anpassen. Möglicherweise wird der Code mehrmals ausgeführt, um eine Datenbank oder etwas zu füllen. 

3
Fraser

Um eine gleichmäßige Verteilung von Nizza über Breiten- und Längengrade zu erhalten, sollten Sie Folgendes tun, um die richtigen Winkel zu erhalten:

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

Haben Sie zur Vermeidung von Gewässern die Daten, wo sich bereits Wasser befindet? Nun, probieren Sie es einfach neu, bis Sie einen Treffer erhalten! Wenn Sie diese Daten noch nicht haben, scheinen andere Leute bessere Vorschläge zu haben als ich ...

Hoffe, das hilft, Prost.

2
Elias Vasylenko

Als Plan B können Sie vielleicht ein zufälliges Land auswählen und dann eine zufällige Koordinate innerhalb dieses Landes auswählen. Um bei der Auswahl eines Landes fair zu sein, können Sie seine Fläche als Gewicht verwenden.

2
cassioso

Es gibt eine Bibliothek hier , und Sie können die .random () - Methode verwenden, um eine zufällige Koordinate zu erhalten. Dann können Sie mit GeoNames WebServices feststellen, ob es sich an Land befindet oder nicht. Sie haben eine Liste von Webservices und Sie müssen nur die richtigen verwenden. GeoNames ist kostenlos und zuverlässig. 

1
bsimic
1
Kamil

Ergänzend zu dem, was bsimic über das Eingraben in GeoNames-Webservices gesagt hat, hier eine Abkürzung:
Sie haben einen dedizierten WebService zum Anfordern eines Ozeannamens .

(Ich bin mir der Einschränkung durch OP bewusst, dass nicht öffentliche Webservices aufgrund der Menge an Anfragen verwendet werden sollten. Trotzdem bin ich mit derselben grundlegenden Frage darauf gestoßen und halte dies für hilfreich.)

Gehen Sie zu http://www.geonames.org/export/web-services.html#astergdem und werfen Sie einen Blick auf "Ocean/Reverse Geocoding". Es ist als XML und JSON verfügbar. Erstellen Sie ein kostenloses Benutzerkonto, um Tageslimits für das Demokonto zu verhindern.

Anforderungsbeispiel zum Meeresgebiet (Ostsee, JSON-URL):

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

führt in

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

während einige Koordinaten an Land ergeben

{
  "status": {
    "message": "we are afraid we could not find an ocean for latitude and longitude :53.0,9.0",
    "value": 15
  }
}
0
hennzen

Sie können auch das blaugrüne Ding ausführen und dann alle grünen Punkte für eine spätere Suche speichern. Dies hat den Vorteil, dass es "schrittweise" verfeinert werden kann. Wenn Sie herausfinden, wie Sie Ihre Liste mit Punkten verbessern können, können Sie Ihren Zufallsgreifer auf eine immer genauere Gruppe von Punkten richten.

Möglicherweise hat ein Dienstanbieter bereits eine Antwort auf Ihre Frage: z. https://www.google.com/enterprise/marketplace/viewListing?productListingId=3030+17310026046429031496&pli=1

Elevation api? http://code.google.com/apis/maps/documentation/elevation/ über dem Meeresspiegel oder darunter? (keine niederländischen Punkte für Sie!)

0
David Thornton

Das Generieren ist einfach, das Problem ist, dass sie nicht auf dem Wasser sein sollten. Ich würde die "Open Streetmap" beispielsweise hier http://ftp.ecki-netz.de/osm/ importieren und in eine Datenbank importieren (sehr einfache Datenstruktur). Ich würde vorschlagen, PostgreSQL, es kommt mit einigen Geo-Funktionen http://www.postgresql.org/docs/8.2/static/functions-geometry.html . Dafür müssen Sie die Punkte in einer "Polygon" -Spalte speichern, dann können Sie mit dem Operator "&&" prüfen, ob es sich um ein Wasser-Polygon handelt. Die Attribute eines OpenStreetmap-Wegeintrags finden Sie unter http://wiki.openstreetmap.org/wiki/Category:En:Keys

0
wutzebaer

Ich denke, Sie könnten eine Weltkarte verwenden, einige Punkte definieren, um die meisten Gewässer zu begrenzen, und die Methode polygon.contains verwenden, um die Koordinaten zu bestätigen.

Ein schnellerer Algorithmus wäre, diese Karte zu verwenden, einen zufälligen Punkt zu nehmen und die Farbe darunter zu überprüfen. Wenn es blau ist, dann Wasser ... Wenn Sie die Koordinaten haben, konvertieren Sie sie in lat/long.

0
Snicolas