2014-01-10 20 views
1

我已經將ArcGIS arcpy的python腳本放在一起用於創建polygonzo json多邊形(http://code.google.com/p/polygonzo/)。這是我的python腳本...Google地圖可以polygonzo處理內部環嗎?

import os, string, arcpy 
arcpy.env.overwriteOutput = True 


layer = "C:\\Other\\Shapefiles\\Geo500K_JSON\\GEOLOGY_500K_Project.shp" 

output = "C:\\Other\\Shapefiles\\Geo500K_JSON\\" 

outfile = output + "Geo500K.json" 
jsonFile = open(outfile,'w') 
jsonFile.write('var geo = {\n') 
jsonFile.write('\t"type": "FeatureCollection",\n') 
jsonFile.write('\t"features": [\n') 

idfield = "ORIG_LABEL" 
shape_field = arcpy.Describe(layer).shapeFieldName 

rows = arcpy.SearchCursor(layer,"","","",idfield + " A") 
row = rows.next() 

while row: 

    geostring = '' #for each lat/lng pt 
    geolist = [] # array for storing individual geostrings 
    ringList = [] #array for storing geolist array with geostrings separated by commas 
    partList = [] #array for storing partlist, final array used 
    shapeString = '' 

    jsonFile.write('\t\t{"type": "Feature", ') 

    extent = row.Shape.extent 
    ne = str(extent.XMax) + ',' + str(extent.YMax) 
    sw = str(extent.XMin) + ',' + str(extent.YMin) 
    jsonFile.write('"bbox": [' + sw + ', ' + ne + '],') 

    jsonFile.write('"properties":{') 

    geoLabel = str(row.getValue(idfield)) 
    jsonFile.write('"label": "' + geoLabel + '", ')  

    geoName = str(row.getValue("FM_NAME")) 
    jsonFile.write('"name": "' + geoName + '", ') 

    lithType = str(row.getValue("LithType")) 
    jsonFile.write('"lithType": "' + lithType + '", ') 

    rank = str(row.getValue("Rank")) 
    jsonFile.write('"rank": "' + rank + '", ') 

    lithName = str(row.getValue("LithName")) 
    jsonFile.write('"lithName": "' + lithName + '", ') 

    ageType = str(row.getValue("AgeType")) 
    jsonFile.write('"ageType": "' + ageType + '", ') 

    minAge = str(row.getValue("MinAge")) 
    jsonFile.write('"minAge": "' + minAge + '", ') 

    maxAge = str(row.getValue("MaxAge")) 
    jsonFile.write('"maxAge": "' + maxAge + '", ') 

    part = row.getValue(shape_field).centroid 
    jsonFile.write('"center":[' + str(part.X) + ',' + str(part.Y) + '],') 

    jsonFile.write('"centroid":[' + str(part.X) + ',' + str(part.Y) + ']},') 


    jsonFile.write('"geometry":{"type":"MultiPolygon","coordinates":[[[') 

    feat = row.shape 
    for p in range(feat.partCount): 
     pInt = p 
     part = feat.getPart(p) 
     pt = part.next() 
     while pt: 
      lat = str(round(pt.Y,6)) 
      lon = str(round(pt.X,6)) 

      geostring = '[' + lon + ',' + lat + ']' 
      geolist.append(geostring) 

      pt = part.next() 

      #if now following point go to the next part which should be an interior ring.  
      if not pt: 
       ringList.append(',' .join(geolist)) 
       geostring = '' 
       geolist = [] 
       pt = part.next() 
       if pt: 
        print 'Interior Ring: ' + geoLabel 

     partList.append(',' .join(ringList)) 
     ringList = [] 

    shapeString = ']], [[' .join(partList) 
    jsonFile.write(shapeString) 
    jsonFile.write(']]]}},\n') 
    row = rows.next() 

#jsonFile.seek(-1, os.SEEK_END) 
#jsonFile.truncate() 
jsonFile.write('\t]\n') 
jsonFile.write('}') 
jsonFile.close() 
del row, rows 

當腳本遇到內環時,它只會打印警告。我不知道如何處理它們。不幸的是,我工作的許多多邊形都有內部環。我用一個有內環的多邊形放在一起測試地圖。這是它看起來像什麼... http://www.geology.ar.gov/test/test-polygonzo.html

可以polygonzo句柄內環?

更新: 我真的很感謝您的迴應Michael Geary先生!但是,我無法讓你的python腳本使用json模塊來工作。其中有一些錯誤,我上面編輯它,但它吐出一個空白的文件。也許我沒有努力。在回顧一下帶有內部環的multipolyon應該看起來像json格式的例子之後,我回過頭去研究我的python腳本(並且是的,在沒有使用json模塊的情況下使json有效是很困難的)。我添加了更多評論,所以如果你有時間的話,你可以使用json模塊來使你的腳本工作 - 我想看一個有效的例子。這是我最後的Python腳本....

import os, string, arcpy 
arcpy.env.overwriteOutput = True 


layer = "C:\\Other\\Shapefiles\\Geo500K_JSON\\GEOLOGY_500K_kn.shp" 

output = "C:\\Other\\Shapefiles\\Geo500K_JSON\\" 

outfile = output + "Geo500K_knTest.json" 
jsonFile = open(outfile,'w') 
jsonFile.write('var geo = {\n') 
jsonFile.write('\t"type": "FeatureCollection",\n') 
jsonFile.write('\t"features": [\n') 

idfield = "ORIG_LABEL" 
shape_field = arcpy.Describe(layer).shapeFieldName 

rows = arcpy.SearchCursor(layer,"","","",idfield + " A") 
row = rows.next() 
#loop through the attribute table 
while row:  

    jsonFile.write('\t\t{"type": "Feature", \n') 

    extent = row.Shape.extent 
    ne = str(extent.XMax) + ',' + str(extent.YMax) 
    sw = str(extent.XMin) + ',' + str(extent.YMin) 
    jsonFile.write('\t\t"bbox": [' + sw + ', ' + ne + '],\n') 

    jsonFile.write('\t\t"properties":{\n') 

    geoLabel = str(row.getValue(idfield)) 
    jsonFile.write('\t\t\t"label": "' + geoLabel + '", \n')  

    geoName = str(row.getValue("FM_NAME")) 
    jsonFile.write('\t\t\t"name": "' + geoName + '", \n') 

    lithType = str(row.getValue("LithType")) 
    jsonFile.write('\t\t\t"lithType": "' + lithType + '", \n') 

    rank = str(row.getValue("Rank")) 
    jsonFile.write('\t\t\t"rank": "' + rank + '", \n') 

    lithName = str(row.getValue("LithName")) 
    jsonFile.write('\t\t\t"lithName": "' + lithName + '", \n') 

    ageType = str(row.getValue("AgeType")) 
    jsonFile.write('\t\t\t"ageType": "' + ageType + '", \n') 

    minAge = str(row.getValue("MinAge")) 
    jsonFile.write('\t\t\t"minAge": "' + minAge + '", \n') 

    maxAge = str(row.getValue("MaxAge")) 
    jsonFile.write('\t\t\t"maxAge": "' + maxAge + '", \n') 

    centroid = row.getValue(shape_field).centroid 
    jsonFile.write('\t\t\t"center":[' + str(centroid.X) + ',' + str(centroid.Y) + '], \n') 
    jsonFile.write('\t\t\t"centroid":[' + str(centroid.X) + ',' + str(centroid.Y) + '] \n') 

    jsonFile.write('\t\t\t}, \n') #end of properties 

    jsonFile.write('\t\t"geometry":{\n\t\t\t"type":"MultiPolygon",\n\t\t\t"coordinates":[\n') 

    feat = row.shape #get the shape/geography of the row in the attribute table 
    partnum = 1 

    #loop through the parts of the polygon (some may have more that one part) 
    for p in range(feat.partCount): 
     jsonFile.write('\t\t\t\t[\n\t\t\t\t\t[\n') 
     jsonFile.write('\t\t\t\t\t\t//Part ' + str(partnum) + '\n') 
     jsonFile.write('\t\t\t\t\t\t//Outer ring of Part ' + str(partnum) + '\n') 

     part = feat.getPart(p) #return an array of point objects for particular part 

     pt = part.next() #return specific pt object of array 
     innerRingNum = 1 

     #loop through each pt object/vertex of part 
     while pt: 
      lat = round(pt.Y,7) #get latitude of pt object and round to 7 decimal places 
      lon = round(pt.X,7) #get longitude of pt object and round to 7 decimal places 

      jsonFile.write('\t\t\t\t\t\t[' + str(lon) + ',' + str(lat) + '],\n') #assemble [lon,lat] 

      pt = part.next() #go to next pt object to continue loop 

      #if no following point go to the next part which should be an interior ring. 
      if not pt: 
       #we've got an interior ring so let's loop through the vertices of the ring 
       pt = part.next() 

       if pt: 
        jsonFile.seek(-3, os.SEEK_END) 
        jsonFile.truncate() #remove trailing comma 
        jsonFile.write('\n\t\t\t\t\t],\n') 
        jsonFile.write('\t\t\t\t\t[\n') 
        jsonFile.write('\t\t\t\t\t\t//Inner ring ' + str(innerRingNum) + ' of Part ' + str(partnum) + '\n') 
        print 'Interior Ring: ' + geoLabel 
        innerRingNum += 1 



     partnum += 1 
     jsonFile.seek(-3, os.SEEK_END) 
     jsonFile.truncate() #remove trailing comma 
     jsonFile.write('\n\t\t\t\t\t]\n\t\t\t\t],\n') 

    jsonFile.seek(-3, os.SEEK_END) 
    jsonFile.truncate() #remove trailing comma 
    jsonFile.write('\n\t\t\t]\n\t\t\t}\n\t\t},\n') 
    row = rows.next() 

jsonFile.seek(-3, os.SEEK_END) 
jsonFile.truncate() #remove trailing comma 
jsonFile.write('\n\t]\n') 
jsonFile.write('}') 
jsonFile.close() 
del row, rows 

我還要補充一點,我與polygonzo以及您願意與他人分享真的很感動。但是,您提供的JavaScript和python確實可以使用更多註釋來更快地理解它。

回答

0

PolyGonzo作者在這裏,對不起,我沒有碰到你的問題,直到現在。

我不知道這是否仍然相關,但我看着你的測試頁。

PolyGonzo確實支持內部環,但GeoJSON數據中沒有內部環。

GeoJSON specMultiPolygon example中有一個內部環的示例。不幸的是它的不良格式化,所以這裏的縮進和註釋版本:

{ 
    "type": "MultiPolygon", 
    "coordinates": [ 
     // First polygon of the multipolygon 
     [ 
      // Outer ring of the first polygon (there is no inner ring) 
      [ 
       [ 102.0, 2.0 ], 
       [ 103.0, 2.0 ], 
       [ 103.0, 3.0 ], 
       [ 102.0, 3.0 ], 
       [ 102.0, 2.0 ] 
      ] 
     ], 
     // Second polygon of the multipolygon 
     [ 
      // Outer ring of the second polygon 
      [ 
       [ 100.0, 0.0 ], 
       [ 101.0, 0.0 ], 
       [ 101.0, 1.0 ], 
       [ 100.0, 1.0 ], 
       [ 100.0, 0.0 ] 
      ], 
      // Inner ring of the second polygon 
      [ 
       [ 100.2, 0.2 ], 
       [ 100.8, 0.2 ], 
       [ 100.8, 0.8 ], 
       [ 100.2, 0.8 ], 
       [ 100.2, 0.2 ] 
      ] 
      // You could have additional inner rings here 
     ] 
    ] 
} 

換句話說,該coordinates屬性所的MultiPolygon是多邊形的數組。每個多邊形又是一組環。這些環中的每一個都是座標對的數組(如果您有高度信息等,則爲三元組)。

對於給定的多邊形,第一個環是外環,而任何其他環是內環。

在您的MultiPolygon中,它的每個多邊形都只有一個環,所以PolyGonzo將其解釋爲外環。

查看您的數據後,我可以看到發生了這樣的情況:對於MultiPolygon中的每個多邊形,您將所有點都用於外環中的所有點任何內環都在一個大陣中。

文件中的第三個多邊形就是一個很好的例子。這是希望北部的大片區域。通過GeoJSON數據的這一部分,我發現了四個內環。 (我通過在地圖上放大虛線來找到它們,並通過查看大跳躍的座標來找到它們。)

我手動拆分GeoJSON中的數組,以便這些內部環擁有自己的數組,並且它將事情修復得真好。

這裏是一個fiddle與希望北部地區的更正數據。 GeoJSON數據內嵌在小提琴的JavaScript代碼中,因此您可以在那裏看到我更改的內容。我還在Arkadelphia周圍發現了一個類似的問題,但沒有改正。

現在關於你生成你的JSON數據的方式......

強烈建議您不要通過作爲代碼是粘貼在一起一堆位和JSON文本片段的產生JSON現在做。

相反,在Python中創建一個代表您的整個GeoJSON結構的對象(dict),然後調用json.dump()json.dumps()將整個結構一次轉換爲JSON。

這使事情變得更容易。它會自動保證你的JSON是有效的 - 它現在已經是這樣了,但我敢打賭你必須努力去達到目的,對吧? ;-) json.dump()使這個微不足道。

它也應該更容易避免像這種情況下,你打算爲外圈和內圈放出單個陣列的問題,但他們意外地將所有卡住到單個陣列中。

這是您的代碼部分轉換爲使用此技術。我並沒有做這件事,因爲我不熟悉arcpy,但這應該給你的想法:

import os, string, arcpy, json 
arcpy.env.overwriteOutput = True 


layer = "C:\\Other\\Shapefiles\\Geo500K_JSON\\GEOLOGY_500K_kn.shp" 

output = "C:\\Other\\Shapefiles\\Geo500K_JSON\\" 

outfile = output + "Geo500K_knTest_C2.json" 

idfield = "ORIG_LABEL" 
shape_field = arcpy.Describe(layer).shapeFieldName 

features = [] 
geojson = { 
    'type': 'FeatureCollection', 
    'features': features 
    } 


rows = arcpy.SearchCursor(layer,"","","",idfield + " A") 
for row in rows: 
    geostring = '' #for each lat/lng pt 
    geolist = [] # array for storing individual geostrings 
    ringList = [] #array for storing geolist array with geostrings separated by commas 
    partList = [] #array for storing partlist, final array used 
    shapeString = '' 

    extent = row.Shape.extent 
    centroid = row.getValue(shape_field).centroid 

    coordinates = [] 

    feature = { 
     'type': 'Feature', 
     'bbox': [ extent.XMin, extent.YMin, extent.XMax, extent.YMax ], 
     'properties': { 
      'label': str(row.getValue(idfield)), 
      'name': str(row.getValue("FM_NAME")), 
      'lithType': str(row.getValue("LithType")), 
      'rank': str(row.getValue("Rank")), 
      'lithName': str(row.getValue("LithName")), 
      'ageType': str(row.getValue("AgeType")), 
      'minAge': str(row.getValue("MinAge")), 
      'maxAge': str(row.getValue("MaxAge")), 
      'center': [ centroid.X, centroid.Y ], 
      'centroid': [ centroid.X, centroid.Y ] 
     }, 
     'geometry': { 
      'type': 'MultiPolygon', 
      'coordinates': coordinates 
     } 
    } 

    feat = row.shape 
    for p in range(feat.partCount):   
     part = feat.getPart(p) 
     pt = part.next() 
     while pt: 
      lat = str(round(pt.Y,6)) 
      lon = str(round(pt.X,6)) 

      geostring = '[' + lon + ',' + lat + ']' 
      geolist.append(geostring) 

      pt = part.next() 

      #if no following point go to the next part which should be an interior ring.  
      if not pt: 
       ringList.append(',' .join(geolist)) 
       geostring = '' 
       geolist = [] 
       pt = part.next() 
       if pt: 
        print 'Interior Ring: ' 

     partList.append('],[' .join(ringList)) 
     ringList = []   


    features.append(feature) 
    shapeString = ']],[[' .join(partList) 
    coordinates.append(shapeString) 



with open(outfile,'wb') as jsonFile: 
    json.dump(geojson, jsonFile) 
+0

我編輯了一些錯誤出你的python腳本Michael Geary。你是否也想用json.dumps代替json.dump? –

+0

@razor_nate - 感謝修復,非常感謝。我的意思是使用'json.dump()'(而不是'dumps()'),因爲這個想法是寫一個文件。但我忘了包含文件參數!現在補充說。 –

+0

Michael Geary - 我用修改後的python腳本更新了我的問題。 –

相關問題