shapelyによるpolygon作成や、numpyによる座標変換(affine変換)、 mpl_toolkits.mplot3d.art3dによる3D表示の練習です。
# coding: utf-8 import numpy as np # cf. https://shapely.readthedocs.io/en/stable/manual.html from shapely.geometry import Polygon from shapely.geometry import MultiPolygon import matplotlib.pyplot as plt import mpl_toolkits.mplot3d.art3d as art3d # 回転や移動の定義 # cf. https://org-technology.com/posts/rotational-transformation-matrix.html affines = { # Z方向へ+40移動 "z90" : np.array([[ 1, 0, 0, 0], [ 0, 1, 0, 0], [ 0, 0, 1,40], [ 0, 0, 0, 1]] ), # X軸に90度回転 "rx90" : np.array([[ 1, 0, 0, 0], # 1, 0, 0 [ 0, 0,-1, 0], # 0,cos,-sin [ 0, 1, 0, 0], # 0 sin, cos [ 0, 0, 0, 1]] ), # Z軸に90度回転後、Y方向へ+40 "rz90" : np.array([[ 0, 1, 0, 0], # cos,sin,0 [-1, 0, 0,40], # -sin,cos,0 [ 0, 0, 1, 0], # 0 0, 1 [ 0, 0, 0, 1]] ), # Z軸に180度回転後、X方向へ+70、Y方向へ+40 "rz180" : np.array([[-1, 0, 0,70], # cos,sin,0 [ 0,-1, 0,40], # -sin,cos,0 [ 0, 0, 1, 0], # 0 0, 1 [ 0, 0, 0, 1]] ), # Z軸に270度回転後、X方向へ+70 "rz270" : np.array([[ 0,-1, 0,70], # cos,sin,0 [ 1, 0, 0, 0], # -sin,cos,0 [ 0, 0, 1, 0], # 0 0, 1 [ 0, 0, 0, 1]] ) } def main(): # 床,天井,壁のpolygonを Local座標で作成 (floor, ceil, wall_a, wall_b, wall_c, wall_d) = \ make_polygon_for_floor_ceil_wall() # メッシュに分割し、numpyのlistを返却 mesh_size = 10 meshs_floor = divide_by_mesh(floor,mesh_size) meshs_ceil = divide_by_mesh(ceil, mesh_size) meshs_wall_a = divide_by_mesh(wall_a, mesh_size) meshs_wall_b = divide_by_mesh(wall_b, mesh_size) meshs_wall_c = divide_by_mesh(wall_c, mesh_size) meshs_wall_d = divide_by_mesh(wall_d, mesh_size) # 絶対座標へ変換(配置) meshs_ceil = mesh_coords_to_abs( meshs_ceil, [affines["z90"]] ) meshs_wall_a = mesh_coords_to_abs( meshs_wall_a,[affines["rx90"]] ) meshs_wall_b = mesh_coords_to_abs( meshs_wall_b,[affines["rx90"], affines["rz180"]] ) meshs_wall_c = mesh_coords_to_abs( meshs_wall_c,[affines["rx90"], affines["rz90"]] ) meshs_wall_d = mesh_coords_to_abs( meshs_wall_d,[affines["rx90"], affines["rz270"]] ) # 3Dで表示 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') for meshs in [meshs_ceil, meshs_wall_a, meshs_wall_b, meshs_wall_c, meshs_wall_d ]: for mesh in meshs: ax.scatter3D(mesh[:,0],mesh[:,1],mesh[:,2], color='gray', s=5) ax.add_collection3d( art3d.Poly3DCollection(meshs, facecolors='gray', linewidths=0.5, edgecolors='gray', alpha=.01) ) plt.show() def mesh_coords_to_abs( meshs, affines ): ret_meshs = [] for mesh in meshs: np_mesh = np.array( mesh ).T # affine変換の為、最終行に[1,1,1,1]を一時追加 np_mesh = np.insert(np_mesh, 3,[1,1,1,1],axis=0) # アフィン変換 for affine in affines: np_mesh = np.dot( affine , np_mesh ) # 先程、一時追加した[1,1,1,1]を削除し、転置 np_mesh = np.delete(np_mesh, 3,axis=0).T ret_meshs.append(np_mesh) return np.array( ret_meshs ) def calc_center( meshes ): centers = [] for mesh in meshes: min_x = mesh[0][0] min_y = mesh[0][1] max_x = mesh[1][0] max_y = mesh[1][1] centers.append([(min_x + max_x) / 2, (min_y + max_y) / 2, 0 ] ) return centers def divide_by_mesh(polygon,mesh_size): (min_x,y, max_x,max_y) = polygon.bounds x = min_x meshes = [] while y < max_y: while x < max_x: mesh = Polygon( [ [x, y+mesh_size],[x+mesh_size,y+mesh_size], [x+mesh_size,y ],[x, y]] ) intersects = polygon.intersection(mesh) if intersects.type == "Polygon": (m_min_x,m_min_y, m_max_x,m_max_y) = intersects.bounds mesh = np.array( [[m_min_x,m_min_y,0],[m_min_x,m_max_y,0], [m_max_x,m_max_y,0],[m_max_x,m_min_y,0]] ) meshes.append( mesh ) elif intersects.type == "MultiPolygon": for intersect in intersects.geoms: if intersect.type != "Polygon": continue (m_min_x,m_min_y, m_max_x,m_max_y) = intersect.bounds mesh = np.array( [[m_min_x,m_min_y,0],[m_min_x,m_max_y,0], [m_max_x,m_max_y,0],[m_max_x,m_min_y,0]] ) meshes.append( mesh ) x += mesh_size x = min_x y += mesh_size return meshes def make_polygon_for_floor_ceil_wall(): # 床/天井 horizontal_shell =[ [ 0, 0],[ 0,40],[70,40],[70, 0],[0, 0] ] floor = Polygon( shell=horizontal_shell ) ceil = Polygon( shell=horizontal_shell ) # ┌─壁-B─┐ #壁-C 壁-D # └─壁-A─┘ wall_ab_shell =[ [ 0, 0],[ 0,40],[70,40],[70, 0],[60,0], [60,30],[40,30],[40, 0],[ 0, 0] ] wall_ab_holes =[[[10,10],[30,10],[30,30],[10,30],[10,10]] ] wall_a = Polygon( shell=wall_ab_shell, holes=wall_ab_holes ) wall_b = Polygon( shell=wall_ab_shell, holes=wall_ab_holes ) wall_cd_shell =[ [ 0, 0],[ 0,40],[40,40],[40, 0],[0, 0] ] wall_cd_holes =[[[ 0,10],[30,10],[30,30],[ 0,30],[0,10]] ] wall_c = Polygon( shell=wall_cd_shell, holes=wall_cd_holes ) wall_d = Polygon( shell=wall_cd_shell, holes=wall_cd_holes ) return (floor, ceil, wall_a, wall_b, wall_c, wall_d) if __name__ == '__main__': main()
↑こう書くと、↓こう表示されます