Domanda

Ho questa immagine: http://imgur.com/99tSz.png . Una mappa del Regno Unito (esclusa l'Irlanda del Sud).

Sono riuscito con successo per ottenere una latitudine e longitudine e tracciarla su questa mappa prendendo il più a sinistra e più a destra longitudine longitudine del Regno Unito e li utilizzano per lavorare fuori dove mettere il punto sulla mappa.

Questo è il codice (per l'uso in Processing.js ma potrebbe essere utilizzato come js o niente):

// Size of the map
int width = 538;
int height = 811;
// X and Y boundaries
float westLong = -8.166667;
float eastLong = 1.762833;
float northLat = 58.666667;
float southLat = 49.95;

void drawPoint(float latitude, float longitude){

 fill(#000000);

 x = width * ((westLong-longitude)/(westLong-eastLong));
 y = (height * ((northLat-latitude)/(northLat-southLat)));

 console.log(x + ", " + y);
 ellipseMode(RADIUS);
 ellipse(x, y, 2, 2);    

}

Tuttavia, non sono stati in grado di attuare una proiezione Mercator su questi valori. Le trame sono ragionevolmente accurata, ma non sono abbastanza buone e questa proiezione sarebbe risolverlo.

Non riesco a capire come farlo. Tutti gli esempi che trovo stanno spiegando come si fa per il mondo intero. Questa è una buona risorsa di esempi che spiegano come implementare la proiezione, ma non sono stato in grado di farlo funzionare.

Un'altra risorsa è il punti estremi del Regno Unito dove ho ottenuto i valori di latitudine e longitudine del rettangolo di selezione intorno al Regno Unito. Essi sono anche qui:

northLat = 58.666667; 
northLong = -3.366667; 
eastLat = 52.481167; 
eastLong = 1.762833; 
southLat = 49.95;
southLong = -5.2; 
westLat = 54.45;
westLong = -8.166667;

Se qualcuno mi potrebbe aiutare con questo, sarei molto grato!

Grazie

È stato utile?

Soluzione

Credo che vale la pena di tenere a mente che non tutte le mappe piatte sono proiezioni di Mercatore. Senza sapere di più su quella mappa, in particolare, è difficile essere sicuri. Potreste scoprire che la maggior parte delle mappe di una piccola area del mondo hanno maggiori probabilità di essere un conica tipo di proiezione, dove l'area di interesse sulla mappa è "adulare" di quanto sarebbe su una proiezione globale di Mercatore . Ciò è particolarmente più importante quanto più ci si allontanarsi dall'equatore (e nel Regno Unito è abbastanza lontano per la sua importanza).

Si può essere in grado di ottenere "abbastanza vicino" utilizzando i calcoli che si sta cercando, ma per una maggiore precisione è possibile usare sia per una mappa con una proiezione ben definita, o creare la propria mappa.

Altri suggerimenti

ho scritto una funzione che fa esattamente quello che stavi cercando. Lo so che è un po 'tardi, ma forse ci sono alcune altre persone interessate.

Hai bisogno di una mappa che è una proiezione di Mercatore e avete bisogno di conoscere le posizioni di latitudine / longitudine della tua mappa. È possibile ottenere grandi mappe Mercator personalizzate con posizioni di corrispondenza lat / lon perfette da TileMill , che è un software gratuito da MapBox

Sto usando questo script e testato con alcune posizioni Earth Google. Ha funzionato perfetto a livello di pixel. A dire il vero non ho prova questo su diverse mappe o più grandi. Spero che ti aiuta!

Raphael;)

<?php

$mapWidth = 1500;
$mapHeight = 1577;

$mapLonLeft = 9.8;
$mapLonRight = 10.2;
$mapLonDelta = $mapLonRight - $mapLonLeft;

$mapLatBottom = 53.45;
$mapLatBottomDegree = $mapLatBottom * M_PI / 180;

function convertGeoToPixel($lat, $lon)
{
    global $mapWidth, $mapHeight, $mapLonLeft, $mapLonDelta, $mapLatBottom, $mapLatBottomDegree;

    $x = ($lon - $mapLonLeft) * ($mapWidth / $mapLonDelta);

    $lat = $lat * M_PI / 180;
    $worldMapWidth = (($mapWidth / $mapLonDelta) * 360) / (2 * M_PI);
    $mapOffsetY = ($worldMapWidth / 2 * log((1 + sin($mapLatBottomDegree)) / (1 - sin($mapLatBottomDegree))));
    $y = $mapHeight - (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY);

    return array($x, $y);
}

$position = convertGeoToPixel(53.7, 9.95);
echo "x: ".$position[0]." / ".$position[1];

?>

Questa è l'immagine che ho creato con TileMill e che ho usato in questo esempio: immagine della mappa

In aggiunta a quanto Raphael Wichmann ha pubblicato (Grazie, tra l'altro!), qui è la funzione inversa, in ActionScript:

function convertPixelToGeo(tx:Number, ty:Number):Point
{   
    /* called worldMapWidth in Raphael's Code, but I think that's the radius since it's the map width or circumference divided by 2*PI  */   
    var worldMapRadius:Number = mapWidth / mapLonDelta * 360/(2 * Math.PI);     
    var mapOffsetY:Number = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian))  ));
    var equatorY:Number = mapHeight + mapOffsetY;   
    var a:Number = (equatorY-ty)/worldMapRadius;

    var lat:Number = 180/Math.PI * (2 * Math.atan(Math.exp(a)) - Math.PI/2);
    var long:Number = mapLonLeft+tx/mapWidth*mapLonDelta;
    return new Point(lat,long);
}

ho convertito il codice PHP fornito da Raffaello a JavaScript e posso confermare che ha funzionato e questo codice me funziona. Tutto il merito a Raffaello.

/*
var mapWidth = 1500;
var mapHeight = 1577;

var mapLonLeft = 9.8;
var mapLonRight = 10.2;
var mapLonDelta = mapLonRight - mapLonLeft;

var mapLatBottom = 53.45;
var mapLatBottomDegree = mapLatBottom * Math.PI / 180;
*/

function convertGeoToPixel(latitude, longitude ,
                           mapWidth , // in pixels
                           mapHeight , // in pixels
                           mapLonLeft , // in degrees
                           mapLonDelta , // in degrees (mapLonRight - mapLonLeft);
                           mapLatBottom , // in degrees
                           mapLatBottomDegree) // in Radians
{
    var x = (longitude - mapLonLeft) * (mapWidth / mapLonDelta);

    latitude = latitude * Math.PI / 180;
    var worldMapWidth = ((mapWidth / mapLonDelta) * 360) / (2 * Math.PI);
    var mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomDegree)) / (1 - Math.sin(mapLatBottomDegree))));
    var y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitude)) / (1 - Math.sin(latitude)))) - mapOffsetY);

    return { "x": x , "y": y};
}

Ecco un altro implementazione JavaScript. Si tratta di una semplificazione della soluzione @ Rob Willet sopra. Invece di richiedere valori calcolati come parametri della funzione, richiede solo valori essenziali e calcola tutto da loro:

function convertGeoToPixel(latitude, longitude,
                  mapWidth, // in pixels
                  mapHeight, // in pixels
                  mapLngLeft, // in degrees. the longitude of the left side of the map (i.e. the longitude of whatever is depicted on the left-most part of the map image)
                  mapLngRight, // in degrees. the longitude of the right side of the map
                  mapLatBottom) // in degrees.  the latitude of the bottom of the map
{
    const mapLatBottomRad = mapLatBottom * Math.PI / 180
    const latitudeRad = latitude * Math.PI / 180
    const mapLngDelta = (mapLngRight - mapLngLeft)

    const worldMapWidth = ((mapWidth / mapLngDelta) * 360) / (2 * Math.PI)
    const mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomRad)) / (1 - Math.sin(mapLatBottomRad))))

    const x = (longitude - mapLngLeft) * (mapWidth / mapLngDelta)
    const y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitudeRad)) / (1 - Math.sin(latitudeRad)))) - mapOffsetY)

    return {x, y} // the pixel x,y value of this point on the map image
}

So che la questione è stato chiesto qualche tempo fa, ma la biblioteca Proj4JS è ideale per trasformare tra le diverse proiezioni cartografiche in JavaScript.

mappe del Regno Unito tendono ad usare National Grid del OSGB che si basa su una proiezione trasversale di Mercatore. Vale a dire. come un convenzionale Mercator ma ruotato di 90 gradi, in modo che il "equatore" diventa un meridiano.

@Xarinko Actionscript frammento in Javascript (con alcuni valori di test)

var mapWidth = 1500;
var mapHeight = 1577;

var mapLonLeft = 9.8;
var mapLonRight = 10.2;
var mapLonDelta = mapLonRight - mapLonLeft;

var mapLatBottom = 53.45;
var mapLatBottomRadian = mapLatBottom * Math.PI / 180;



function convertPixelToGeo(tx, ty)
{   
    /* called worldMapWidth in Raphael's Code, but I think that's the radius since it's the map width or circumference divided by 2*PI  */   
    var worldMapRadius = mapWidth / mapLonDelta * 360/(2 * Math.PI);     
    var mapOffsetY = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian))  ));
    var equatorY = mapHeight + mapOffsetY;   
    var a = (equatorY-ty)/worldMapRadius;

    var lat = 180/Math.PI * (2 * Math.atan(Math.exp(a)) - Math.PI/2);
    var long = mapLonLeft+tx/mapWidth*mapLonDelta;
    return [lat,long];
}

convertPixelToGeo(241,444)

Se si vuole evitare alcuni degli aspetti Messier di proiezioni LAT / intrinseche a Proj4JS, è possibile utilizzare D3, che offre molti cotto-in proiezioni e rende splendidamente. Ecco un esempio interattivo di vari gusti di proiezioni azimutali. Io preferisco Albers per le mappe USA.

Se D3 non è un'opzione per l'utente finale - per esempio, è necessario supportare IE 7/8 - si può rendere in D3 e poi agganciare le coordinate XY dal file SVG risultante che D3 genera. È quindi possibile rendere tali coordinate xy in Raffaello.

Questa funzione è grande per me perché voglio definire il mapHeight basata sulla mappa che voglio tracciare. Sto generando mappe PDF. Tutto quello che devi fare è passare della mappa max Lat, Lon min e restituisce la dimensione pixel per la mappa come [altezza, larghezza].

convertGeoToPixel (maxlatitude, maxlongitude)

Una nota nella fase finale in cui è impostato $ y, non sottrarre il calcolo dal mapHeight se il sistema di coordinate 'xy' inizia in basso / sinistra, come con i file PDF, questo sarà invertire la carta.

$y =  (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY);

C # applicazione:

private Point ConvertGeoToPixel(
    double latitude, double longitude, // The coordinate to translate
    int imageWidth, int imageHeight, // The dimensions of the target space (in pixels)
    double mapLonLeft, double mapLonRight, double mapLatBottom // The bounds of the target space (in geo coordinates)
) {
    double mapLatBottomRad = mapLatBottom * Math.PI / 180;
    double latitudeRad = latitude * Math.PI / 180;

    double mapLonDelta = mapLonRight - mapLonLeft;
    double worldMapWidth = (imageWidth / mapLonDelta * 360) / (2 * Math.PI);
    double mapOffsetY = worldMapWidth / 2 * Math.Log((1 + Math.Sin(mapLatBottomRad)) / (1 - Math.Sin(mapLatBottomRad)));

    double x = (longitude - mapLonLeft) * (imageWidth / mapLonDelta);
    double y = imageHeight - ((worldMapWidth / 2 * Math.Log((1 + Math.Sin(latitudeRad)) / (1 - Math.Sin(latitudeRad)))) - mapOffsetY);

    return new Point()
    {
        X = Convert.ToInt32(x),
        Y = Convert.ToInt32(y)
    };
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top