Python生成简单3D管道

笔者最近研究了一下通过python生成简单3D管道的方法。主要通过空间坐标旋转平移的方法,得到管道起止点的圆截面(正多边形顶点——其法线向量与起止点向量相同),根据顶点构建管道面。并保存为obj文件。obj文件仅包含顶点v、组g、面f。

matplotlib,mpl_toolkits仅用于测试查看管道截面圆顶点的坐标生成情况。

代码如下:

import os, sys

from math import cos, sin, sqrt, atan2, pi, acos

from matplotlib import colors

import numpy as np

import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

import psycopg2

import config

import pghelper

# 获取绕Z轴旋转矩阵

def GetRotateMatrix_AngleZ(az):

raz = np.array([[cos(az), -sin(az), 0.000, 0.000],

[sin(az), cos(az), 0.000, 0.000],

[0.0000, 0.0000, 1.0000, 0.0000],

[0.0000, 0.0000, 0.0000, 1.0000]])

return raz

# 获取绕X轴旋转矩阵

def GetRotateMatrix_AngleX(ax):

rax = np.array([[1.0000, 0.0000, 0.000, 0.000],

[0.000, cos(ax), -sin(ax), 0.0000],

[0.000, sin(ax), cos(ax), 0.000],

[0.0000, 0.0000, 0.0000, 1.0000]])

return rax

# 获取绕Y轴旋转矩阵

def GetRotateMatrix_AngleY(ay):

ray = np.array([[cos(ay), 0.0000, sin(ay), 0.0000],

[0.0000, 1.0000, 0.0000, 0.0000],

[-sin(ay), 0.0000, cos(ay), 0.0000],

[0.0000, 0.0000, 0.0000, 1.0000]])

return ray

# 获取旋转矩阵(对象坐标系坐标旋转到世界坐标系)

def GetRotationMatrix(ax, ay, az):

# 对象坐标系坐标旋转到世界坐标系,先旋转Y再X再Z,反之则先后循序相反

raz = GetRotateMatrix_AngleZ(az)

rax = GetRotateMatrix_AngleX(ax)

ray = GetRotateMatrix_AngleY(ay)

return np.dot(np.dot(ray, rax), raz)

# 世界坐标系到对象坐标系

# return np.dot(np.dot(raz, rax), ray)

# 生成空间直线起止点的圆柱体(圆或多边形顶点沿直线放样)底面和顶面多边形顶点points_start、points_end

def GetPipePoints(startpoint, endpoint, radius, num):

x1, y1, z1 = startpoint[0], startpoint[1], startpoint[2]

x2, y2, z2 = endpoint[0], endpoint[1], endpoint[2]

dx, dy, dz = x2 - x1, y2 - y1, z2 - z1

sxy = sqrt(dy**2 + dx**2)

az = -atan2(dy, dx)

ax = 0

ay = atan2(dz, sxy)

# print("sxy=", sxy)

# print("az=", az * 180 / pi)

# print("ay=", ay * 180 / pi)

rrM = GetRotationMatrix(ax, ay, az)

circlepoints = getcirclepoints(radius, num)

point3d = np.dot(circlepoints, rrM)

parr1 = np.array([x1, y1, z1, 1])

parr2 = np.array([x2, y2, z2, 1])

# print(point3d)

points_start = point3d + parr1

points_end = point3d + parr2

return points_start, points_end

def getcirclepoints(radius, num):

points = []

for i in range(num):

angle = i * pi * 2 / num

y = cos(angle) * radius

z = sin(angle) * radius

points.append([0, -y, z, 1])

return points

# 新坐标系(以空间直线(P1,P2,已知P1、P2在世界坐标系的三维坐标)为X'轴,过直线P1P2且垂直于世界OXY面的面内,垂直于P1P2的方向为Z'轴,垂直于X'和Z'轴的Y'轴构成新坐标系)

# 将新坐标系的多边形顶点转换为原世界坐标系的坐标。

def TestRotation():

startpoint = [50, 50, 50]

endpoint = [200.0, 100.0, 175.0]

radius = 20

num = 12

points_start, points_end = GetPipePoints(startpoint, endpoint, radius, num)

np.set_printoptions(suppress=True)

#定义坐标轴

fig = plt.figure()

axio = Axes3D(fig)

# 设置坐标轴标题和刻度

axio.set(xlabel='X', ylabel='Y', zlabel='Z')

axio.set_xlim3d(-50, 200)

axio.set_ylim3d(-50, 200)

axio.set_zlim3d(-50, 200)

for p in points_start:

x, y, z = p[0], p[1], p[2]

axio.scatter3D(x, y, z, cmap='Blues')

for p in points_end:

x, y, z = p[0], p[1], p[2]

print(x, y, z)

axio.scatter3D(x, y, z, cmap='Blues')

a = sqrt((startpoint[0] - endpoint[0])**2 +

(startpoint[1] - endpoint[1])**2 +

(startpoint[2] - endpoint[2])**2)

for i in range(len(points_start)):

# if i % 3 == 0: continue

pointp = points_start[i]

b = sqrt((pointp[0] - endpoint[0])**2 + (pointp[1] - endpoint[1])**2 +

(pointp[2] - endpoint[2])**2)

c = sqrt((pointp[0] - startpoint[0])**2 +

(pointp[1] - startpoint[1])**2 +

(pointp[2] - startpoint[2])**2)

cosA = (b**2 + c**2 - a**2) / (2 * b * c)

cosB = (a**2 + c**2 - b**2) / (2 * a * c)

cosC = (b**2 + a**2 - c**2) / (2 * b * a)

# print(f"cosA={cosA} cosB={cosB} cosC={cosC}")

a_angle = acos(cosA) * 180.0 / pi

b_angle = acos(cosB) * 180.0 / pi

c_angle = acos(cosC) * 180.0 / pi

print(

f"a={a} b={b} c={c} a_angle={a_angle} b_angle={b_angle} c_angle={c_angle}"

)

# print(f"a_angle={a_angle} b_angle={b_angle} c_angle={c_angle}")

linex = np.linspace(startpoint[0], endpoint[0], 100)

liney = np.linspace(startpoint[1], endpoint[1], 100)

linez = np.linspace(startpoint[2], endpoint[2], 100)

axio.plot3D(linex, liney, linez)

# XX = [point3d_2[0] for i in range(len(point3d_2))]

# YY = [point3d_2[1] for i in range(len(point3d_2))]

# ZZ = [point3d_2[2] for i in range(len(point3d_2))]

# axio.plot_surface(XX,YY,ZZ,color="r")

# print(XX)

# axio.legend()

# plt.zlabel('z')

plt.show()

def writepipeobj3d(pgconnectparam,file,facesnum):

pgconn = pghelper.connectdb(pgconnectparam)

pgcur = pgconn.cursor()

sql = '''select id,x1,y1,z1,x2,y2,z2 from js_line

where   x1 is not null and

x2 is not null and

y1 is not null and

y1 is not null and

z1 is not null and

z1 is not null LIMIT 10 ;

'''

pgcur.execute(sql)

rows = pgcur.fetchall()

k = 0

num = facesnum

vertexes = []

Faces = []

for row in rows:

(id, x1, y1, z1, x2, y2, z2) = row

# 管道半径应该在数据row中获取

radius = 1.0

startpoint = [float(x1), float(y1), float(z1)]

endpoint = [float(x2), float(y2), float(z2)]

points_start, points_end = GetPipePoints(startpoint, endpoint,

radius, num)

k = len(vertexes)

for p in points_start:

x, y, z = p[0], p[1], p[2]

x = x - 3370000

y = y - 500000

vertexes.append([x, y, z])

file.write(f"v {y:.4f} {x:.4f} {z:.4f}\n")

for p in points_end:

x, y, z = p[0], p[1], p[2]

x = x - 3370000

y = y - 500000

vertexes.append([x, y, z])

file.write(f"v {y:.4f} {x:.4f} {z:.4f}\n")

file.write(f"g cube_{id}\n")

for i in range(k + 1, k + num):

# f = [i, i + 1, i + num, i + num + 1]

v1, v2, v3, v4 = i + 1, i, i + num, i + num + 1

Faces.append([v1, v2, v3, v4])

file.write(f"f {v1} {v2} {v3} {v4}\n")

v1, v2, v3, v4 = k + 1 , k + num, k + 2 * num, k + num+1

Faces.append([v1, v2, v3, v4])

file.write(f"f {v1} {v2} {v3} {v4}\n")

pgcur.close()

pgconn.close()

def main():

(dataconfigxmlfile, templatexmlfile, mdbfilename, pgconnectparam,

pipetables, surfaceobj) = config.readconfig()

file3d = "mypipe.obj"

open(file3d, "w")

with open(file3d, mode="a") as file:

writepipeobj3d(pgconnectparam,file,12)

print("管道生成完成!")

if __name__ == "__main__":

np.set_printoptions(suppress=True)

# TestRotation()

main()

(0)

相关推荐

  • 【技术综述】万字长文详解Faster RCNN源代码

    言有三 毕业于中国科学院,计算机视觉方向从业者,有三工作室等创始人 作者 | 言有三 编辑 | 言有三/Yolo 作为深度学习算法工程师,如果你想提升C++水平,就去研究caffe源代码,如果你想提升 ...

  • 解析Transformer模型

    ❝ GiantPandaCV导语:这篇文章为大家介绍了一下Transformer模型,Transformer模型原本是NLP中的一个Idea,后来也被引入到计算机视觉中,例如前面介绍过的DETR就是将 ...

  • 鱼池过滤超级简单3D详细教程视频

    鱼池过滤超级简单3D详细教程视频

  • 用 python 编写简单的证书域名到期报警脚本

    将脚本放在服务器的计划任务内,定时检测,证书到期不足60天发送报警邮件及钉钉提醒. 在服务器上需要提前安装好 requests 库. pip install requests 钉钉机器人 https: ...

  • Web前端和Python哪个简单?Python学习!

    Web前端和Python都比较简单,适合零基础的人员学习,但两者之间就业方向不同.前景不同,所以很多人在选择上犯了难,不知道学习Web前端好还是Python好,接下来为大家分析一下. 其实Web前端和 ...

  • Python语言简单介绍及安装

    到目前为止,我已经学习过不少语言了,C.C++.Java甚至C#我也曾看过一两本书,但仍旧没找到一种最适合我的,或者说是我最适合的(哎,太不专一不说,还都只学到皮毛 ). 最近受新老板的影响,要用py ...

  • 用 Python 生成炫酷二维码及解析

    说到二维码大家一定不陌生,可以说现在二维码几乎渗透到了我们生活的各个角落,举例来说吧,我们到超市商场购物时扫描二维码付款,我们出行时乘坐公交地铁扫描二维码进站,我们到菜鸟驿站取件时扫描二维码取件,如果 ...

  • 算法创作 | 用python解决简单的数学运算

    前言朴实无华的基础练习却能为自身的学习奠定无限可能问题描述使用while函数完成:输出1到100之间的偶(奇)数输出1-2+3-4+...+99-100的和用python的math工具结合if:解决一 ...

  • Python|关于简单插入排序的奥秘

    前言 相信大家在生活中经常会遇到排序的问题,比如,如果你是超市工作人员,看到货架上的货品被顾客弄乱了,你一定会重新给货品排序,基本上是按从小到大.从矮到高的顺序摆放.在家里面,你也一定会给家里的物品按 ...

  • Python做简单爬虫(urllib.request怎么抓取https以及伪装浏览器访问的方法)

    一:抓取简单的页面: 用Python来做爬虫抓取网站这个功能很强大,今天试着抓取了一下百度的首页,很成功,来看一下步骤吧 首先需要准备工具: 1.python:自己比较喜欢用新的东西,所以用的是Pyt ...

  • 有人说Python是青铜?我用50行Python代码绘制3D机场分布图

    原创 菜鸟哥 菜鸟学Python 2020-03-23 绘制一款的3D图形,不仅可以直观的展示数据分析的结果,也更方便数据化运营,同时也让工作成果更容易被大众理解.本文就基于python绘制一款基础的 ...