Coordonnées géographiques aléatoires (sur terre, éviter l'océan)
des idées astucieuses sur la façon de générer des coordonnées aléatoires (latitude / longitude) de lieux sur terre? Latitude / Longitude. Précision à 5 points et éviter les plans d'eau.
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));
peut-être que je vis dans un monde de rêve et le sujet de l'eau est inévitable ... mais espérons qu'il y ait un moyen plus gentil, plus propre et plus efficace de le faire?
EDIT
quelques réponses/idées fantastiques -- cependant, à l'échelle, disons que je dois générer 25,000 coordonner. Le recours à un fournisseur de services externe n'est peut-être pas la meilleure option en raison de la latence, du coût et de quelques autres facteurs.
16 réponses
pour traiter le problème du corps de l'eau va être en grande partie une question de données, par exemple voulez-vous juste manquer les océans ou avez-vous besoin de également manquer de petits cours d'eau. Soit vous avez besoin d'utiliser un service de la qualité des données que vous avez besoin, ou vous avez besoin d'obtenir les données vous-même l'exécuter localement. De votre édition, il semble que vous voulez aller la route des données locales, donc je vais me concentrer sur un moyen de le faire.
une méthode consiste à obtenir un shapefile pour les zones terrestres ou aquatiques. Vous pouvez ensuite générer un point aléatoire et déterminer s'il croise une zone terrestre (ou, alternativement, ne croise pas une zone aquatique).
pour commencer, vous pourriez obtenir des données de basse résolution ici et puis obtenir de plus haute résolution de données ici pour quand vous voulez obtenir de meilleures réponses sur les lignes de côte ou avec les lacs / rivières / etc. Vous avez mentionné que vous voulez de la précision dans vos points à 5 décimales, ce qui est un peu plus de 1m. Soyez conscient que si vous obtenez données pour correspondre à cette précision, vous aurez un jeu de données géant. Et, si vous voulez vraiment de bonnes données, être prêt à payer pour cela.
Une fois que vous avez vos données de forme, vous avez besoin d'outils pour vous aider à déterminer l'intersection de vos points aléatoires. outils géographiques est un excellent point de départ et conviendra probablement à vos besoins. Vous finirez aussi par regarder opengis code (docs sous geotools site-pas sûr s'ils les ont consommés ou quoi) et JTS pour les gestion de la géométrie. En utilisant ceci, vous pouvez rapidement ouvrir le shapefile et commencer à faire des requêtes d'intersection.
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 );
explications rapides:
- ceci suppose que le shapefile que vous avez obtenu est des données polygonales. L'Intersection sur des lignes ou des points ne va pas vous donner ce que vous voulez.
- première section ouvre le shapefile-rien d'intéressant
- vous devez récupérer le nom de la propriété geometry pour le fichier donné
- système de coordonnées stuff-vous avez spécifié lat / long dans votre post mais GIS peut être un peu plus compliqué. En général, les données que je vous ai indiquées sont géographique wgs84, et, c'est ce que j'ai paramétré ici. Toutefois, si ce n'est pas le cas pour vous, alors vous devez être sûr que vous faites affaire avec vos données dans le bon système de coordonnées. Si tout cela ressemble à du charabia, cherchez un tutoriel sur les SIG/systèmes de coordonnées/système de référence/ellipsoïde sur google around.
- générant les géométries de coordonnées et les filtres sont assez explicites. L'ensemble des caractéristiques résultantes sera soit vide, ce qui signifie que la coordonnée est dans l'eau si vos données sont la couverture terrestre, ou pas vide, ce qui signifie le contraire.
Remarque: si vous faites cela avec un ensemble aléatoire de points, vous allez toucher de l'eau assez souvent et il pourrait vous prendre un certain temps pour obtenir à 25k points. Vous pouvez essayer de définir votre génération de points mieux que vraiment aléatoire (comme supprimer de grands morceaux de la Atlantique / Pacifique / océan Indien).
En outre, vous pouvez trouver que vos requêtes d'intersection sont trop lentes. Si c'est le cas, vous pouvez envisager de créer un index quadtree (qix) avec un outil comme GDAL. Je ne me souviens pas quels types d'index sont supportés par les géotools, cependant.
- téléchargez un truckload de fichiers KML contenant des localisations terrestres.
- extraire toutes les coordonnées d'eux cela peut aider à ici.
- Les choisir au hasard.
Cela a demandé il y a longtemps et j'ai maintenant besoin similaire. Il y a deux possibilités que j'examine:
1. Définissez les portées de surface pour le générateur aléatoire.
Ici, il est important d'identifier le niveau de précision que vous allez pour. Le plus simple serait d'avoir un très détendue et approximative approche. Dans ce cas, vous pouvez diviser la carte du monde en des "boîtes":
chaque boîte a sa propre gamme de lat lon. Ensuite, vous Randomisez d'abord pour obtenir une boîte aléatoire, puis vous Randomisez pour obtenir un lat aléatoire et aléatoire long dans les limites de cette boîte.
la précision n'est évidemment pas la meilleure ici... Bien que cela dépende:) si vous faites bien vos devoirs et définissez beaucoup de boîtes couvrant la plupart des formes de surface complexes - vous pourriez être tout à fait ok avec le précision.
2. Élément de liste
une API pour retourner le nom du continent à partir des coordonnées ou de l'adresse ou du pays ou du district = quelque chose que L'eau n'a pas. Les API GoogleMaps peuvent vous aider ici. Je n'ai pas fait de recherche plus approfondie, mais je pense que c'est possible, même si vous devrez vérifier chaque paire de coordonnées générée et recommencer si c'est faux. Si vous pouvez obtenir un peu coincé si le générateur aléatoire garde à vous jeter dans l'océan.
également - certaines eaux appartiennent à des pays, des districts...donc oui, pas très précis.
Pour mes besoins, je vais avec les "boîtes" parce que je veux aussi le contrôle exact des zones dont le hasard les coordonnées sont prises et ne me dérange pas si il tombe sur un lac ou une rivière, tout simplement pas de l'océan ouvert:)
vous devriez certainement avoir une carte comme ressource. Vous pouvez le prendre ici: http://www.naturalearthdata.com/
puis je préparais 1bit noir et blanc bitmap ressource avec 1S marquage de la terre et 0x marquage de l'eau.
la taille de bitmap dépend de votre précision. Si vous avez besoin de 5 degrés alors votre bitmap sera 360/5 x 180/5 = 72x36 pixels = 2592 bits.
alors je chargerais ce bitmap en Java, générerais un entier aléatoire avec portée au-dessus, lecture bit, et régénérer si elle était zéro.
P.S. vous pouvez aussi creuser ici http://geotools.org/ pour quelques solutions toutes faites.
il y a une autre façon d'aborder cela en utilisant L'Api Google Earth. Je sais que c'est du javascript, mais je pensais que c'était une nouvelle façon de résoudre le problème.
de toute façon, j'ai mis en place une solution de travail d'ici l'avis qu'il fonctionne pour les rivières trop: http://www.msa.mmu.ac.uk/~fraser/ge/coord/
l'idée de base que j'ai utilisée est d'implémenter le méthode hiTest geview object dans le Google Earth Api.
jetez un oeil à l'exemple suivant de la hitest de Google. http://earth-api-samples.googlecode.com/svn/trunk/examples/hittest.html
la méthode hitTest fournit un point aléatoire sur l'écran en (coordonnées pixel) pour lequel elle renvoie un objet GEHitTestResult qui contient des informations sur l'emplacement géographique correspondant au point. Si on utilise la GEPlugin.Le mode HIT_TEST_TERRAIN avec la méthode on peut limiter les résultats seulement à la terre (terrain) aussi longtemps que nous scrutons les résultats à des points avec une altitude > 1m
C'est la fonction que j'utilise qui implémente le plus de 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 };
};
évidemment vous voulez aussi avoir des résultats aléatoires de n'importe où sur le globe (pas seulement des points aléatoires visibles d'un seul point de vue). Pour ce faire, je déplace la vue de la terre après chaque succès hitTestTerrain
appel. Ceci est réalisé en utilisant une petite fonction d'aide.
var flyTo = function(lat, lng, rng)
{
lookAt.setLatitude(lat);
lookAt.setLongitude(lng);
lookAt.setRange(rng);
ge.getView().setAbstractView(lookAt);
};
Enfin, voici une version allégée de le bloc de code principal qui appelle ces deux méthodes.
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();
}
};
ainsi, la terre se déplace aléatoirement vers une position
les autres fonctions ne sont que des helpers pour générer des X,y et lat aléatoires,des nombres lng, pour afficher les résultats et aussi pour basculer les contrôles etc.
j'ai testé le code un peu et les résultats ne sont pas parfaits à 100%, peaufinant le altitude
à quelque chose de plus haut, comme 50m résout ceci mais évidemment il diminue la zone de possible coordonnées.
évidemment, vous pouvez adapter l'idée pour répondre à vos besoins. Peut-être lancer le code plusieurs fois pour alimenter une base de données ou quelque chose.
pour obtenir une distribution uniforme agréable sur les latitudes et les longitudinales, vous devriez faire quelque chose comme ça pour obtenir les angles droits:
double longitude = Math.random() * Math.PI * 2;
double latitude = Math.acos(Math.random() * 2 - 1);
pour éviter les plans d'eau, avez-vous des données pour les cas où l'eau est déjà? Rééchantillonne jusqu'à ce que tu aies un résultat! Si vous ne disposez pas déjà de ces données, il semble que d'autres personnes aient de meilleures suggestions que moi...
J'espère que cela vous aidera, santé.
en tant que plan B, vous pouvez peut-être choisir un pays au hasard et ensuite choisir une coordonnée aléatoire à l'intérieur de ce pays. Pour être juste quand vous choisissez un pays, vous pouvez utiliser sa zone comme poids.
Il y a une bibliothèque iciGeoNames WebServices pour déterminer si elle est sur terre ou non. Ils ont une liste de services web et vous aurez juste à utiliser la bonne. GeoNames est gratuit et fiable.
- il y a http://wiki.openstreetmap.org/
- Essayez d'utiliser l'API: http://wiki.openstreetmap.org/wiki/Databases_and_data_access_APIs
je suppose que vous pourriez utiliser une carte du monde, définir quelques points dessus pour délimiter la plupart des plans d'eau comme vous le dites et utiliser un polygone.contient méthode pour valider les coordonnées.
un algorithme plus rapide serait d'utiliser cette carte, de prendre un point aléatoire et de vérifier la couleur en dessous, si elle est bleue, puis l'eau... quand vous avez les coordonnées, vous les convertissez en lat / long.
vous pouvez aussi faire le truc bleu vert , puis stocker tous les points verts pour plus tard regarder vers le haut. Cela a l'avantage d'être "progressif" utilisable dans une recherche approfondie. Comme vous trouver une meilleure façon de faire votre liste de points que vous pouvez simplement pointer votre aléatoires graber plus et plus précis d'un groupe de points.
peut-être qu'un fournisseur de services a déjà une réponse à votre question: par exemple https://www.google.com/enterprise/marketplace/viewListing?productListingId=3030+17310026046429031496&pli=1