你好,這里是BIMBOX。
我們的老朋友,建筑學(xué)和計(jì)算機(jī)雙修的小神仙@VCTCN93又來(lái)BOX分享了。
當(dāng)我問(wèn)到他這次打算聊點(diǎn)啥,VCTCN93說(shuō),100%原創(chuàng)首發(fā),聊一個(gè)很多人還不知道的事,可能有點(diǎn)超前,但他相信代表了未來(lái)的工作方式:給Dynamo搭一個(gè)服務(wù)器,讓它成為真正的變形金剛。
下面的文章,代碼部分你可以照著實(shí)操一下,絕對(duì)可以驗(yàn)證;如果你從來(lái)沒(méi)寫(xiě)過(guò)Python、甚至沒(méi)用過(guò)Dynamo,也完全可以跳過(guò)代碼部分,看這套方法背后的思想,還能給給漲點(diǎn)談資。
Let’s rock it.
很多人不知道,Python 有很多不同的版本,比如 CPython、 Jython、 RPython 與 IronPython 等等。一般大家口中所說(shuō)的 Python,默認(rèn)代指的是標(biāo)準(zhǔn)版CPython,基于C語(yǔ)言實(shí)現(xiàn),能夠兼容諸多 CAPI。CAPI是什么你不需要知道,只需要知道這些 CAPI 幾乎無(wú)所不能,運(yùn)行速度極快,于是大神們便通過(guò)它們,為 CPython 創(chuàng)造了一個(gè)又一個(gè)牛逼哄哄的武器:第三方庫(kù),這些武器能夠把 Python 武裝起來(lái),最終讓 Python 成了編程世界中一個(gè)無(wú)比強(qiáng)大的存在。
如果你去看大神們寫(xiě)的Python代碼,會(huì)經(jīng)??吹剿鼈兘?jīng)常以這樣的語(yǔ)句開(kāi)頭:from pyecharts.charts
import
Bar
import plotly.express as px
這里的 import 某某,就是在召喚某個(gè)強(qiáng)大的第三方庫(kù)進(jìn)入python,你可以把它理解為一個(gè)別人寫(xiě)好的插件,不需要知道它的工作原理,只要載進(jìn)來(lái),就能幫你做到很多厲害的事。比如,使用第三方庫(kù) pandas_profiling ,你只需要一行代碼,就能做出一份完整的數(shù)據(jù)報(bào)表。import pandas as pd
import pandas_profiling
#前兩行是導(dǎo)入,命令就下面一行
df = pd.read_csv(‘churn.csv’)
可以說(shuō),沒(méi)有第三方庫(kù)的 Python,就像失去了武器的武者,要他干活,就像要他肉身搏坦克。
前面我們說(shuō)的是標(biāo)準(zhǔn)版 CPython,遺憾的是,Windows平臺(tái)下的很多設(shè)計(jì)軟件,比如我們熟知的 Grasshopper 與 Dynamo,它們內(nèi)置的 Python 都是 IronPython。IronPython 雖然也有 Python 之名,但其底層是基于 .NET 平臺(tái)實(shí)現(xiàn)的,與基于 C語(yǔ)言 的 原生Python 有天壤之別。它從一出生就注定了無(wú)法使用大神們創(chuàng)造的強(qiáng)大第三方武器。從某種意義上來(lái)說(shuō),與 CPython 相比,IronPython 就是個(gè)只能用肉身搏坦克的先天殘疾。想要讓手上的 Python 發(fā)出最大的威力,使用那些屬于 Python 的利器,你就需要繞過(guò) IronPython 的封鎖,奔向 CPython 的自由世界。
想在 Dynamo 中直接裝 CPython?這是不現(xiàn)實(shí)的,不然就不會(huì)有 IronPython 這樣折衷的存在了。沒(méi)關(guān)系,此路不通,換個(gè)思路。我曾在教程「Dynamo 場(chǎng)地有限元分析」課程中提到過(guò) MVP(Model-View-Present) 模式,簡(jiǎn)單來(lái)說(shuō)就是,讓計(jì)算與顯示互不干涉、完全分離,把參數(shù)發(fā)給計(jì)算者,計(jì)算者返回你結(jié)果。用大白話來(lái)解釋就是:你不需要管我是怎么計(jì)算的,你給我數(shù)據(jù),我給你結(jié)果就行了。舉個(gè)最簡(jiǎn)單的例子,你日常瀏覽網(wǎng)頁(yè)就是一個(gè)這樣的過(guò)程。你在瀏覽器中輸入了一串網(wǎng)頁(yè)地址,按下回車,瀏覽器就把包含了參數(shù)的 URL 地址發(fā)給了網(wǎng)站的服務(wù)器,服務(wù)器再經(jīng)過(guò)海量的計(jì)算,把計(jì)算的結(jié)果返回給你,這就形成了你日??吹降木W(wǎng)頁(yè)。有些 URL 不僅是一個(gè)網(wǎng)站的地址,還包括一定的運(yùn)算規(guī)則。比如你在搜索引擎中搜索 「ArchiPython」,瀏覽器中的那一條 URL 中,就蘊(yùn)含了大量需要完成本次搜索的參數(shù),服務(wù)器計(jì)算了你提供的這些參數(shù)之后,才把所有本次運(yùn)算的結(jié)果 ,也就是「含有ArchiPython的條目」返回給你。想要擺脫 IronPython 的束縛,使用 CPython?我們大可以模仿這種方式。沒(méi)錯(cuò),我就是要你在 Dynamo 中,像訪問(wèn)網(wǎng)頁(yè)一樣使用 Cpython。我們的思路是,搭建一個(gè)使用 CPython 的本地服務(wù)器,接收 Dynamo 發(fā)來(lái)的含有參數(shù)的 URL,服務(wù)器計(jì)算出結(jié)果,再把計(jì)算的結(jié)果發(fā)回 Dynamo。整個(gè)過(guò)程,其實(shí)是完全不用 Dynamo 中的電池做任何計(jì)算,而是讓 Dynamo 成為一個(gè)純顯示端的存在。云負(fù)責(zé)計(jì)算有所數(shù)據(jù),本地負(fù)責(zé)顯示所有結(jié)果,這也就是云計(jì)算的基本思想。高能預(yù)警:下面開(kāi)始出現(xiàn)代碼,沒(méi)有基礎(chǔ)的小白同學(xué)可以跳著看看熱鬧。日后用到的時(shí)候,再回來(lái)看源代碼做參考。
前面我們說(shuō)到了CPython 強(qiáng)大的第三方庫(kù),接下來(lái)要干的活兒自然也少不了它的幫忙。你只需要幾行代碼,就能使用 flask 庫(kù),在 CPython 中搭建本地服務(wù)器:fromflaskimportFlask
__publisher__ = ‘ArchiPython’
app=Flast(__name__)
if__name__=='__main__':
app.run()
諾,服務(wù)器就這么簡(jiǎn)單的搭好了,運(yùn)行這個(gè)文件,你就開(kāi)啟了服務(wù)器。圖中Running on http://后邊是一串服務(wù)器的地址你可以在這個(gè)服務(wù)器中實(shí)現(xiàn)一些功能,比如測(cè)試是否成功鏈接:fromflaskimportFlask
__author__ = ‘Vctcn93’
__publisher__ = ‘ArchiPython’
app=Flask(__name__)
@app.route('/connect')
defconnect():
return'連接成功!'
if__name__=='__main__':
app.run()
通過(guò)設(shè)置的 connect
函數(shù),如果連接成功,網(wǎng)頁(yè)上就會(huì)顯示出 連接成功 四個(gè)字。值得注意的是,服務(wù)器只能返回字符串 (string),如果你想將計(jì)算結(jié)果用于 Dynamo 中,還需要對(duì)服務(wù)器返回的數(shù)據(jù)進(jìn)行加工,以確保其類型的正確。你也可以讓服務(wù)器根據(jù)輸入的參數(shù),來(lái)計(jì)算出結(jié)果。在腳本中添加一個(gè) add
函數(shù),讓他求參數(shù) a
和 參數(shù) b
的和:總結(jié)說(shuō)來(lái),一條滿足服務(wù)器計(jì)算的 URL,需要滿足如下公式:與服務(wù)器只能返回字符串的特性一樣,你通過(guò)請(qǐng)求(request)得到的參數(shù)也全是字符。恭喜你,你現(xiàn)在已經(jīng)成功突破了 Dynamo 的封鎖!基于以上代碼,你就可以在這個(gè) CPython 環(huán)境的服務(wù)器下,使用各種 Python 強(qiáng)大武器了,比如大名鼎鼎的 Numpy,pandas 等等。在 Dynamo 中像在瀏覽器里一般發(fā)送接請(qǐng)求,就可以獲得使用 CPython 計(jì)算的結(jié)果了。
由于 Dynamo 中的 Python 是 IronPython,所以它發(fā)送請(qǐng)求的方式是使用 .NET
的庫(kù),與 CPython 有非常大的不同,我們需要把發(fā)送和接受轉(zhuǎn)化成 CPython 的方式,下面直接送上 DynamoPythonScript 中實(shí)現(xiàn)的代碼:(代碼中帶有#的灰色行是代碼說(shuō)明)# 啟用 Python 支持和加載 DesignScript 庫(kù)
importclr
clr.AddReference('ProtoGeometry')
fromAutodesk.DesignScript.Geometryimport*
# 該節(jié)點(diǎn)的輸入內(nèi)容將存儲(chǔ)為 IN 變量中的一個(gè)列表。
dataEnteringNode=IN
# 將代碼放在該行下面
# IronPython 庫(kù)的環(huán)境變量,一般在這個(gè)位置
importsys
sys.path.append('C:/Program Files (x86)/IronPython 2.7/Lib')
fromSystem.NetimportWebRequest
fromSystem.IOimportStreamReader
fromSystem.TextimportEncoding
__author__ = ‘Vctcn93’
__publisher__ = ‘ArchiPython’
# 服務(wù)器地址
url=r'http://127.0.0.1:5000/'
# 可在在此處對(duì) URL 進(jìn)行編輯,使其支持參數(shù)
# 發(fā)送請(qǐng)求
request=WebRequest.Create(url)
# 獲取計(jì)算的結(jié)果
response=request.GetResponse()
result=StreamReader(response.GetResponseStream()).ReadToEnd()
# 將輸出內(nèi)容指定給 OUT 變量。
OUT=result
開(kāi)啟服務(wù)器后,你只需要對(duì)那個(gè) URL 做一定的修改,Dynamo 就能發(fā)送請(qǐng)求,收到結(jié)果了。
下面我們來(lái)試試具體能做些什么,拋磚引玉,歡迎大家迸發(fā)新的靈感。
在 CPython 中有一個(gè)幾何庫(kù),稱為 shapely
,它功能強(qiáng)大,運(yùn)算速度極快,是目前 Python 世界中非常流行的幾何庫(kù)之一。
繞開(kāi)了 IronPython 的封鎖后,你就可以通過(guò)服務(wù)器,使用 shapely 做相關(guān)的幾何運(yùn)算。運(yùn)算速度一般比 Dynamo 自帶電池快 1000 倍以上。
我們來(lái)設(shè)計(jì)一個(gè)函數(shù),通過(guò)一條多段線(polyline)與精度(density),返回一個(gè)均分的點(diǎn)矩陣(matrix),寫(xiě)成代碼如下:defcreate_grid(polyline:List[list],deisty:float):->List(list)
pass
根據(jù)這個(gè)要求,你就可以開(kāi)始搭建自己的服務(wù)器了,功能代碼如下:importnumpyasnp
fromflaskimportFlask,request
fromshapely.geometryimportPolygon,Point
__author__ = ‘Vctcn93’
__publisher__ = ‘ArchiPython’
app=Flask(__name__)
@app.route('/connect')
defconnect():
return'連接成功!'
@app.route('/add')
defadd():
# 拿到 URL 中的參數(shù)
a=request.args.get('a')
b=request.args.get('b')
# 將他們還原成數(shù)字
a,b=eval(a),eval(b)
# 計(jì)算
result=a+b
# 只能返回字符串
returnstr(result)
@app.route('/create_grid')
defcreate_grid():
# 獲得polyline參數(shù)
polyline=request.args.get('polyline')
print(polyline)
# 獲得density
density=request.args.get('density')
# 還原他們的類型
polyline,density=eval(polyline),eval(density)
# 獲得圖形信息
polygon=Polygon(polyline)
bbox=polygon.bounds
start_coords=bbox[:-2]
width=bbox[2]-bbox[0]
height=bbox[3]-bbox[1]
round_x=round(width/density)
round_y=round(height/density)
# 定義基本矢量
vector_right=np.array([density,0])
vector_up=np.array([0,density])
vector_point_start=np.array(start_coords)
# 獲得原始點(diǎn)矩陣
matrix=list()
forxinrange(round_x):
foryinrange(round_y):
vector_point=vector_point_start+vector_right*x+vector_up*y
point=Point(vector_point)
# 同時(shí)做判斷,如果點(diǎn)在范圍內(nèi)
ifpolygon.contains(point):
matrix.append(point)
# 將結(jié)果輸出為字符
result=[
list(p.coords)[0]forpinmatrix
]
returnstr(result)
if__name__=='__main__':
app.run()
在 Console 中運(yùn)行這個(gè)腳本,你就可以在瀏覽器中輸入?yún)?shù)來(lái)測(cè)試結(jié)果:輸入一個(gè) polyline,其幾何為 [[0,0],[100,0],[100,100],[0,100]], density 為 10,求出其結(jié)果。
接下來(lái),使用 Dynamo 發(fā)送這次請(qǐng)求,并獲得服務(wù)器返回的結(jié)果:# 啟用 Python 支持和加載 DesignScript 庫(kù)
—
importclr
clr.AddReference('ProtoGeometry')
fromAutodesk.DesignScript.Geometryimport*
# 該節(jié)點(diǎn)的輸入內(nèi)容將存儲(chǔ)為 IN 變量中的一個(gè)列表。
dataEnteringNode=IN
# 將代碼放在該行下面
# IronPython 庫(kù)的環(huán)境變量,一般在這個(gè)位置
importsys
sys.path.append('C:/Program Files (x86)/IronPython 2.7/Lib')
fromSystem.NetimportWebRequest
fromSystem.IOimportStreamReader
fromSystem.TextimportEncoding
__author__ = ‘Vctcn93’
__publisher__ = ‘ArchiPython’
# 服務(wù)器地址
url=http://127.0.0.1:5000/
url+='creaet_grid?'
url+='polyline=[[0,0],[100,0],[100,100],[0,100]]&'
url+='density=10'
# 發(fā)送請(qǐng)求
request=WebRequest.Create(url)
# 獲取計(jì)算的結(jié)果
response=request.GetResponse()
result=StreamReader(response.GetResponseStream()).ReadToEnd()
# 將結(jié)果處理為一個(gè)個(gè)的點(diǎn):
points=[Point.ByCoordinates(*coords)forcoordsineval(result)]
# 將輸出內(nèi)容指定給 OUT 變量。
OUT=points
到這一步,我們就真正實(shí)現(xiàn)了 0 節(jié)點(diǎn)運(yùn)算,僅靠服務(wù)器本身完成復(fù)雜的功能,Dynamo 在整個(gè)鏈條中,僅僅起到了顯示的作用。
你也可以使用 Dynamo 中的 Polyline
與 NumberSlider
來(lái)完成這項(xiàng)計(jì)算:? 將紅線導(dǎo)入 Dynamo 中,設(shè)置 number slider,讓 Density 參數(shù)可調(diào)。? 修改部分代碼,讓鏈接地址隨參數(shù)變化而變化。? 此時(shí),你便會(huì)得到一個(gè)響應(yīng)速度極快的、使用 CPython 實(shí)時(shí)計(jì)算的點(diǎn)矩陣。
從表面上來(lái)看,這只是一個(gè)通過(guò)搭建服務(wù)器,跳出 Dynamo 自帶的 IronPython,實(shí)現(xiàn)使用原生 Python 牛哄哄功能的方法。這對(duì)于純建筑人員來(lái)說(shuō)或許有些許難度,而對(duì)于程序員而言,或許并不是很厲害的功能。但是,這篇分享的意義,遠(yuǎn)不止搭建個(gè)服務(wù)器這么簡(jiǎn)單。VCTCN93 認(rèn)為,「本地客戶端只負(fù)責(zé)顯示,運(yùn)算交給云端」,這極有可能是未來(lái)幾年越來(lái)越普及的工作方式。在這個(gè)案例之中,在傳統(tǒng)工作流中起到計(jì)算作用的 Dynamo,完全成為了顯示結(jié)果的存在,所有的計(jì)算,都在服務(wù)器上完成了。這次的分享僅僅只是引入了少量矢量庫(kù),未來(lái)有可能會(huì)引入計(jì)算機(jī)神經(jīng)引擎,而正如我們前面所說(shuō)的,Dynamo 也好,Revit 也好,目前都是不支持這些尖兒貨的。如果我們能在任意軟件使用自己開(kāi)發(fā)的功能,又何須要被軟件本身的功能和API鎖死自己的生產(chǎn)力呢?軟件如果能做,那就用軟件做;軟件如果不能做,那么我就只把它當(dāng)做顯示工具,整個(gè)系統(tǒng)都可能會(huì)被時(shí)代拋棄掉。往大點(diǎn)的方向說(shuō),5G時(shí)代將要來(lái)臨了,人類數(shù)據(jù)傳輸?shù)男视謱⑦M(jìn)入一個(gè)新的臺(tái)階,云計(jì)算一定會(huì)成為未來(lái)的主流。建筑師只需要把設(shè)計(jì)參數(shù)發(fā)送給云端,云端就能返回給你算好的結(jié)果,企業(yè)對(duì)于軟件功能和硬件性能的升級(jí),也只對(duì)應(yīng)著云端服務(wù)器,能大量節(jié)省本地的資源。今天只是 Dynamo 成了我們的顯示端,但其實(shí)我可以用任何東西作為我的顯示端。如果一個(gè)工程師說(shuō)「這件事我做不了,因?yàn)檐浖](méi)有這個(gè)功能」,他就是被軟件功能鎖死了。軟件本身應(yīng)該為工程師的自身業(yè)務(wù)服務(wù),而不是由工程師去遷就軟件功能劃出的地牢。和很多建筑圈的計(jì)算機(jī)大牛一樣,VCTCN93 曾經(jīng)不止一次的在多個(gè)場(chǎng)合呼吁,不要局限在軟件層面,更不要被任何軟件鎖死的原因。因?yàn)榘褎e人造好的輪子玩得滾瓜爛熟,遠(yuǎn)不如自己掌握核心科技。很多人會(huì)說(shuō),工程師是做設(shè)計(jì)、做施工的,憑啥去學(xué) Dynamo、學(xué)Python?每個(gè)人當(dāng)然有權(quán)不學(xué),我們希望的是,至少人們知道自己腳下的邊界在哪里,邊界之外,還有多廣闊的天地。今天你至少收獲了一個(gè)談資:下次別人再告訴你學(xué) Dynamo 要把 Python 玩兒溜,你可以反問(wèn)一句:你說(shuō)的是 CPython 還是 IronPython ? IronPython 可不夠用啊!關(guān)于云計(jì)算是怎么回事,它的發(fā)展和未來(lái),我們?cè)凇?/span>精讀10本好書(shū)中的20項(xiàng)新科技》這門音頻課程里專門有一節(jié)講到了它,特地拿出來(lái)給你設(shè)置成免費(fèi)收聽(tīng),感興趣的話可以聽(tīng)聽(tīng)看。作為BIMBOX小伙伴里的建筑+計(jì)算機(jī)雙修撐場(chǎng)專員,再次向你誠(chéng)意推薦 VCTCN93 的《Dynamo可視化腳本思維課》,能幫你打開(kāi)一片為所欲為的新天地。另外,VCTCN93 和BOX合作的 Dynamo+Python 工程師自我提升課程,也在積極籌備中,各位小伙伴有哪方面的實(shí)際需求,也歡迎給我們留言,幫助我們打造一套有價(jià)值的好教程。有態(tài)度,有深度,BIMBOX,咱們下次見(jiàn)!