Si te ves en la necesidad de generar puntos aleatorios en una zona en concreta, pero además tienes la restricción de que todos los puntos tienen que ser en una zona donde haya agua, igual la siguiente guía te ayuda. Así es como lo hice yo:
En primer lugar obtener todas las líneas que separan la tierra y el agua (en mi caso con las líneas de costa me llegaba). El lugar con datos libres y con mayor detalle lo he encontrado en la web de OpenStreetMapData en el siguiente enlace: Water polygons
Para recortar la zona que me interesaba utilicé el software libre QGIS. Nunca antes había usado ese software, pero siguiendo el tutorial "Tutorial for creating polygons in QGIS" conseguí mi objetivo muy fácilmente.
En el punto 6 del tutorial, explica como cargar los datos descargados de OpenStreetMapData.
En el punto 8 como dibujar un polígono que delimitará la zona sobre la que se está interesado.
Después utilizando el polígono se puede recortar una zona del mapa generando la forma deseada.
Para exportar la forma obtenida (SHP) a formato WKT solo hay que seguir el siguiente artículo: "Cómo convertir un shapefile en WKT"
Una vez se ha obtenido el WKT ya se puede generar desde .Net puntos aleatorios entre la mínima y la máxima latitud y entre la mínima y máxima longitud de la figura y comprobar si el punto obtenido está dentro de la figura (ya que si la forma es irregular puede que cuadre fuera)
public static double GetRandomDouble(Random rnd, double minimum, double maximum) { return rnd.NextDouble() * (maximum - minimum) + minimum; } public static DbGeography GetRandomPointInZone(DbGeography validZone,Random rnd) { DbGeography pos = null; double minlat = double.MaxValue; double maxlat = double.MinValue; double minlon = double.MaxValue; double maxlon = double.MinValue; for (int i = 1; i <= validZone.PointCount; i++) { var point = validZone.PointAt(i); if (point.Latitude != null && minlat > point.Latitude) minlat = (double)point.Latitude; if (point.Longitude != null && minlon > point.Longitude) minlon = (double)point.Longitude; if (point.Latitude != null && maxlat < point.Latitude) maxlat = (double)point.Latitude; if (point.Longitude != null && maxlon < point.Longitude) maxlon = (double)point.Longitude; } int retry = 0; while (pos == null || !pos.Intersects(validZone)) //Aquí comprobamos que la posición aleatoria está dentro de la zona. { var latitude = GetRandomDouble(rnd, minlat, maxlat); var longitude = GetRandomDouble(rnd, minlon, maxlon); var wkt = String.Format("POINT({0} {1})", longitude.ToString(CultureInfo.InvariantCulture), latitude.ToString(CultureInfo.InvariantCulture)); pos = DbGeography.PointFromText(wkt, 4326); retry++; if (retry > 1000) throw new Exception("Parece un bucle infinito, tras 1000 reintentos no se ha podido obtener una posición dentro de la zona válida"); } return pos; } static void Main(string[] args) { var rnd = new Random(); var validZone = DbGeography.PolygonFromText(ConfigurationManager.AppSettings["ValidZone"], 4326); var posRandom = GetRandomPointInZone(validZone, rnd); Console.WriteLine("Posición aleatoria dentro de zona: Latitud {0}, Longitud {1}",posRandom.Latitude,posRandom.Longitude); Console.ReadKey(); }En mi caso necesitaba ir generando los puntos aleatorios desde código en C#. Si en tu caso eso no es necesario, utiliza el propio QGIS para generar puntos aleatorios. Seguro que lo hace de una forma mucho más eficiente ;)
0 comentarios:
Publicar un comentario