本文是利用python生成一颗行星以及它周围的环带,它是由线、点构造而成的二维平面图形。
可根据自己的想法更改参数得到不同的结果,可更改颜色、光线方向、阴影等参数,实现以上结果源码如下:
"""
本代码绘制了小行星以及它周围的环带
"""
import numpy as np
import matplotlib.pyplot as plt
from math import sin, cos, radians, sqrt
def rotx(xc, yc, zc, xp, yp, zp, Rx):
g[0] = xp + xc
g[1] = yp * cos(Rx) - zp * sin(Rx) + yc
g[2] = yp * sin(Rx) + zp * cos(Rx) + zc
return g
def roty(xc, yc, zc, xp, yp, zp, Ry):
g[0] = xp * cos(Ry) + zp * sin(Ry) + xc
g[1] = yp + yc
g[2] = -xp * sin(Ry) + zp * cos(Ry) + zc
return g
def rotz(xc, yc, zc, xp, yp, zp, Rz):
g[0] = xp * cos(Rz) - yp * sin(Rz) + xc
g[1] = xp * sin(Rz) + yp * cos(Rz) + yc
g[2] = zp + zc
return g
plt.axis([0,150,100,0])
plt.axis('off')
plt.grid(False)
print('冲冲冲!!!!!')
#定义参数
g=[0]*3
xc=80 #圆心
yc=50
zc=0
rs=25 #球面半径
lx=-1 #光线单位矢量分量
ly=0
lz=0
IA=0 # 定义曲线
IB=.8
n=2
Rx=radians(-20)
Ry=radians(0)
Rz=radians(30)
# 添加背景色
for x in np.arange(0,150,1):
for y in np.arange(0,100,1):
plt.scatter(x,y,color = 'midnightblue')
#绘制球体
## 横向
phi1 = radians(-90)
phi2 = radians(90)
dhpi = radians(2)
alpha1 = radians(0)
alpha2 = radians(360)
dalpha = radians(2)
for alpha in np.arange(alpha1,alpha2+dalpha,dalpha):
for phi in np.arange(phi1,phi2+dhpi,dhpi):
xp = rs * cos(phi) * cos(alpha)
yp = rs * sin(phi)
zp = -rs * cos(phi) * sin(alpha)
rotx(xc, yc, zc, xp, yp, zp, Rx)
xp = g[0] - xc
yp = g[1] - yc
zp = g[2] - zc
roty(xc, yc, zc, xp, yp, zp, Ry)
xp = g[0] - xc
yp = g[1] - yc
zp = g[2] - zc
rotz(xc, yc, zc, xp, yp, zp, Rz)
xpg = g[0]
ypg = g[1]
zpg = g[2]
a = xpg - xc
b = ypg - yc
c = zpg - zc
qp = sqrt(a*a+b*b+c*c)
nx = a/qp
ny = b/qp
nz = c/qp
ndotl = nx * lx + ny * ly + nz * lz
I = IA + (IB-IA)*((1+ndotl)/2)**n
if phi == phi1:
xpglast = xpg
ypglast = ypg
if nz < 0:
plt.plot([xpglast,xpg],[ypglast,ypg],linewidth = 4,
color = ((1-I),.8*(1-I),.45*(1-I)))
xpglast = xpg
ypglast = ypg
## 纵向
for phi in np.arange(phi1,phi2+dhpi,dhpi):
r = rs * cos(phi)
for alpha in np.arange(alpha1, alpha2 + dalpha, dalpha):
xp = r * cos(alpha)
yp = rs * sin(phi)
zp = -rs * cos(phi) * sin(alpha)
rotx(xc, yc, zc, xp, yp, zp, Rx)
xp = g[0] - xc
yp = g[1] - yc
zp = g[2] - zc
roty(xc, yc, zc, xp, yp, zp, Ry)
xp = g[0] - xc
yp = g[1] - yc
zp = g[2] - zc
rotz(xc, yc, zc, xp, yp, zp, Rz)
xpg = g[0]
ypg = g[1]
zpg = g[2]
a = xpg - xc
b = ypg - yc
c = zpg - zc
qp = sqrt(a*a+b*b+c*c)
nx = a/qp
ny = b/qp
nz = c/qp
ndotl = nx * lx + ny * ly + nz * lz
textbfI = IA + (IB-IA)*((1+ndotl)/2)**n
if alpha == alpha1:
xpglast = xpg
ypglast = ypg
if nz < 0:
plt.plot([xpglast,xpg],[ypglast,ypg],linewidth = 4,
color = ((1-I),.8*(1-I),.45*(1-I)))
xpglast = xpg
ypglast = ypg
#绘制外围环形带
alpha1=radians(-10)
alpha2=radians(370)
dalpha=radians(.5)
r1=rs*1.5
r2=rs*2.2
dr=rs*.02
deltar=(r2-r1)/7 #环形带宽
#旋转位于rα的环点p
for r in np.arange(r1,r2,dr):
for alpha in np.arange(alpha1,alpha2,dalpha):
xp=r*cos(alpha)
yp=0
zp=-r*sin(alpha)
rotx(xc,yc,zc,xp,yp,zp,Rx)
xp=g[0]-xc
yp=g[1]-yc
zp=g[2]-zc
roty(xc,yc,zc,xp,yp,zp,Ry)
xp=g[0]-xc
yp=g[1]-yc
zp=g[2]-zc
rotz(xc,yc,zc,xp,yp,zp,Rz)
xpg=g[0]
ypg=g[1]
zpg=g[2]
#选择环带颜色
if r1 <= r < r1+1*deltar:
clr=(.63,.54,.18)
if r1+1*deltar <= r <= r1+2*deltar:
clr=(.78,.7,.1)
if r1+2*deltar <= r <= r1+3*deltar:
clr=(.95,.85,.1)
if r1+3*deltar <= r <= r1+4*deltar:
clr=(.87,.8,.1)
if r1+5*deltar <= r <= r1+7*deltar:
clr=(.7,.6,.2)
#阴影
magu=sqrt(lx*lx+ly*ly+lz*lz)
ux=-lx/magu
uy=-ly/magu
uz=-lz/magu
vx=xc-xpg
vy=yc-ypg
vz=zc-zpg
Bx=uy*vz-uz*vy
By=uz*vx-ux*vz
Bz=ux*vy-uy*vx
magB=sqrt(Bx*Bx+By*By+Bz*Bz)
if magB < rs: #在阴影区域
if vx*lx+vy*ly+vz*lz <= 0:
clr=(.5,.5,.2)
if r1+4*deltar <= r <= r1+5*deltar:
clr='midnightblue'
#绘制线段
if alpha == alpha1:
xstart=xpg
ystart=ypg
if zpg <= zc:
plt.plot([xstart,xpg],[ystart,ypg],linewidth=2,color=clr)
if zpg >= zc:
a=xpg-xc
b=ypg-yc
c=sqrt(a*a+b*b)
if c > rs*1.075: #仅绘制环的可见部分
plt.plot([xstart,xpg],[ystart,ypg],linewidth=2,color=clr)
xstart=xpg
ystart=ypg
plt.show()
本绘制总共分为三部分:首先是定义参数,其次是绘制中心的球体,最后是绘制外围环带。
定义参数是通过建立数学模型,借了书中的示例,对数学感兴趣可参考《python图形编程2D和3D图像的创建》这本书。
绘制球体和外围环带有遮挡和阴影,需要消隐之类的操作,这些在实现的过程中有一定难度。
本图绘制是用线、点构成的,其中背景是用点来构成,而图形是采用线构成,前文效果展示时看不出来,但是将局部放大展示使可以很清楚的看到。这也让我更深刻的理解了“点动成线、线动成面”这句话。很棒!希望本文对学习中的您有帮助。
局部展示图:点为背景,线为图像。