3D坐标轴下画一个姿态、位置可调整的圆柱体 您所在的位置:网站首页 3dmax怎么画横着的圆柱体 3D坐标轴下画一个姿态、位置可调整的圆柱体

3D坐标轴下画一个姿态、位置可调整的圆柱体

2024-07-11 01:32| 来源: 网络整理| 查看: 265

matplotlib中3D坐标轴下圆柱体的绘制 关于圆柱体的绘制圆柱的姿态问题代码示例

介绍下需求:使用matplotlib在一个3D坐标轴下绘制任意位置、任意姿态的圆柱体。 在这里插入图片描述

分析:可以看出这里主要解决的问题有两个,一个是绘制圆柱体,另一个是圆柱体的姿态控制。其中对于姿态的控制,需要用到欧拉旋转矩阵。

核心思想:

首先绘制中心坐标为(0,0,0)的半径为1、高为1的圆柱面(相当于是单位1的圆柱面),注意此时绘制出来的没有上底和下底,圆柱面的绘制主要通过将高度坐标1分为两份(-0.5,0.5)即底边和顶边的高度对应z坐标,将2*pi的角度u平分成若干份,sin(u)对应x坐标,cos(u)对应y坐标(此处利用圆心为(0,0)的极坐标公式)将每个高度z与x,y分别对应,此时即得到圆柱体上底与下底的三维坐标,此时对x,y,z坐标进行相应调整即可构造出不同位置,不同姿态,不同大小的圆柱体的上底和下底的三维坐标利用matplotlib中的plot_surface方法即可绘制出圆柱面,此时绘制的仅仅为圆柱曲面,另外需要把两个底面补上,利用上面得到的上底与下底的3维坐标,利用add_collection3d方法即可将底面和顶面补上。 关于圆柱体的绘制

plot_surface函数的定义如下:

def plot_surface(self, X, Y, Z, *args, norm=None, vmin=None, vmax=None, lightsource=None, **kwargs): """ Create a surface plot. Parameters ---------- X, Y, Z : 2d arrays color : color-like Color of the surface patches.可以设置16进制的rgb颜色 rstride=1, # rstride(row)指定行的跨度 cstride=1, # cstride(column)指定列的跨度

add_collection3d函数的定义

def add_collection3d(self, col, zs=0, zdir='z'): """ Add a 3D collection object to the plot. 2D collection types are converted to a 3D version by modifying the object and adding z coordinate information. Supported are: - PolyCollection - LineCollection - PatchCollection """

PolyCollection表示3维多边形的集合类,可以通过该类对平面多边形给出正确的填充外观,该类的定义如下:

def __init__(self, verts, *args, zsort='average', **kwargs): """ Parameters ---------- verts : list of array-like Nx3 Each element describes a polygon as a sequence of ``N_i`` points ``(x, y, z)``. facecolors:可以为平面设置16进制的rgb颜色 """

Notes: 关于圆柱面的绘制可以参考https://blog.csdn.net/weixin_41494909/article/details/86257870

PolyCollection类中的verts参数为包含表示多边形的坐标的元组的list,进而通过add_collection3d函数在3D坐标轴下绘制填充颜色的平面。多边形填充这部分参考:https://stackoverflow.com/questions/64029288/plotting-poly3dcollection-using-add-collection3d

圆柱的姿态问题

解释一下欧拉角: 在这里插入图片描述 如上图所示欧拉角Yaw,Pitch以及Roll,这三个角度的可以决定物体的姿态,由这3个角度可计算欧拉旋转矩阵,而相对于观察坐标系,物体的姿态发生变化时,只需要通过原位置坐标乘以欧拉旋转矩阵即可得到姿态变化后的物体在观测坐标系下的坐标。 更详细的内容可以参考:https://www.cnblogs.com/flyinggod/p/8144100.html 由上面的图,可以看出来,对于圆柱体而言,无论Yaw角度如何变化,物体的姿态是不变化的,所以对于圆柱体而言,只有pitch和Roll角度控制着物体的姿态。 欧拉旋转矩阵的实现代码如下:

def RotationMatrix(theta, phi, psi): '''将观测坐标系中的向量v转换成物体坐标系中向量v'或者将向量(坐标)绕原点旋转. Notes ----- 此程序旋转顺序(z->y->x),内旋. .每种特定顺序的外旋等价于其相反顺序的内旋,反之亦然. .坐标系绕原点旋转的旋转矩阵与向量(坐标)绕原点旋转的旋转矩阵互为转置. .世界坐标系向目标坐标系旋转的旋转矩阵与目标坐标系向世界坐标系旋转的旋转矩阵互为转置. ''' theta, phi, psi = theta * pi / 180, phi * pi / 180, psi * pi / 180 Rz = np.mat([[cos(psi), sin(psi), 0], [-sin(psi), cos(psi), 0], [0, 0, 1]]) Ry = np.mat([[cos(theta), 0, -sin(theta)], [0, 1, 0], [sin(theta), 0, cos(theta)]]) Rx = np.mat([[1, 0, 0], [0, cos(phi), sin(phi)], [0, -sin(phi), cos(phi)]]) return Rx * Ry * Rz 代码示例

示例:

import numpy as np from math import * from mpl_toolkits.mplot3d.art3d import Poly3DCollection import matplotlib.pyplot as plt class Target(object): """Refer in particular to cylinder targets. Attributes ---------- radius: float The radius of the base of a cylinder pitch: float the pitch angle of the cylinder roll: float the roll angle of the cylinder yaw:float the roll angle of the cylinder length: float the length of the target position: list the position of the target, [x, y, z] """ def __init__(self, radius, pitch, roll, yaw, length, position_x, position_y, position_z, **kwargs): self.radius = radius self.pitch = pitch self.roll = roll self.yaw = yaw self.length = length self.position = [position_x, position_y, position_z] def RotationMatrix(theta, phi, psi): '''将观测坐标系中的向量v转换成物体坐标系中向量v'或者将向量(坐标)绕原点旋转. Notes ----- 此程序旋转顺序(z->y->x),内旋. .每种特定顺序的外旋等价于其相反顺序的内旋,反之亦然. .坐标系绕原点旋转的旋转矩阵与向量(坐标)绕原点旋转的旋转矩阵互为转置. .世界坐标系向目标坐标系旋转的旋转矩阵与目标坐标系向世界坐标系旋转的旋转矩阵互为转置. ''' theta, phi, psi = theta * pi / 180, phi * pi / 180, psi * pi / 180 Rz = np.mat([[cos(psi), sin(psi), 0], [-sin(psi), cos(psi), 0], [0, 0, 1]]) Ry = np.mat([[cos(theta), 0, -sin(theta)], [0, 1, 0], [sin(theta), 0, cos(theta)]]) Rx = np.mat([[1, 0, 0], [0, cos(phi), sin(phi)], [0, -sin(phi), cos(phi)]]) return Rx * Ry * Rz def show_cylinder(fig, target): """在3D坐标轴下展示一个任意位置,任意姿态的圆柱体 Parameters ---------- fig : matplotlib.figure.Figure 传入一个空白的fig target : class Target 一个圆柱体 """ fig.clf() # Clear the figure in different detection scene # show the metal cylinder u = np.linspace(0, 2 * np.pi, 50) # 把圆划分50等份 h = np.linspace(-0.5, 0.5, 2) # 把高(1m)划分两等份,对应上底和下底 x = target.radius * np.sin(u) y = target.radius * np.cos(u) x = np.outer(x, np.ones(len(h))) # 20*2 y = np.outer(y, np.ones(len(h))) # 20*2 z = np.outer(np.ones(len(u)), h) # 20*2 z = z * target.length x_rotation = np.ones(x.shape) # 旋转后的坐标 20*2 y_rotation = np.ones(y.shape) z_rotation = np.ones(z.shape) th1 = target.pitch th2 = target.roll th3 = target.yaw a = np.array(RotationMatrix(th1, th2, th3)) # 3*3 pitch,roll for i in range(2): r = np.c_[x[:, i], y[:, i], z[:, i]] # 20*3 rT = r @ a # 20*3 x_rotation[:, i] = rT[:, 0] y_rotation[:, i] = rT[:, 1] z_rotation[:, i] = rT[:, 2] ax = fig.add_subplot(projection='3d') ax.view_init(30, 45) ax.plot_surface(x_rotation + target.position[0], y_rotation + target.position[1], z_rotation + target.position[2], color='#E7C261', alpha=1, antialiased=False) verts = [list(zip(x_rotation[:, 0] + target.position[0], y_rotation[:, 0] + target.position[1], z_rotation[:, 0] + target.position[2]))] ax.add_collection3d(Poly3DCollection(verts, facecolors='#E7C261')) verts = [list(zip(x_rotation[:, 1] + target.position[0], y_rotation[:, 1] + target.position[1], z_rotation[:, 1] + target.position[2]))] ax.add_collection3d(Poly3DCollection(verts, facecolors='#E7C261')) ax.set_xticks(np.arange(-2, 3, 1)) ax.set_yticks(np.arange(-2, 3, 1)) ax.set_xlabel('X/m') ax.set_ylabel('Y/m') ax.set_zlabel('Z/m') ax.set_xlim(-2, 2) ax.set_ylim(-2, 2) ax.set_zlim(target.position[2] - 2, 0.1) ax.grid(None) # delete the background grid target = Target(0.2, 0, 0, 0, 1, 0, 0, -5) fig = plt.figure() show_cylinder(fig, target) plt.show()

运行结果: 在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有