2013-04-15 15 views
6

Ich habe eine Karte, die eine GeoJSON-Datei verwendet, um die Länder zu zeichnen. Ich möchte dann einen Kreis um jedes Land zentrieren. Aber für Länder mit mehreren Grenzregionen (die USA haben Festland, Hawaii, Alaska) möchte ich den Kreis auf der größten Grenzregion. Ich versuche dies zu tun, indem ich die Bereiche der verschiedenen Grenzregionen vergleiche, aber es funktioniert nicht aus Gründen, die ich nicht verstehen kann.D3: Den Bereich eines Geo-Polygons in d3 finden

Hier ist ein Beispiel aus der GeoJSON, das zeigt, wie Australien mehrere Begrenzungsbereiche hat:

{"type":"Feature","properties":{"name":"Australia"},"geometry":{"type":"MultiPolygon","coordinates":[[[[145.397978,-40.792549],[146.364121,-41.137695],[146.908584,-41.000546],[147.689259,-40.808258],[148.289068,-40.875438],[148.359865,-42.062445],[148.017301,-42.407024],[147.914052,-43.211522],[147.564564,-42.937689],[146.870343,-43.634597],[146.663327,-43.580854],[146.048378,-43.549745],[145.43193,-42.693776],[145.29509,-42.03361],[144.718071,-41.162552],[144.743755,-40.703975],[145.397978,-40.792549]]],[[[143.561811,-13.763656],[143.922099,-14.548311],[144.563714,-14.171176],[144.894908,-14.594458],[145.374724,-14.984976],[145.271991,-15.428205],[145.48526,-16.285672],[145.637033,-16.784918],[145.888904,-16.906926],[146.160309,-17.761655],[146.063674,-18.280073],[146.387478,-18.958274],[147.471082,-19.480723],[148.177602,-19.955939],[148.848414,-20.39121],[148.717465,-20.633469],[149.28942,-21.260511],[149.678337,-22.342512],[150.077382,-22.122784],[150.482939,-22.556142],[150.727265,-22.402405],[150.899554,-23.462237],[151.609175,-24.076256],[152.07354,-24.457887],[152.855197,-25.267501],[153.136162,-26.071173],[153.161949,-26.641319],[153.092909,-27.2603],[153.569469,-28.110067],[153.512108,-28.995077],[153.339095,-29.458202],[153.069241,-30.35024],[153.089602,-30.923642],[152.891578,-31.640446],[152.450002,-32.550003],[151.709117,-33.041342],[151.343972,-33.816023],[151.010555,-34.31036],[150.714139,-35.17346],[150.32822,-35.671879],[150.075212,-36.420206],[149.946124,-37.109052],[149.997284,-37.425261],[149.423882,-37.772681],[148.304622,-37.809061],[147.381733,-38.219217],[146.922123,-38.606532],[146.317922,-39.035757],[145.489652,-38.593768],[144.876976,-38.417448],[145.032212,-37.896188],[144.485682,-38.085324],[143.609974,-38.809465],[142.745427,-38.538268],[142.17833,-38.380034],[141.606582,-38.308514],[140.638579,-38.019333],[139.992158,-37.402936],[139.806588,-36.643603],[139.574148,-36.138362],[139.082808,-35.732754],[138.120748,-35.612296],[138.449462,-35.127261],[138.207564,-34.384723],[137.71917,-35.076825],[136.829406,-35.260535],[137.352371,-34.707339],[137.503886,-34.130268],[137.890116,-33.640479],[137.810328,-32.900007],[136.996837,-33.752771],[136.372069,-34.094766],[135.989043,-34.890118],[135.208213,-34.47867],[135.239218,-33.947953],[134.613417,-33.222778],[134.085904,-32.848072],[134.273903,-32.617234],[132.990777,-32.011224],[132.288081,-31.982647],[131.326331,-31.495803],[129.535794,-31.590423],[128.240938,-31.948489],[127.102867,-32.282267],[126.148714,-32.215966],[125.088623,-32.728751],[124.221648,-32.959487],[124.028947,-33.483847],[123.659667,-33.890179],[122.811036,-33.914467],[122.183064,-34.003402],[121.299191,-33.821036],[120.580268,-33.930177],[119.893695,-33.976065],[119.298899,-34.509366],[119.007341,-34.464149],[118.505718,-34.746819],[118.024972,-35.064733],[117.295507,-35.025459],[116.625109,-35.025097],[115.564347,-34.386428],[115.026809,-34.196517],[115.048616,-33.623425],[115.545123,-33.487258],[115.714674,-33.259572],[115.679379,-32.900369],[115.801645,-32.205062],[115.689611,-31.612437],[115.160909,-30.601594],[114.997043,-30.030725],[115.040038,-29.461095],[114.641974,-28.810231],[114.616498,-28.516399],[114.173579,-28.118077],[114.048884,-27.334765],[113.477498,-26.543134],[113.338953,-26.116545],[113.778358,-26.549025],[113.440962,-25.621278],[113.936901,-25.911235],[114.232852,-26.298446],[114.216161,-25.786281],[113.721255,-24.998939],[113.625344,-24.683971],[113.393523,-24.384764],[113.502044,-23.80635],[113.706993,-23.560215],[113.843418,-23.059987],[113.736552,-22.475475],[114.149756,-21.755881],[114.225307,-22.517488],[114.647762,-21.82952],[115.460167,-21.495173],[115.947373,-21.068688],[116.711615,-20.701682],[117.166316,-20.623599],[117.441545,-20.746899],[118.229559,-20.374208],[118.836085,-20.263311],[118.987807,-20.044203],[119.252494,-19.952942],[119.805225,-19.976506],[120.85622,-19.683708],[121.399856,-19.239756],[121.655138,-18.705318],[122.241665,-18.197649],[122.286624,-17.798603],[122.312772,-17.254967],[123.012574,-16.4052],[123.433789,-17.268558],[123.859345,-17.069035],[123.503242,-16.596506],[123.817073,-16.111316],[124.258287,-16.327944],[124.379726,-15.56706],[124.926153,-15.0751],[125.167275,-14.680396],[125.670087,-14.51007],[125.685796,-14.230656],[126.125149,-14.347341],[126.142823,-14.095987],[126.582589,-13.952791],[127.065867,-13.817968],[127.804633,-14.276906],[128.35969,-14.86917],[128.985543,-14.875991],[129.621473,-14.969784],[129.4096,-14.42067],[129.888641,-13.618703],[130.339466,-13.357376],[130.183506,-13.10752],[130.617795,-12.536392],[131.223495,-12.183649],[131.735091,-12.302453],[132.575298,-12.114041],[132.557212,-11.603012],[131.824698,-11.273782],[132.357224,-11.128519],[133.019561,-11.376411],[133.550846,-11.786515],[134.393068,-12.042365],[134.678632,-11.941183],[135.298491,-12.248606],[135.882693,-11.962267],[136.258381,-12.049342],[136.492475,-11.857209],[136.95162,-12.351959],[136.685125,-12.887223],[136.305407,-13.29123],[135.961758,-13.324509],[136.077617,-13.724278],[135.783836,-14.223989],[135.428664,-14.715432],[135.500184,-14.997741],[136.295175,-15.550265],[137.06536,-15.870762],[137.580471,-16.215082],[138.303217,-16.807604],[138.585164,-16.806622],[139.108543,-17.062679],[139.260575,-17.371601],[140.215245,-17.710805],[140.875463,-17.369069],[141.07111,-16.832047],[141.274095,-16.38887],[141.398222,-15.840532],[141.702183,-15.044921],[141.56338,-14.561333],[141.63552,-14.270395],[141.519869,-13.698078],[141.65092,-12.944688],[141.842691,-12.741548],[141.68699,-12.407614],[141.928629,-11.877466],[142.118488,-11.328042],[142.143706,-11.042737],[142.51526,-10.668186],[142.79731,-11.157355],[142.866763,-11.784707],[143.115947,-11.90563],[143.158632,-12.325656],[143.522124,-12.834358],[143.597158,-13.400422],[143.561811,-13.763656]]]]},"id":"AUS"}, 

Und hier ist der Code, wo ich versuche Bereiche unterschiedlicher Begrenzungs Regionen zu vergleichen. In dieser if Erklärung versuche ich herauszufinden, ob das Land mehr als eine Grenzregion hat (das scheint zu funktionieren) und dann im for Block den größten auszuwählen.

Das Problem: Die "Bereich" -Werte, die ich bekomme, sind alle 0 und coords wird immer aus der ersten Begrenzungsregion ausgewählt, anstatt der größten.

function calculateCountryCenter(country) { 

    var coords; 

    //Check if the country has more than one bounding region. 
    if (country.geometry.coordinates.length > 1) { 

     coords = country.geometry.coordinates[0][0]; 

     var regionArea = path.area(country.geometry.coordinates[0]); 

     for (var i=0; i<country.geometry.coordinates.length; i++) { 
      if (path.area(country.geometry.coordinates[i]) > regionArea) { 

       coords = country.geometry.coordinates[i][0]; 
      } 
     }  

    } else {  
     coords = country.geometry.coordinates[0]; 
    } 

    var averageCoords = [0,0]; 
    coords.forEach(function(coord) { 
     averageCoords[0] += coord[0] 
     averageCoords[1] += coord[1] 
    }); 

    averageCoords[0] = averageCoords[0]/coords.length 
    averageCoords[1] = averageCoords[1]/coords.length 
    return averageCoords; 

} 

Hier ist die Definition des Pfades.

 var path = d3.geo.path().projection(projection) 

Jede Anleitung würde sehr geschätzt werden. Danke vielmals.

+0

Was meinen Sie mit "nicht arbeiten"? Erhalten Sie Fehlermeldungen? –

+0

Sorry, gute Frage, ich werde meinen ursprünglichen Beitrag bearbeiten. Was nicht funktioniert ist, dass der Wert, den ich für diese Flächenberechnungen bekomme, null zu sein scheint. Und die Kreise werden auf die erste Grenzregion gezogen, egal was passiert. – ACPrice

+0

Können Sie uns bitte auch die Definition von 'Pfad' zeigen? –

Antwort

1

Die Funktion path.area erwartet eine Funktion und funktioniert nicht nur mit einer Koordinatenliste. Der einfachste Weg, um es zum Laufen zu bringen, ist wahrscheinlich, das ursprüngliche Objekt zu kopieren, alle Koordinaten zu löschen, an denen Sie nicht interessiert sind, und dieses an path.area weiterzugeben. Der Code würde ungefähr so ​​aussehen:

for (var i=0; i<country.geometry.coordinates.length; i++) { 
    var copy = JSON.parse(JSON.stringify(country)); 
    copy.geometry.coordinates = [copy.geometry.coordinates[i]]; 
    path.area(copy); 
    ... 
} 
+0

Hey, danke. Ich habe letzte Nacht eine etwas explizitere Lösung implementiert. Habe es einfach als weitere Antwort hinzugefügt. Ihre Herangehensweise könnte ein bisschen schlanker sein. – ACPrice

4

Nur weil niemand eine vollständig implementierte Antwort hinzugefügt hat, habe ich mich entschieden, meine eigene Frage zu beantworten. Der folgende Code nimmt geoJSON wie in der ursprünglichen Frage angegeben auf und gibt die Koordinaten der größten Begrenzungsregion für Länder mit mehr als einer Begrenzungsregion zurück. Für Länder mit nur einer Grenzregion werden die Koordinaten der einen Grenzregion zurückgegeben. (Ich hatte den Code ein wenig ändern es ein eigenständiges Verfahren hier zu machen, aber ich bin mir ziemlich sicher, dass es fehlerfrei ist.)

function getLargestBoundingRegion(country) { 

var largestRegionCoords; 
var path = d3.geo.path() 

//Check if the country has more than one bounding region. 
if (country.geometry.coordinates.length > 1) { 

    var regionToReturn = {   
     "type": "Feature", 
     "geometry": { 
      "type": "Polygon", 
      "coordinates": country.geometry.coordinates[0]},    
     }; 

    for (var i=1; i<country.geometry.coordinates.length; i++) { 

     var testRegion = {   
        "type": "Feature", 
       "geometry": { 
        "type": "Polygon", 
        "coordinates": country.geometry.coordinates[i]},    
      }; 

     if (path.area(testRegion) > path.area(regionToReturn)) { 
      regionToReturn = testRegion;  
      largestRegionCoords = country.geometry.coordinates[i][0];  
      } 
     } 

    } else {  
     largestRegionCoords = country.geometry.coordinates[0]; 
    } 

return largestRegionCoords; 
7

Sie können den Bereich eines beliebigen Polygon berechnen die Shoelace algorithm verwenden.

function polygonArea(points) { 
    var sum = 0.0; 
    var length = points.length; 
    if (length < 3) { 
    return sum; 
    } 
    points.forEach(function(d1, i1) { 
    i2 = (i1 + 1) % length; 
    d2 = points[i2]; 
    sum += (d2[1] * d1[0]) - (d1[1] * d2[0]); 
    }); 
    return sum/2; 
} 

polygonArea([[0,0], [4,0], [4,3]]); // 6 

Beachten Sie, dass entgegen dem Uhrzeigersinn Polygone, die einen positiven Bereich haben wird, und im Uhrzeigersinn Polygone einen negativen Bereich. Sich selbst schneidende Polygone haben normalerweise sowohl im Uhrzeigersinn als auch gegen den Uhrzeigersinn Bereiche, so dass ihr Bereich ausgelöscht wird.

+0

in welchen Einheiten ist das Ergebnis? –

+0

@PaulVidal, Die gleichen Einheiten wie die als Eingabe verwendeten Punktkoordinaten. –