主頁 > 軟體設計 > 天空盒里放風箏,OpenGL就這么任性:想怎么放,就怎么放!

天空盒里放風箏,OpenGL就這么任性:想怎么放,就怎么放!

2021-04-15 10:56:21 軟體設計

文章目錄

  • 1 前言
  • 2 原材料
    • 2.1 Python環境和模塊
    • 2.2 草原和風箏素材
    • 2.3 打開IDLE,匯入模塊
  • 3 制作工序
    • 3.1 藍天和草原
    • 3.2 第一只風箏
    • 3.3 給風箏加上線
    • 3.4 讓風箏動起來
    • 3.5 放飛更多的風箏
  • 4 完整原始碼

1 前言

今天是農歷的三月初三,相傳這一天是軒轅黃帝的誕辰日,春秋時期,三月初三的紀念活動還是非常隆重的,至魏晉則演變為達官顯貴、文人雅士臨水宴飲的節日,蘭亭序中提到的"曲水流觴",也許就是這一習俗的寫照吧(個人猜想,未經考證),唐以后,三月初三漸漸湮沒于歷史的長河中,

于我而言,三月初三卻是一個放風箏的日子,每逢這一天,耳邊總會響起一首老歌:又是一年三月三,風箏飛滿天……上班路上,看道路兩側草長鶯飛、楊柳拂面,一時玩心頓起:何不用3D構造一個天上白云飄飄,地上綠草茵茵的虛幻空間,在里面放飛幾只風箏自娛自樂呢?

心動不如行動,打開Python的IDLE,經過一番嘗試,竟然輕松在一片遼闊的草原上放飛了幾只風箏,風箏們迎風飄動,長長的風箏線像懸鏈一樣跟著擺動,拖動滑鼠,還可以從不同的角度、距離欣賞,恍若置身于大草原上,

在這里插入圖片描述

如果覺得好玩,就跟我一起到草原放風箏吧,先說好了,你可以搭我的便車,食宿請自理,不多說了,快上車!

2 原材料

2.1 Python環境和模塊

一臺安裝了Python環境的電腦,Python環境需要安裝以下模塊,

  • numpy
  • scipy
  • pillow
  • wxgl

如果沒有上述模塊,請參考下面的命令安裝,我剛剛升級了wxgl模塊(從0.6.3升級到0.6.4),如果此前有安裝,請洗掉后再次安裝.

pip install numpy
pip install scipy
pip install pillow
pip install wxgl

NumPy和pillow是Python旗下最常用的科學計算庫和影像處理庫,屬于常用模塊,WxGL是一個基于PyOpenGL的三維資料可視化庫,以wx為顯示后端,提供Matplotlib風格的互動式應用模式,同時,也可以和wxPython無縫結合,在wx的表單上繪制三維模型,關于WxGL的更多資訊,請參閱我的另一篇博客《十分鐘玩轉3D繪圖:WxGL完全手冊》,

2.2 草原和風箏素材

請下載下面的草原和風箏素材,保存到專案路徑下的res檔案夾中,如果使用其他圖片,請保持草原圖片的寬高比為4:3,風箏素材需要帶透明通道的png格式,

草原素材:sky.jpg
在這里插入圖片描述
風箏素材:butterfly.jpg
在這里插入圖片描述

風箏素材:eagle.jpg
在這里插入圖片描述
風箏素材:fish.jpg
在這里插入圖片描述

2.3 打開IDLE,匯入模塊

>>> import numpy as np
>>> from PIL import Image
>>> import wxgl.wxplot as plt # 互動式3D繪圖庫
>>> from scipy.spatial.transform import Rotation # 空間旋轉計算

3 制作工序

3.1 藍天和草原

用3D繪制天空,最常用的方法是天空頂和天空盒,不過,這兩個方法都有局限性,效果只能說差強人意,我們這里用的是天空盒,所謂天空盒,顧名思義,就是從一張圖片上裁切出六個矩形,拼成一個六面體,觀察者站在六面體內,就有了“天蒼蒼野茫茫”的趕腳,
在這里插入圖片描述
下圖是從上圖裁切出的上下前后左右六個面,
在這里插入圖片描述
了解了天空盒的原理,實作起來就簡單多了,先來裁切上下前后左右六個面,

>>> im = np.array(Image.open(r'D:\temp\kite\res\sky.jpg')) # 打開藍天草原的圖片
>>> u = im.shape[0]//3 # 天空盒(正六面體的棱長)
>>> im_top = im[:u, u:2*u, :]
>>> im_left = im[u:2*u, :u, :]
>>> im_front = im[u:2*u, u:2*u, :]
>>> im_right = im[u:2*u, 2*u:3*u, :]
>>> im_back = im[u:2*u, 3*u:, :]
>>> im_bottom = im[2*u:, u:2*u, :]

再生成立方體的六個面在三維空間中的坐標,其中每個面用四個頂點表示,頂點按逆時針方向排列,立方體的棱長為2,也就是xyzz坐標都在[-1,1]范圍內,

>>> vs_front = np.array([[-1,-1,1], [-1,-1,-1], [-1,1,-1], [-1,1,1]])
>>> vs_left = np.array([[1,-1,1], [1,-1,-1], [-1,-1,-1], [-1,-1,1]])
>>> vs_right = np.array([[-1,1,1], [-1,1,-1], [1,1,-1], [1,1,1]])
>>> vs_top = np.array([[1,-1,1], [-1,-1,1], [-1,1,1], [1,1,1]])
>>> vs_bottom = np.array([[-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1]])
>>> vs_back = np.array([[1,-1,1], [1,-1,-1], [1,1,-1], [1,1,1]])

有了六個面的材質和頂點,就可以使用surface函式繪制天空盒了,

>>> plt.surface(vs_front, texture=im_front, alpha=False)
>>> plt.surface(vs_left, texture=im_left, alpha=False)
>>> plt.surface(vs_right, texture=im_right, alpha=False)
>>> plt.surface(vs_top, texture=im_top, alpha=False)
>>> plt.surface(vs_bottom, texture=im_bottom, alpha=False)
>>> plt.surface(vs_back, texture=im_back, alpha=False)
>>> plt.show()

咦?不對啊,為什么我在天空盒外而不是天空盒內呢?
在這里插入圖片描述
原來,WxGL默認觀察者距離坐標原點5個單位的距離,而天空盒在[-1,1]范圍內,自然就處于天空盒外了,莫著急,只要設定一下畫布函式plt.figure()的引數,就OK了,引數dist用于設定觀察者距離觀察目標的距離,配合方位角引數azimuth和仰角引數elevation,可以確定觀察者位置;引數view用于設定視景體,view陣列的6個元素分別表示視景體的左、右、上、下面,以及前后面距離觀察者的距離,

>>> plt.figure(dist=0.8, view=[-1, 1, -1, 1, 0.8, 7], elevation=0, azimuth=0)
>>> plt.surface(vs_front, texture=im_front, alpha=False)
>>> plt.surface(vs_left, texture=im_left, alpha=False)
>>> plt.surface(vs_right, texture=im_right, alpha=False)
>>> plt.surface(vs_top, texture=im_top, alpha=False)
>>> plt.surface(vs_bottom, texture=im_bottom, alpha=False)
>>> plt.surface(vs_back, texture=im_back, alpha=False)
>>> plt.show()

天空盒最終的效果如下圖所示,嘗試拖動滑鼠、滑動滾輪,你會發現天空盒的缺陷,不過,這不會影響我們放飛風箏,
在這里插入圖片描述
為了方便后續操作,我們將繪制天空盒的代碼封裝成一個函式,

>>> def draw_sky_box():
		plt.surface(vs_front, texture=im_front, alpha=False)
		plt.surface(vs_left, texture=im_left, alpha=False)
		plt.surface(vs_right, texture=im_right, alpha=False)
		plt.surface(vs_top, texture=im_top, alpha=False)
		plt.surface(vs_bottom, texture=im_bottom, alpha=False)
		plt.surface(vs_back, texture=im_back, alpha=False)
>>> 

3.2 第一只風箏

現在觀察者位于(0.8,0,0)的位置,假定風箏中心位于v1點(-0.5,-0.3,0.2)的位置(觀察者左前上方),我們需要根據風箏素材的尺寸,確定風箏在空間中的坐標,

>>> im_kite = np.array(Image.open(r'D:\temp\kite\res\butterfly.png')) # 打開風箏圖片
>>> max_s = max(im_kite.shape) # 風箏的最長邊
>>> dx, dy = 0.1*im_kite.shape[0]/max_s, 0.1*im_kite.shape[1]/max_s # 計算風箏在空間中的實際尺寸
>>> v1 = (-0.5,-0.3,0.2) # 風箏中心位置
>>> vs_kite = np.array([[dx,-dy,0.03], [-dx,-dy,0], [-dx,dy,0], [dx,dy,0.03]]) # 風箏四角的坐標,前端略高(后仰0.03)
>>> vs_kite[:,0] += v1[0] # 從原點移到v1點
>>> vs_kite[:,1] += v1[1] # 從原點移到v1點
>>> vs_kite[:,2] += v1[2] # 從原點移到v1點
>>> plt.figure(dist=0.8, view=[-1, 1, -1, 1, 0.8, 7], elevation=0, azimuth=0) # 設定畫布
>>> draw_sky_box() # 繪制天空盒
>>> plt.surface(vs_kite, texture=im_kite, alpha=True) # 繪制風箏(png格式需要使用透明通道)
>>> plt.show()

至此,終于在草原上放飛了第一只風箏,
在這里插入圖片描述

3.3 給風箏加上線

風箏線近似于一條懸鏈線,我們可以用三次曲線模擬,如果放風箏的人在v0點,風箏中心位于v1點,風箏線就可以用k個點來描述,先來定義一個根據v0點和v1點計算風箏線的函式,

>>> def get_line(v0, v1, k=300):
		m = np.power(np.linspace(0,k,k), 3)/(k*k*k)
		dx, dy = v1[0]-v0[0], v1[1]-v0[1]
		x = v1[0] - m*dx
		y = v1[1] - m*dy
		z = np.linspace(v1[2], v0[2], k)
		return x, y, z
>>> 

重復一遍繪制天空盒和風箏的代碼,稍加修改,即可加上風箏線,

>>> v0 = (0.5,0.2,-1) # 放風箏的人在v0點
>>> v1 = (-0.5,-0.3,0.2) # 風箏中心位于v1點
>>> xs, ys, zs = get_line(v0, v1) # 計算風箏懸鏈線
>>> plt.figure(dist=0.8, view=[-1, 1, -1, 1, 0.8, 7], elevation=0, azimuth=0) # 設定畫布
>>> draw_sky_box() # 繪制天空盒
>>> plt.surface(vs_kite, texture=im_kite, alpha=True) # 繪制風箏
>>> plt.plot(xs, ys, zs, color='#C0C0C0', width=0.3) # 繪制風箏懸鏈線
>>> plt.show()

plt.plot()函式用于繪制點或線,引數width用于設定線寬,如果覺得風箏線不夠明顯,可以適當增加線寬,
在這里插入圖片描述

3.4 讓風箏動起來

想象一下風箏在天空中的飄動姿態,其運動軌跡有兩個特點:

  • 水平方向延弧線擺動,幅度約30°左右
  • 擺動到左側則左側稍低,擺動到右側則右側稍低

據此,不難模擬出風箏的擺動軌跡,計算出運動軌跡線上每一處風箏的坐標,同時計算出對應的風箏懸鏈線,啟動一個定時器,順序顯示軌跡線上每一處風箏及其懸鏈線,形成影片,

WxGL的plt.surface()函式和plt.plot()函式,支持通過引數slide=True將對應的模型放入一個影片序列,執行plt.show()的時候,會自動播放這個模型序列,時間間隔由plt.figure()函式interval的引數決定,默認值100毫秒,如果多個模型需要同時顯示,只需要用name引數為多個模型指定相同的名字即可,

好,我們來定義一個繪制飄動風箏的函式,

>>> def draw_kite(fn, v0, v1, dh=0.03, ex=(-20,20), fs=160):
		im_kite = np.array(Image.open(fn)) # 打開風箏圖片
		max_s = max(im_kite.shape) # 風箏的最長邊
		dx, dy = 0.1*im_kite.shape[0]/max_s, 0.1*im_kite.shape[1]/max_s # 計算風箏在空間中的實際尺寸    
		delta = np.hstack((np.linspace(-0.03, 0.03, fs), np.linspace(0.03, -0.03, fs))) # 風箏左右擺動程序中的高度波動
		theta = np.hstack((np.linspace(ex[0], ex[1], fs), np.linspace(ex[1], ex[0], fs))) # 風箏左右擺動的角度
		vs_kite = np.array([[dx,-dy,dh], [-dx,-dy,0], [-dx,dy,0], [dx,dy,dh]]) # 風箏四角的坐標,前端略高(后仰)
		vs_kite[:,0] += v1[0]
		vs_kite[:,1] += v1[1]
		vs_kite[:,2] += v1[2]    
		offset = np.random.randint(0, 2*fs)
		for i in range(2*fs):
			k = (i+offset)%(2*fs)
			rotator = Rotation.from_euler('xyz', [0, 0, theta[k]], degrees=True)
			vs = rotator.apply(vs_kite)
			vs[:2, 2] -= delta[k]
			vs[2:, 2] += delta[k]
			plt.surface(vs, texture=im_kite, alpha=True, slide=True, name='id_%d'%i)
			xs, ys, zs = get_line(v0, ((vs[0][0]+vs[2][0])/2,(vs[0][1]+vs[2][1])/2,(vs[0][2]+vs[2][2])/2))
			plt.plot(xs, ys, zs, color='#C0C0C0', width=0.3, slide=True, name='id_%d'%i)	
>>> 

呼叫一下試試看,

>>> plt.figure(dist=0.8, view=[-1, 1, -1, 1, 0.8, 7], elevation=0, azimuth=0, interval=50) # 設定畫布,影片間隔50毫秒
>>> draw_sky_box() # 繪制天空盒
>>> draw_kite(r'D:\temp\kite\res\butterfly.png', (0.5,0.2,-1), (-0.5,-0.3,0.2)) # 繪制風箏
>>> plt.show()

和我們設想的一樣,風箏在[-20°,20°]的范圍內左右擺動,懸鏈線也跟著一起飄動,

在這里插入圖片描述

3.5 放飛更多的風箏

現在,我們有三張風箏的圖片,把它們都放飛到天空盒中吧,至于風箏的位置、放飛者的位置,你可以根據自己的想象,隨意定義,

>>> plt.figure(dist=0.8, view=[-1, 1, -1, 1, 0.8, 7], elevation=0, azimuth=0, interval=50)
>>> draw_sky_box()
>>> draw_kite(r'D:\temp\kite\res\butterfly.png', (0.5,0.2,-1), (-0.5,-0.3,0.2))
>>> plt.show()
>>> plt.figure(dist=0.8, view=[-1, 1, -1, 1, 0.8, 7], elevation=0, azimuth=0, interval=50)
>>> draw_sky_box()
>>> draw_kite(r'D:\temp\kite\res\butterfly.png', (0.5,0.2,-1), (-0.5,-0.3,0.2))
>>> draw_kite(r'D:\temp\kite\res\fish.png', (0.3,0,-1), (-0.2,-0.1,0.05), ex=(-40,40))
>>> draw_kite(r'D:\temp\kite\res\eagle.png', (0.2,0.05,-1), (-0.6,0.5,0.35))
>>> plt.show()

至此,大功告成,
在這里插入圖片描述

4 完整原始碼

# -*- coding: utf-8 -*-

import numpy as np
from PIL import Image
import wxgl.wxplot as plt # 互動式3D繪圖庫
from scipy.spatial.transform import Rotation # 空間旋轉計算

def draw_sky_box(fn):
    """繪制天空盒
    
    fn      - 圖片檔案名(寬高比4:3)
    """
    
    im = np.array(Image.open(fn)) # 打開資源圖片
    u = im.shape[0]//3 # 天空盒(正六面體的棱長)

    # 裁切出天空盒6個面:上下前后左右
    im_top = im[:u, u:2*u, :]
    im_left = im[u:2*u, :u, :]
    im_front = im[u:2*u, u:2*u, :]
    im_right = im[u:2*u, 2*u:3*u, :]
    im_back = im[u:2*u, 3*u:, :]
    im_bottom = im[2*u:, u:2*u, :]

    # 定義天空盒六個面的,4個頂點按逆時針方向排列
    vs_front = np.array([[-1,-1,1], [-1,-1,-1], [-1,1,-1], [-1,1,1]])
    vs_left = np.array([[1,-1,1], [1,-1,-1], [-1,-1,-1], [-1,-1,1]])
    vs_right = np.array([[-1,1,1], [-1,1,-1], [1,1,-1], [1,1,1]])
    vs_top = np.array([[1,-1,1], [-1,-1,1], [-1,1,1], [1,1,1]])
    vs_bottom = np.array([[-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1]])
    vs_back = np.array([[1,-1,1], [1,-1,-1], [1,1,-1], [1,1,1]])
    
    # 繪制天空盒的六個面
    plt.surface(vs_front, texture=im_front, alpha=False)
    plt.surface(vs_left, texture=im_left, alpha=False)
    plt.surface(vs_right, texture=im_right, alpha=False)
    plt.surface(vs_top, texture=im_top, alpha=False)
    plt.surface(vs_bottom, texture=im_bottom, alpha=False)
    plt.surface(vs_back, texture=im_back, alpha=False)

def get_line(v0, v1, k=300):
    """風箏線:從風箏底部到放飛者,近似懸鏈線
    
    v0      - 放飛者坐標
    v1      - 風箏底部系線處坐標
    k       - 描繪風箏線的點的數量,默認300點
    """
    
    m = np.power(np.linspace(0,k,k), 3)/(k*k*k)
    dx, dy = v1[0]-v0[0], v1[1]-v0[1]
    x = v1[0] - m*dx
    y = v1[1] - m*dy
    z = np.linspace(v1[2], v0[2], k)
    
    return x, y, z
    
def draw_kite(fn, v0, v1, dh=0.03, ex=(-20,20), fs=160):
    """繪制風箏
    
    fn      - 風箏圖片檔案名(png格式,帶透明通道)
    dh      - 風箏后仰高度,默認0.02
    ex      - 風箏左右擺動的角度范圍
    fs      - 風箏隨風擺動的幀數
    """
    
    im_kite = np.array(Image.open(fn)) # 打開風箏圖片
    max_s = max(im_kite.shape) # 風箏的最長邊
    dx, dy = 0.1*im_kite.shape[0]/max_s, 0.1*im_kite.shape[1]/max_s # 計算風箏在空間中的實際尺寸
    
    delta = np.hstack((np.linspace(-0.03, 0.03, fs), np.linspace(0.03, -0.03, fs))) # 風箏左右擺動程序中的高度波動
    theta = np.hstack((np.linspace(ex[0], ex[1], fs), np.linspace(ex[1], ex[0], fs))) # 風箏左右擺動的角度
    
    vs_kite = np.array([[dx,-dy,dh], [-dx,-dy,0], [-dx,dy,0], [dx,dy,dh]]) # 風箏四角的坐標,前端略高(后仰)
    vs_kite[:,0] += v1[0]
    vs_kite[:,1] += v1[1]
    vs_kite[:,2] += v1[2]
    
    offset = np.random.randint(0, 2*fs)
    for i in range(2*fs):
        k = (i+offset)%(2*fs)
        rotator = Rotation.from_euler('xyz', [0, 0, theta[k]], degrees=True)
        vs = rotator.apply(vs_kite)
        vs[:2, 2] -= delta[k]
        vs[2:, 2] += delta[k]
        plt.surface(vs, texture=im_kite, alpha=True, slide=True, name='id_%d'%i)
        
        xs, ys, zs = get_line(v0, ((vs[0][0]+vs[2][0])/2,(vs[0][1]+vs[2][1])/2,(vs[0][2]+vs[2][2])/2))
        plt.plot(xs, ys, zs, color='#C0C0C0', width=0.3, slide=True, name='id_%d'%i)
    
if __name__ == '__main__':
    plt.figure(dist=0.8, view=[-1, 1, -1, 1, 0.8, 7], elevation=0, azimuth=0, interval=50)
    draw_sky_box('res/sky.jpg')
    draw_kite('res/butterfly.png', (0.5,0.2,-1), (-0.5,-0.3,0.2))
    draw_kite('res/fish.png', (0.3,0,-1), (-0.2,-0.1,0.05), ex=(-40,40))
    draw_kite('res/eagle.png', (0.2,0.05,-1), (-0.6,0.5,0.35))
    plt.show()

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/276243.html

標籤:其他

上一篇:攜程面試官問我怎么劃分 Java 虛擬機記憶體區域,相見恨晚!

下一篇:資料庫應用——MySQL主從復制和Atlas讀寫分離

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more