"""
このモジュールは3Dビジュアライゼーションのためのクラスを提供します。
クラス:
Visualizer3D - 3D空間にベクトル、軸、点、平面、立方体を描画するためのクラス。
使用例:
visualizer = Visualizer3D()
visualizer.add_axis([0, 0, 0])
visualizer.add_vector([0, 0, 0], [1, 1, 1], 'blue')
visualizer.show()
"""
__version__ = "1.1.0"
import plotly.graph_objects as go
import numpy as np
import random
class Visualizer3D:
def __init__(self):
self.fig = go.Figure()
# 描写する空間を立方体に固定
self.fig.update_layout(
scene=dict(
aspectmode='cube'
)
)
def config_set_xyz_range(self, x_range, y_range, z_range):
# レイアウトの調整
self.fig.update_layout(
scene=dict(
xaxis=dict(range=x_range),
yaxis=dict(range=y_range),
zaxis=dict(range=z_range)
)
)
def config_set_window_size(self, width, height):
self.fig.update_layout(
width=width, # グラフの幅と高さの設定
height=height,
hoverlabel_font_size=20
)
def add_vector(self, start_point, end_point, color='black'):
# コーンと線の色
# color = 'blue'
# ベクトルの方向を求める
u = end_point[0] - start_point[0]
v = end_point[1] - start_point[1]
w = end_point[2] - start_point[2]
# ベクトルの長さを計算
length = np.linalg.norm([u, v, w])
# コーンのサイズ調整(ベクトルの長さに応じてスケーリング)
cone_size = length * 0.1
cone_size=300
if length <= 500:
cone_size = cone_size * 0.5
# コーンの追加
self.fig.add_trace(go.Cone(
x=[end_point[0]], y=[end_point[1]], z=[end_point[2]], # コーンの位置(先端)
u=[u * 0.1], v=[v * 0.1], w=[w * 0.1], # コーンの向き
showscale=False,
colorscale=[[0, color], [1, color]], # コーンの色を設定
# hoverinfo='skip',
sizemode='absolute', # 絶対サイズモードに設定
sizeref=cone_size, # サイズのスケールを調整
anchor="tip" # コーンをベクトルの先端に配置
))
# ベクトル(線分)の追加
self.fig.add_trace(go.Scatter3d(
x=[start_point[0], end_point[0]], y=[start_point[1], end_point[1]], z=[start_point[2], end_point[2]],
mode='lines',
line=dict(color=color, width=2), # 線の太さを調整し、色を設定
hoverinfo='skip',
))
def add_axis(self, origin, R=None, t=None):
x_begin = np.array(origin)
y_begin = np.array(origin)
z_begin = np.array(origin)
x_end = np.array([origin[0] + 1000, origin[1], origin[2]])
y_end = np.array([origin[0], origin[1] + 1000, origin[2]])
z_end = np.array([origin[0], origin[1], origin[2] + 1000])
print(x_end)
# 回転行列Rが与えられた場合の計算
if R is not None:
x_begin = np.dot(R, x_begin)
y_begin = np.dot(R, y_begin)
z_begin = np.dot(R, z_begin)
x_end = np.dot(R, x_end)
y_end = np.dot(R, y_end)
z_end = np.dot(R, z_end)
# 並進移動tが与えられた場合の計算
if t is not None:
x_begin = x_begin + t
y_begin = y_begin + t
z_begin = z_begin + t
x_end = x_end + t
y_end = y_end + t
z_end = z_end + t
print(x_end)
self.add_vector(x_begin, x_end, 'red') # x-axis
self.add_vector(y_begin, y_end, 'green') # y-axis
self.add_vector(z_begin, z_end, 'blue') # z-axis
def add_point(self, point, label=None, color='black'):
if label is None:
label = f"Point {len(self.fig.data) + 1}"
self.fig.add_trace(go.Scatter3d(
x=[point[0]], y=[point[1]], z=[point[2]],
mode='markers',
marker=dict(size=3, color=color, opacity=0.8),
name=label
))
def add_plain(self, vertices):
# verticesは(n, 3)の形状のリストまたは配列
vertices = np.array(vertices)
x = vertices[:, 0]
y = vertices[:, 1]
z = vertices[:, 2]
# 三角形のインデックスを生成
n = len(vertices)
if n < 3:
raise ValueError("頂点の数が3未満です。")
i = []
j = []
k = []
for idx in range(1, n-1):
i.append(0)
j.append(idx)
k.append(idx + 1)
# メッシュを作成
self.fig.add_trace(go.Mesh3d(
x=x, y=y, z=z,
i=i, j=j, k=k,
opacity=0.5,
color='rgba(255, 0, 0, 0.8)', # RGB値を変更して色を濃くする
# hoverinfo='skip' # ホバー表示を無効化
))
def add_circle(self, radius, z_position, origin=(0, 0, 0), color='rgb(255, 0, 0)', num_points=100):
theta = np.linspace(0, 2*np.pi, num_points)
x = radius * np.cos(theta) + origin[0]
y = radius * np.sin(theta) + origin[1]
z = np.full_like(x, z_position) + origin[2]
self.fig.add_trace(go.Scatter3d(x=x, y=y, z=z, mode='lines', line=dict(color='black', width=3)))
def add_cube(self, x0, y0, z0, length):
# 立方体の各頂点の座標を定義
x = [x0, x0+length, x0+length, x0, x0, x0+length, x0+length, x0]
y = [y0, y0, y0+length, y0+length, y0, y0, y0+length, y0+length]
z = [z0, z0, z0, z0, z0+length, z0+length, z0+length, z0+length]
# メッシュを構成する頂点と面の組み合わせを指定(三角形の組み合わせで描写)
i = [0, 0, 0, 0, 1, 1, 4, 4, 0 ,0, 3, 3]
j = [1, 2, 1, 5, 2, 6, 5, 6, 3 ,4, 2, 6]
k = [2, 3, 5, 4, 6, 5, 6, 7, 7 ,7, 6, 7]
# Mesh3d オブジェクトを作成して描画
self.fig.add_trace(go.Mesh3d(x=x, y=y, z=z,
i=i, j=j, k=k,
opacity=0.5, color='blue'))
def add_sphere(self, radius, origin=(0, 0, 0), color='rgb(0, 0, 255)', opacity=0.4,):
r = radius
phi, theta = np.mgrid[0:2*np.pi:100j, 0:np.pi:50j]
x = r * np.sin(theta) * np.cos(phi) + origin[0]
y = r * np.sin(theta) * np.sin(phi) + origin[1]
z = r * np.cos(theta) + origin[2]
# Define colors for the sphere
colors = np.full(x.shape, color, dtype=str)
self.fig.add_trace(go.Surface(
x=x, y=y, z=z,
colorscale=[[0, color], [1, color]],
surfacecolor=colors,
opacity=opacity
))
def show(self):
self.fig.show()
if __name__ == "__main__":
# デモンストレーション用のコード
# 使用例
visualizer = Visualizer3D()
# 初期設定
visualizer.config_set_xyz_range([-5000,5000],[-5000,5000],[-5000,5000])
visualizer.config_set_window_size(1000, 1000)
# 点を追加
point01 = random.sample(range(3000), 3)
point02 = random.sample(range(3000), 3)
point03 = random.sample(range(3000), 3)
# visualizer.add_point(point01)
# visualizer.add_point(point02)
# visualizer.add_point(point03)
# visualizer.add_plane(point01, point02, point03)
# 面を追加
point10 = random.sample(range(3000), 3)
point11 = random.sample(range(3000), 3)
point12 = random.sample(range(3000), 3)
# visualizer.add_plane(point10, point11, point12)
# ベクトルを追加
point1 = random.sample(range(3000), 3)
point2 = random.sample(range(3000), 3)
point3 = random.sample(range(3000), 3)
point4 = random.sample(range(3000), 3)
# visualizer.add_vector(point1, point2)
# visualizer.add_vector(point3, point4)
# visualizer.add_vector([0,0,0], [500, 0, 0])
# 回転行列のテスト
point_from = np.array([0, 0, 0])
point_to = np.array([1000, 1000, 1000])
visualizer.add_vector(point_from, point_to)
print(point_to)
# 回転行列
# ロドリゲスの回転行列を計算
axis = [0, 0, 1] # 回転軸
theta = 45 # 回転角
rad = np.deg2rad(theta)
R1 = vc.rodrigues_rotation_matrix(rad, axis)
t1 = [0, 0, 2000]
print("ロドリゲスの回転行列:")
print(R1)
print('-------------------------------')
for i in range(3):
point_to = np.dot(R1, point_to)
visualizer.add_vector(point_from, point_to)
print(point_to)
# キューブを追加
# vp.add_cube(1000, 2000, 4000, 400)
# 座標軸を追加
visualizer.add_axis([0, 0, 0])
# 座標軸を追加
visualizer.add_axis([0, 0, 0], R=R1, t=t1)
# 描写
visualizer.show()
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme