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

複数地域の浮き出し地図(シェープファイル)

 これ以降の記事は、QGISなどの地図ソフトを使える方限定になります。

 視覚効果が得られるか疑問な点もありますが、浮き出し地図も、1つの地域だけでは物足りず、周辺を含めたいことがあります。

 この周辺というのが、東京都内の一部と神奈川県内の一部とか、東京都内と千葉県内のようになると、行政地域のファイルが都道府県単位だとそれぞれ別物になり、扱いづらくなります。

 そこで、全国版の行政地域のデーターを使い、QGISなどの地図ソフトで目的地だけを抜き出したシェープファイルを使うと抜き出し作業が楽になります。

 Pythonのスクリプトも、これまでのように1つの地区を探し出して中心位置を割り出して…という複雑な作業がなくなるので簡単になります。というより、シェープファイルアクセスの本領を発揮します。

 もちろん、1つだけの地域を収録したシェープファイルでも構いません。

 スクリプトは、シェープファイルのアクセス側(CShpR.py)も必要です。

 メインのスクリプトです。この例では、シェープファイルの名前が23区のみ.shpになっています。ここに生pyファイルがあります。

#!BPY
import bpy
import math
import glob
from CShpR import CShpR
#
# 複数地域の浮き出し地図を実験(シェープファイル)
#       main005.py
#       2016/11/17 Shizuka-Toikanbetsu
#
ShpName = "23区のみ.shp"   # 収録されているshpファイルを指定
ObjScale = 0.001        # 原寸では大きいので1000分の1
#
# 世界座標の基準緯度と世界座標の目標座標の距離をメートル単位で返す
def     GetLatOffset(pBaseLat, pLat):
        return ( pLat - pBaseLat ) * 40007000.0 / 360.0
#
# 世界座標の基準経度と世界座標の目標座標の距離をメートル単位で返す
def     GetLonOffset(pBaseLon, pLat, pLon):
        return ( pLon - pBaseLon ) * 40075000.0 * math.cos( math.radians( pLat ) ) / 360.0
#
def     MergeRecName():
        Buff = []
        for item in bpy.data.objects:
                if item.type == "MESH":
                        temp = item.name
                        Buff.append( temp[ 0 : 5 ] )
        Buff.sort()
        AreaCode = []
        OldCode = ""
        for temp in Buff:
                if temp != OldCode:
                        AreaCode.append( temp )
                OldCode = temp
        #
        for Code in AreaCode:
                bpy.ops.object.select_all(action='DESELECT')
                flag = True
                for curve in bpy.data.objects:
                        if curve.type == 'MESH':
                                NowName = curve.name
                                NowCode = NowName[:5]
                                if NowCode == Code:
                                        if flag:
                                                RecName = NowName
                                                flag = False
                                        curve.select = True
                                        bpy.context.scene.objects.active = curve
                bpy.ops.object.join()
                bpy.ops.object.select_all(action='DESELECT')
        # 小数点の付く名前は書き換える
        for item in bpy.data.objects:
                if item.type == "MESH":
                        temp = item.name
                        try:
                                item.name = temp[ 0 : temp.index( "." ) ]
                        except ValueError:
                                pass
        #
        bpy.context.scene.objects.active = None
#
def     CreateCurve(pName, pShape, pPart, pInterior):
        temp = pShape.parts[ pPart ]
        top = temp[ 0 ]
        btm = temp[ 1 ]
        Count = btm - top + 1
        CvData = bpy.data.curves.new( name = pName, type="CURVE" )
        CvData.dimensions = "2D"
        ObjData = bpy.data.objects.new( pName, CvData )
        if pInterior:
                ObjData.location = ( 0, 0, 1 )
        else:
                ObjData.location = ( 0, 0, 0 )
        ObjData.scale[0] = ObjScale
        ObjData.scale[1] = ObjScale
        ObjData.scale[2] = ObjScale
        bpy.context.scene.objects.link( ObjData )
        polyline = CvData.splines.new( "POLY" )
        #
        polyline.points.add( Count - 1 )
        ptr = top
        for xyptr in range( 0, Count ):
                posX = pShape.XY[ ptr ][ 0 ]
                posY = pShape.XY[ ptr ][ 1 ]
                ptr = ptr + 1
                posX = GetLonOffset( wx, posY, posX )
                posY = GetLatOffset( wy, posY )
                polyline.points[xyptr].co = ( posX, posY, 0, 0 )
        polyline.use_cyclic_u = True
        ObjData.select = True
        if pInterior:
                bpy.context.scene.objects.active = ObjData
                bpy.ops.object.modifier_add(type='SOLIDIFY')    # 厚み付け
                bpy.context.object.modifiers["Solidify"].thickness = 5.0 / ObjScale
        # カーブをメッシュオブジェクトに変換
        bpy.context.scene.objects.active = ObjData
        bpy.ops.object.convert( target = "MESH" )
        ObjData.select = False
        return ObjData
#
print( '\nStart Script' )
#
# 既存メッシュの削除
for item in bpy.context.scene.objects:
        if item.type == "MESH":
                bpy.context.scene.objects.unlink( item )
for item in bpy.data.objects:
        if item.type == "MESH":
                bpy.data.objects.remove( item )
for item in bpy.data.meshes:
        bpy.data.meshes.remove( item )
#
files = glob.glob( ShpName )
if files:
        file = files[ 0 ]       # きりがないので処理は1ファイルに限る
        shape = CShpR()
        shape.open( file )
        #
        for fldptr in range( 0, shape.DbfFieldCount ):
                temp = shape.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
        #
        wx = shape.VolWx
        wy = shape.VolWy
        #
        # ここから本番。レコードごとに図形を作る
        for RecNo in range( 0, shape.DbfRecCount ):
                # dbfを1レコード読む
                tempbin = shape.readdbf( RecNo )
                AreaCode = shape.getdbfvalue( tempbin, DbfArea )
                if len( AreaCode ) == 0:
                        AreaCode = "?????"
                # ↓ オブジェクト名を作る
                RecName = AreaCode
                temp = shape.getdbfvalue( tempbin, DbfPref )
                RecName = RecName + "_" + temp
                temp = shape.getdbfvalue( tempbin, DbfCounty )
                if len( temp ):
                        RecName = RecName + "_" + temp
                temp = shape.getdbfvalue( tempbin, DbfCity )
                if len( temp ):
                        RecName = RecName + "_" + temp
                # ↑ オブジェクト名を作る
                #
                tempbin = shape.readrec( RecNo )
                shptype = shape.GetBinDword( tempbin[:4] )
                if shptype == 5:        # polygon is 5
                        shape.CreateSegVert( tempbin )
                        #
                        objectdata = CreateCurve( RecName, shape, 0, False )
                        #
                        # 穴をあける処理を追加
                        for part in range( 1, len( shape.parts ) ):
                                objectdata2 = CreateCurve( "temp", shape, part, True )
                                #
                                objectdata.select = True
                                bpy.context.scene.objects.active = objectdata
                                bpy.ops.object.modifier_add(type='BOOLEAN')
                                bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
                                bpy.context.object.modifiers["Boolean"].object = bpy.data.objects["temp"]
                                bpy.context.object.modifiers["Boolean"].double_threshold = 0.0
                                bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
                                objectdata.select = False
                                objectdata2.select = True
                                bpy.ops.object.delete(use_global=False)
        #
        shape.close()
        #
        #
        MergeRecName()  # 複数レコードを1つにまとめたいなら実行
#
print( '\nEnd Script' )

 2つのスクリプトとも1度テキストエディタから解放してBlenderを保存し、エクスプローラーでBlenderファイルをダブルクリックで起動した後テキストエディタに入り、2つのスクリプトを読み込みます。

 千代田区とその周辺とか、東京23区は一見するとうまくいったように見えます。

 ただ、欲張って広域にすると面の塗り残しなど不具合が出てくることがあります。また、スケールも1000分の1では図形が大きすぎます。

 例えば、北海道の根室半島に近い厚岸町(あっけしちょう)単体では問題ありません。

 これを、欲張って北海道全域にすると、距離が長くなり、不具合が出てきます。

<トップページに戻る>


Copyright© Shizuka-Toikanbetsu.
inserted by FC2 system