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 arrayscolor : color-likeColor 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 bymodifying 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 Nx3Each 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 / 180Rz = 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 pltclass Target(object):"""Refer in particular to cylinder targets.Attributes----------radius: floatThe radius of the base of a cylinderpitch: floatthe pitch angle of the cylinderroll: floatthe roll angle of the cylinderyaw:floatthe roll angle of the cylinderlength: floatthe length of the targetposition: listthe position of the target, [x, y, z]"""def __init__(self, radius, pitch, roll, yaw, length, position_x, position_y, position_z, **kwargs):self.radius = radiusself.pitch = pitchself.roll = rollself.yaw = yawself.length = lengthself.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 / 180Rz = 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 * Rzdef show_cylinder(fig, target):"""在3D坐标轴下展示一个任意位置,任意姿态的圆柱体Parameters----------fig : matplotlib.figure.Figure传入一个空白的figtarget : class Target一个圆柱体"""fig.clf()  # Clear the figure in different detection scene# show the metal cylinderu = 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*2y = np.outer(y, np.ones(len(h)))  # 20*2z = np.outer(np.ones(len(u)), h)  # 20*2z = z * target.lengthx_rotation = np.ones(x.shape)  # 旋转后的坐标 20*2y_rotation = np.ones(y.shape)z_rotation = np.ones(z.shape)th1 = target.pitchth2 = target.rollth3 = target.yawa = np.array(RotationMatrix(th1, th2, th3))  # 3*3 pitch,rollfor i in range(2):r = np.c_[x[:, i], y[:, i], z[:, i]]  # 20*3rT = r @ a  # 20*3x_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 gridtarget = Target(0.2, 0, 0, 0, 1, 0, 0, -5)
fig = plt.figure()
show_cylinder(fig, target)
plt.show()

运行结果:

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

  1. 用python画一个动态樱花

    还是很好看的,哈哈 代码写在下面啦 <!doctype html> <html> <head> <meta http-equiv="Pragma&q ...

  2. 用opengl画一个3D机器人 完整源码 直接使用

    机器人代码: 1.copy就可以运行,前提是要配置好opengl的环境. 2.最后有使用说明. // first.cpp : Defines the entry point for the conso ...

  3. 用php编写一个正方体,three.js画一个3D立体的正方体教程

    Three.js是一个3DJavaScript库,基于右手坐标系,可以创建简单或是比较复杂的三维图形并应用丰富多彩的纹理和材质,可以添加五光十色的光源,可以在3D场景中移动物体或是添加脚本动画等等.本 ...

  4. 用Python画一个3D太阳系

    用Python画一个平面的太阳系得到一些朋友的欣赏,然后有同学提出了绘制三维太阳系的要求. 从Python画图的角度来说,三维太阳系其实并不难,问题在于八大行星对黄道面的倾斜太小,所以尽管画个三维的图 ...

  5. 使用matplotlib给女朋友画一个爱心吧,这份满满的爱意,一定要记得收下

    使用matplotlib给女朋友画一个爱心吧,这份满满的爱意,一定要记得收下 1.起因 女朋友总是查你的电脑,于是想到是否可以画一个爱心呢​!最后经过不懈的努力找到了一个非常简单的​实现方式,用起来看 ...

  6. 图形学笔记(七)画一个 3D 的彩色的立方体

    画完会动的 3D 矩形,现在玩点高级的,画一个会动的 3D 彩色的立方体. 一.代码 main.cpp #include <iostream>//GLEW #define GLEW_STA ...

  7. 编写程序,生成一种贯穿10*10字符数组(初始时全为字符'.')的“随机步法”。程序必须随机地从一个元素“走到”另一个元素,每次都向上、向下、向左或向右移动一个元素位置

    编写程序,生成一种贯穿10*10字符数组(初始时全为字符'.')的"随机步法".程序必须随机地从一个元素"走到"另一个元素,每次都向上.向下.向左或向右移动一个 ...

  8. python在坐标轴上画矩形_Python使用matplotlib实现在坐标系中画一个矩形的方法

    本文实例讲述了Python使用matplotlib实现在坐标系中画一个矩形的方法.分享给大家供大家参考.具体实现方法如下: import matplotlib.pyplot as plt from m ...

  9. 使用CAXA 3D实体画一个立体五角星

    第一步:新建设计,从设计元素库中拖拽一个三棱锥. 第二步:编辑三棱锥的截面,删除原有的截面图素,更改我们想画的五角星的大小. 第三步:画一个五角星. 第四步:退出草图编辑,得到立体五角星. 第五步:可 ...

最新文章

  1. linux进程间通信:popen函数通过管道与shell通信
  2. MySQL的datetime日期格式化,和Oracle的datetime日期格式化
  3. java poi读取word中附件_Java POI导入word, 带图片
  4. 2021-03-09了解示隐式接口和编译时多态
  5. Spring Boot2整合Shiro(1):身份认证
  6. Uniswap 24h交易量约为10.6亿美元涨2.91%
  7. 更适合智能家庭使用的新 Wi-Fi 技术问世了
  8. C# 一个基于.NET Core3.1的开源项目帮你彻底搞懂WPF框架Prism
  9. 计算机文化基础测试题网教,计算机文化基础测试题
  10. Win10 环境变量配置
  11. Misumi米思米数据线驱动无法安装
  12. c# 抓取数据的3种方法
  13. Android应用切换皮肤功能实现
  14. 【机器人学】机器人开源项目KDL源码学习:(9)KDL中的内联函数
  15. 从个人网站到泛生活化平台 百货之家背后的故事
  16. 一文搞懂浏览器缓存机制
  17. 模电(三)晶体三极管
  18. altc财金网为你分享币圈波段操作技巧
  19. linux中giep命令作用,Linux查看硬件信息以及驱动设备的命令
  20. 向新而生保业务增长,亚信科技持续锻造“核心引擎”

热门文章

  1. 逆向工程核心原理——PE文件格式分析
  2. Java NIO通信框架在电信领域的实践
  3. 【make_shared的使用】
  4. 计算机毕业设计Java普通中学体育卫生信息管理系统(源码+系统+mysql数据库+lw文档)
  5. 唐尼vr眼镜好吗_USP和唐尼VR眼镜哪个好
  6. 深度学习图形工作站配置
  7. 齐次线性方程-基础解系与解向量的关系
  8. 想教小学计算机面试报哪个,小学教师资格证面试,建不建议考信息技术?
  9. C# --什么时候用迭代器(Iterator)?
  10. springmvc关于404的异常处理