国土数値情報 ダウンロードサービスの利用

試しに1地域の地図(シェープファイル)

 今度は千代田区をシェープファイルで作ってみます。

 dbfの扱いが面倒ですが、その部分を過ぎるとxmlより扱いやすかったりします。

 実は、座標定義がぐるっと1周しているかチェック…というのを今回のシェープファイル版ではやっていません。ぐるっと1周して開始点と終了点で同じものを2回定義していると決めつけたスクリプトです。今回のスクリプトではチェックしませんが、次回以降ではチェックします。

 数値のエンディアンの関係で、Windows専用です。

#!BPY
import bpy
import glob
import struct
#
# 試しに1地域の浮き出し地図(シェープファイル)
#
ShpName = "N03-*.shp"   # 収録されているshpファイルを指定
AreaCode = "13101"      # 地方公共団体コードを文字列型で指定
#
def     GetBinDword(Item):
        return struct.unpack( "L", Item )[ 0 ]
#
def     GetBinDouble(Item):
        return struct.unpack( "d", Item )[ 0 ]
#
def     GetBinDwordRev(Item):
        return struct.unpack( "L", Item[::-1] )[ 0 ]
#
class   CDbfFieldRec:
        def __init__(self):
                self.name = ""
                self.Top = 0
                self.Btm = 0
#
print( '\nStart Script' )
#
# 既存カーブとメッシュの削除
for item in bpy.context.scene.objects:
        if item.type == "CURVE" or item.type == "MESH":
                bpy.context.scene.objects.unlink( item )
for item in bpy.data.objects:
        if item.type == "CURVE" or item.type == "MESH":
                bpy.data.objects.remove( item )
for item in bpy.data.curves:
        bpy.data.curves.remove( item )
for item in bpy.data.meshes:
        bpy.data.meshes.remove( item )
#
files = glob.glob( ShpName )
if files:
        file = files[ 0 ]       # きりがないので処理は1ファイルに限る
        fshp = open( file, "rb" )
        temp = file.split( "." )
        fshx = open( temp[ 0 ] + ".shx", "rb" )
        fdbf = open( temp[ 0 ] + ".dbf", "rb" )
        fdbf.read( 4 )  # skip
        tempbin = fdbf.read( 4 )
        DbfRecCount = struct.unpack( "L", tempbin )[ 0 ]
        tempbin = fdbf.read( 2 )
        DbfHeaderSize = struct.unpack( "H", tempbin )[ 0 ]
        tempbin = fdbf.read( 2 )
        DbfRecSize = struct.unpack( "H", tempbin )[ 0 ]
        DbfFieldCount = int( ( DbfHeaderSize - 33 ) / 32 )
        # フィールドのレコード内位置を割り出す
        fdbf.seek( 32, 0 )
        DbfField = []
        CodePosE = 1
        for fldptr in range( 0, DbfFieldCount ):
                DbfFieldRec = CDbfFieldRec()
                tempbin = fdbf.read( 32 )
                temp = tempbin[:10]
                temp = temp.decode('shift_jis')
                DbfFieldRec.name = temp.rstrip( ' \0' )
                temp = tempbin[16:17]
                temp = struct.unpack( "B", temp )
                temp = temp[ 0 ]
                CodePosE = CodePosE + temp
                CodePosS = CodePosE - temp
                DbfFieldRec.Top = CodePosS
                DbfFieldRec.Btm = CodePosE
                DbfField.append( DbfFieldRec )
        #
        for fldptr in range( 0, DbfFieldCount ):
                temp = DbfField[ fldptr ].name
                if temp == "N03_001":
                        DbfPref = fldptr
                elif temp == "N03_003":
                        DbfCounty = fldptr
                elif temp == "N03_004":
                        DbfCity = fldptr
                elif temp == "N03_007":
                        DbfArea = fldptr
        #
        # ここから本番。レコードごとに図形を作る
        fdbf.read( 1 )
        for RecNo in range( 0, DbfRecCount ):
                # dbfを1レコード読む
                tempbin = fdbf.read( DbfRecSize )
                temp = tempbin[ DbfField[ DbfArea ].Top : DbfField[ DbfArea ].Btm ]
                temp = temp.decode('shift_jis')
                if( temp == AreaCode ):
                        # ↓ オブジェクト名を作る
                        RecName = AreaCode
                        temp = tempbin[ DbfField[ DbfPref ].Top : DbfField[ DbfPref ].Btm ]
                        temp = temp.rstrip( b' ' )
                        temp = temp.decode('shift_jis')
                        RecName = RecName + "_" + temp
                        temp = tempbin[ DbfField[ DbfCounty ].Top : DbfField[ DbfCounty ].Btm ]
                        temp = temp.rstrip( b' ' )
                        temp = temp.decode('shift_jis')
                        if len( temp ):
                                RecName = RecName + "_" + temp
                        temp = tempbin[ DbfField[ DbfCity ].Top : DbfField[ DbfCity ].Btm ]
                        temp = temp.rstrip( b' ' )
                        temp = temp.decode('shift_jis')
                        if len( temp ):
                                RecName = RecName + "_" + temp
                        # ↑ オブジェクト名を作る
                        #
                        fshx.seek( RecNo * 8 + 100, 0 )
                        tempbin = fshx.read( 8 )
                        shppos = GetBinDwordRev( tempbin[:4] ) * 2
                        shplen = GetBinDwordRev( tempbin[4:8] ) * 2
                        #
                        fshp.seek( shppos + 8, 0 )
                        tempbin = fshp.read( shplen )
                        shptype = GetBinDword( tempbin[:4] )
                        if shptype == 5:        # polygon is 5
                                NumParts = GetBinDword( tempbin[36:40] )
                                NumPoints = GetBinDword( tempbin[40:44] )
                                parts = []
                                ptr = 44
                                for temp in range( 0, NumParts ):
                                        NowPart = GetBinDword( tempbin[ptr:ptr+4] )
                                        parts.append( NowPart )
                                        ptr = ptr + 4
                                parts.append( NumPoints )
                                #
                                Count = parts[ 1 ] - parts[ 0 ] - 1
                                curvedata = bpy.data.curves.new(name=RecName, type='CURVE')
                                curvedata.dimensions = '2D'
                                objectdata = bpy.data.objects.new(RecName, curvedata)
                                objectdata.location = (0,0,0)
                                bpy.context.scene.objects.link(objectdata)
                                polyline = curvedata.splines.new('POLY')
                                #
                                polyline.points.add( Count - 1 )
                                for xyptr in range( 0, Count ):
                                        posX = GetBinDouble( tempbin[ptr:ptr+8] )
                                        ptr = ptr + 8
                                        posY = GetBinDouble( tempbin[ptr:ptr+8] )
                                        ptr = ptr + 8
                                        polyline.points[xyptr].co = ( posX, posY, 0, 0 )
                                polyline.use_cyclic_u = True
        #
        # ↓ 複数レコードを1つにまとめたいなら実行
        for Code in AreaCode:
                bpy.ops.object.select_all(action='DESELECT')
                for curve in bpy.data.objects:
                        if curve.type == 'CURVE':
                                NowName = curve.name
                                NowCode = NowName[:5]
                                if NowCode == AreaCode:
                                        curve.select = True
                                        bpy.context.scene.objects.active = curve
                bpy.ops.object.join()
                bpy.ops.object.select_all(action='DESELECT')
                objectdata.name = RecName
        # ↑ 複数レコードを1つにまとめたいなら実行
        #
        fdbf.close()
        fshx.close()
        fshp.close()
#
print( '\nEnd Script' )

 dbfファイルの処理があるのでどうしてもリストが長くなります。

<トップページに戻る>


Copyright© Shizuka-Toikanbetsu.
inserted by FC2 system