python的真实感图形生成(含源码)

基于python生成真实感图形

  • 简介
  • 一、运行结果图
  • 二、python源码
  • 三、实现思路

简介

  本文是利用python生成一颗行星以及它周围的环带,它是由线、点构造而成的二维平面图形。

一、运行结果图

  源代码运行结果如下:
python的真实感图形生成(含源码)_第1张图片
  去掉坐标轴结果如下:
python的真实感图形生成(含源码)_第2张图片

二、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图像的创建》这本书。
  绘制球体和外围环带有遮挡和阴影,需要消隐之类的操作,这些在实现的过程中有一定难度。
  本图绘制是用线、点构成的,其中背景是用点来构成,而图形是采用线构成,前文效果展示时看不出来,但是将局部放大展示使可以很清楚的看到。这也让我更深刻的理解了“点动成线、线动成面”这句话。很棒!希望本文对学习中的您有帮助。
  局部展示图:点为背景,线为图像。
python的真实感图形生成(含源码)_第3张图片

你可能感兴趣的:(python)