Frage

Ich habe dieses Bild: http://imgur.com/99tsz.png. Eine Karte des Vereinigten Königreichs (ohne Südirland).

Ich habe es erfolgreich geschafft, einen Breitengrad und Längengrad auf diese Karte zu bringen, indem ich den linken Längengrad und rechts langen Längengrad Großbritanniens einnehme und sie benutzte, um herauszufinden, wo ich den Punkt auf die Karte setzen soll.

Dies ist der Code (zur Verwendung in der Verarbeitung.js, kann aber als JS oder irgendetwas verwendet werden):

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

}

Ich konnte jedoch keine Mercator -Projektion für diese Werte implementieren. Die Handlungen sind einigermaßen genau, aber sie sind nicht gut genug und diese Projektion würde sie lösen.

Ich kann nicht herausfinden, wie es geht. Alle Beispiele, die ich finde, erklären, wie man es für die ganze Welt macht. Dies ist eine gute Beispiele für Beispiele, die erklären, wie man die Projektion implementiert, aber ich konnte sie nicht zum Laufen bringen.

Eine andere Ressource ist die Extrempunkte des Vereinigten Königreichs wo ich die Breiten- und Längengradwerte des Begrenzungsbox in Großbritannien bekam. Sie sind auch hier:

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

Wenn mir jemand dabei helfen könnte, würde ich es sehr schätzen!

Vielen Dank

War es hilfreich?

Lösung

Ich denke, es lohnt sich zu berücksichtigen, dass nicht alle flachen Karten Mercator -Projektionen sind. Ohne insbesondere mehr über diese Karte zu wissen, ist es schwierig, sicher zu sein. Sie können feststellen, dass die meisten Karten eines kleinen Gebiets der Welt eher a sind konisch Typprojektion, wobei der Interessenbereich auf der Karte "flacher" ist, als auf einer globalen Mercator -Projektion. Dies ist besonders wichtiger, je weiter Sie sich vom Äquator entfernen (und Großbritannien ist weit genug weg, um es zu tun).

Möglicherweise können Sie mit den Berechnungen, die Sie ausprobieren, "nah genug" bekommen. Für die beste Genauigkeit möchten Sie jedoch entweder eine Karte mit einer gut definierten Projektion verwenden oder Ihre eigene Karte erstellen.

Andere Tipps

Ich habe eine Funktion geschrieben, die genau das macht, wonach Sie gesucht haben. Ich weiß, dass es ein bisschen spät ist, aber vielleicht sind einige andere Leute interessiert.

Sie benötigen eine Karte, die eine Mercator -Projektion ist und die LAT / LON -Positionen Ihrer Karte kennen. Sie erhalten großartige maßgeschneiderte Mercator -Karten mit perfekten passenden LAT / LON -Positionen von Tilemill Welches ist eine kostenlose Software von MAPBOX!

Ich verwende dieses Skript und habe es mit einigen Google Earth -Positionen getestet. Es hat auf einer Pixelebene perfekt funktioniert. Eigentlich habe ich dies nicht auf verschiedenen oder größeren Karten getestet. Ich hoffe es hilft dir!

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

?>

Hier ist das Bild, das ich mit Tilemill erstellt habe und das ich in diesem Beispiel verwendet habe: map image

Zusätzlich zu dem, was Raphael Wichmann gepostet hat (danke, übrigens!), Hier ist die umgekehrte Funktion in ActionsScript:

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

Ich habe den von Raphael bereitgestellten PHP -Code in JavaScript konvertiert und kann bestätigen, dass er funktioniert hat und dieser Code selbst funktioniert. Alle Anerkennung für Raphael.

/*
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};
}

Hier ist eine weitere JavaScript -Implementierung. Dies ist eine Vereinfachung der oben genannten Lösung von @Rob Willet. Anstatt berechnete Werte als Parameter für die Funktion zu verlangen, erfordert es nur wesentliche Werte und berechnet alles von ihnen:

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
}

Ich weiß, dass die Frage vor einiger Zeit gestellt wurde, aber die ProJ4JS -Bibliothek ist ideal, um zwischen verschiedenen Kartenprojektionen in JavaScript zu transformieren.

UK -Karten neigen dazu, das National Grid des OSGB zu verwenden, das auf einer Querzersierung basiert. Dh. Wie ein herkömmlicher Mercator wurde aber 90 Grad, so dass der "Äquator" zum Meridian wird.

@Xarinko ActionScript -Snippet in JavaScript (mit einigen Testwerten)

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)

Wenn Sie einige der unordentlicheren Aspekte von LAT/LNG-Projektionen vermeiden möchten, die für Proj4Js intrinsisch sind, können Sie D3 verwenden, was viele eingebackene Projektionen bietet und wunderbar macht. Hier ist ein Interaktives Beispiel von mehreren Geschmacksrichtungen azimutaler Projektionen. Ich bevorzuge Albers für USA Maps.

Wenn D3 keine Endbenutzeroption ist-beispielsweise, müssen Sie IE 7/8 unterstützen-Sie können in D3 rendern und dann die XY-Koordinaten aus der resultierenden SVG-Datei, die D3 generiert, ausschnappen. Sie können dann diese XY -Koordinaten in Raphael rendern.

Diese Funktion funktioniert hervorragend für mich, weil ich das Mapheight basierend auf der Karte definieren möchte, die ich zeichnen möchte. Ich generiere PDF -Karten. Alles was ich tun muss, ist in der Max Lat, Min Lon der Karte zu passieren, und es gibt die Pixelgröße für die Karte als [Höhe, Breite] zurück.

Convertgeotopixel (Maxlatitude, Maxlongitude)

Ein Hinweis im letzten Schritt, in dem $ y festgelegt wird, subtrahieren Sie die Berechnung nicht vom Mapheight, wenn Ihr Koordinatensystem 'XY' unten/links startet, wie bei PDFs, dadurch wird die Karte umgebaut.

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

C# Implementierung:

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)
    };
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top