日々適当

hibitekitou

matplotlibに敗北したのでBlenderで変形させてみる

cg |2019-11-24

正距円筒図法の日本地図を他の図法に変形したいわけですけど、Pythonのモジュールとしてはcartopyとmatplotlibの組み合わせでできそうだと思って格闘したんですけど、荒れた絵しか出てこないのですね。単に無知な結果なのか、そもそも無理なのか…
なので諦めて、3DCGソフトのグリッドに日本地図を貼り付けて、それを変形させることにしました。

Pythonが使えればいいのでなんでもいいんですけど、せっかくなのでBlenderで。座標変換にはPyprojモジュールを使います。
macOS上で pip3 install pyproj でOSのPythonにはそのモジュールが入りましたが、BlenderのPythonでは認識されないので一手間加えます。

Blender上で
import sys
sys.path.append('/usr/local/lib/python3.7/site-packages')
をするだけなんですけどね。これでpyprojが使えるようになりました。

ということで、突貫工事の稚拙なスクリプト。1000x1000のグリッドで実行完了まで数秒かかりますw

import bpy
from mathutils import Vector, Matrix
from pyproj import Proj
import numpy as np

#変形後の形状の東西方向のサイズ(m)
gridWidth = 100.0

#日本各地の端っこ(Google mapでクリックして返ってくる値w)
north = [ 45.523015 , 141.936587 ] #宗谷岬
#east= [ 43.385437 , 145.817579 ] #納沙布岬
east = [ 45.509032 , 148.893014 ] #択捉島
south = [ 24.045030 , 123.791862 ] #波照間島
west = [ 24.449230 , 122.932030 ] #与那国島

#中心地としてとりあえず明石を指定してみる。
akashi = [ 34.0 + 39.0/60.0, 135.0  ] #明石

#ランベルト正角円錐図法
#標準緯線が何が正解か分からんので、とりあえず国土地理院のページの地図の一つを参考にしている。
#https://www.gsi.go.jp/chubu/minichishiki22.html
lat_1 = 34.0 + 5.0/60.0
lat_2 = 37.0 + 54.0/60.0 + 30.0/3600.0
converter = Proj( proj='lcc', R=6371200,  lat_1=lat_1, lat_2=lat_2, lon_0=akashi[1], ellps='WGS84' )

obj = bpy.context.object
mesh = obj.data
verts = mesh.vertices

xMax = -1000000.0
yMax = -1000000.0
xMin = 1000000.0
yMin = 1000000.0
vertsList = []

for vert in verts:
    vertPos =  vert.co[:2] 
    vertsList.append( list( vertPos ) )
    if vertPos[0] > xMax:
        xMax = vertPos[0]
    if vertPos[0]  < xMin:
        xMin = vertPos[0] 
    if vertPos[1] > yMax:
        yMax = vertPos[1]
    if vertPos[1] < yMin:
        yMin = vertPos[1]

newXMax = -10000000.0
newYMax = -10000000.0
newXMin = 10000000.0
newYMin = 10000000.0
i = 0

cntX , cntY  = converter( akashi[1], akashi[0] ) #中心地は明石にしている

for vertPos in vertsList:
    lon = ( vertPos[0] - xMin )/( xMax - xMin ) * ( east[1] - west[1] ) + west[1]
    lat = ( vertPos[1] - yMin )/( yMax - yMin ) * ( north[0] - south[0] ) + south[0]
    
    x , y = converter( lon, lat )
    x = x * 0.001
    y = y * 0.001
    
    y = y - cntY * 0.001
    
    if x > newXMax:
        newXMax = x
    if y > newYMax:
        newYMax = y
    if x < newXMin:
        newXMin = x
    if y < newYMin:
        newYMin = y
    
    v = Vector( ( x, y, 0.0 ) )
    verts[i].co = v
    i+=1

sclVal = gridWidth / (newXMax - newXMin)
obj.scale = ( sclVal, sclVal, sclVal )

コメント ( 0 )|Trackback ( )
  ・