Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
程式碼區塊是 Dynamo 中的獨有功能,用於動態連接視覺程式設計環境與文字型環境。程式碼區塊可存取所有 Dynamo 節點,並可以在一個節點定義整個圖形。請仔細閱讀本章,因為程式碼區塊是 Dynamo 中的基礎建置材料。

在本節中,您將會學習一系列如何使用 DesignScript 建立幾何圖形的課程。請將範例 DesignScript 複製到 Dynamo 程式碼區塊逐步進行。
// copy this code into a Code Block
// to start writing DesignScript
x = "Let's create some geometry!";Python 是使用廣泛的程式設計語言,其備受青睞與其語法樣式有很大關係。Python 的可讀性很高,因此較許多其他語言更容易瞭解。Python 支援模組與套件,可嵌入至既有應用程式中。如需如何正常使用 Python 的資訊, 上的 頁面是良好的資源。

Intersect、Trim 和 SelectTrim 主要是用在較低維度的幾何圖形 (例如點、曲線和曲面)。而立體幾何圖形則有額外的一組方法,可以透過類似 Trim 的方法減去材料,然後將元素合併在一起形成較大的元素,在建構幾何圖形後修改形狀。
Union 方法使用兩個實體物件,從兩個物件都涵蓋到的空間建立單一實體物件。物件之間重疊的空間會合併成最終的形狀。此範例將一個圓球和一個立方體合併成一個單一的立體圓球-立方塊造型:
s1 = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
s2 = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(4, 0,
0), 6);
combined = s1.Union(s2);Difference 方法與 Trim 類似,從基準實體減去輸入工具實體的內容。在此範例中,我們從一個圓球切掉一個小凹口:
Intersect 方法傳回兩個實體輸入之間重疊的實體。在以下範例中,Difference 已變成 Intersect,產生的實體是一開始切掉不見的空洞:
程式碼區塊是 DesignScript 中的深層視窗,是 Dynamo 程式設計語言的核心。DesignScript 可用於從頭開始進行建置以支援探索式設計工作流程,它是一個可讀且簡要的語言,可為較小的位元碼提供即時意見以也可以用於大型且複雜的互動。DesignScript 還形成在後台驅動 Dynamo 大多數方面之引擎的基礎。因為幾乎 Dynamo 節點的所有功能和互動都與指令碼撰寫語言有一對一的關係,所以有獨特的機會以流暢方式在節點式互動與指令碼撰寫之間轉換。
對於初學者,節點可以自動轉換為文字語法,以協助學習 DesignScript,或單純只是為了縮小較大的圖表部分。使用稱為「要編碼的節點」的流程即可達成。在 會說明更多詳細資訊。經驗更豐富的使用者可以使用程式碼區塊,建立既有功能以及使用許多標準編碼範例的使用者編寫關係的自訂組合。對於初學者和進階使用者之間的使用者,提供了大量的捷徑和程式碼片段可加快您的設計。雖然術語「程式碼區塊」可能會讓非程式設計師覺得有點難以理解,但它其實很容易使用,而且功能強大。初學者可以在進行最少編碼的情況下使用程式碼區塊,進階使用者可定義在 Dynamo 定義的其他位置可進行呼叫的指令碼型定義。
簡而言之,程式碼區塊是視覺指令碼撰寫環境中的文字指令碼撰寫介面。它們可以用作數字、字串、公式和其他資料類型。程式碼區塊是專為 Dynamo 設計的,因此可以在程式碼區塊中定義任意變數,且這些變數會自動新增至節點的輸入:



s = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
tool = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(10, 0,
0), 6);
result = s.Difference(tool);s = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
tool = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(10, 0,
0), 6);
result = s.Intersect(tool);程式碼區塊可讓使用者靈活決定如何指定輸入。下面提供了幾種不同方式來使用座標建立基本點 (10,5,0):
在您進一步瞭解資源庫中可用的函數後,您可能甚至會發現,鍵入「Point.ByCoordinates」的速度比在資源庫中搜尋和找出正確的節點更快。例如當您鍵入 Point. 時,Dynamo 會顯示一個可能函數的清單以套用到點。這可使得指令碼撰寫更直覺,並協助學習如何在 Dynamo 中套用函數。
您可以透過 Core>Input>Actions>Code Block 找到程式碼區塊。但更快的方式是在圖元區按兩下,程式碼區塊就會出現。此節點因為經常使用,所以被賦予完整的按兩下權限。
程式碼區塊對於資料類型也可以很靈活。使用者可以快速定義數字、字串和公式,程式碼區塊將提供所需的輸出。
在以下圖像中,您可以看到以「舊」的方式進行的作業有點冗長,使用者在介面中搜尋所需的節點,將節點新增至畫布,然後輸入資料。使用 Code Block 時,使用者可以按兩下畫布以拉取節點,然後使用基本語法鍵入正確資料類型。
number 和 string 節點是 Dynamo 節點的兩個範例,與 Code Block 相比可以說是舊式節點。
舊式
程式碼區塊

Dynamo 標準幾何圖形資源庫中最簡單的幾何圖形物件是一個點。所有幾何圖形都是使用稱作建構函式的特殊函數建立的,每個建構函式都會傳回一個該特定幾何圖形類型的新實體。在 Dynamo 中,建構函式以物件類型的名稱 (在此案例中為 Point) 為開頭,後接建構的方法。若要建立一個以 x、y、z 直角座標指定的三維點,請使用 ByCoordinates 建構函式:
Dynamo 中的建構函式通常以「By」字首指定,呼叫這些函數會傳回該類型新建立的物件。這個新建立的物件以等號左邊命名的變數儲存。
大多數物件都有許多不同的建構函式,我們可以使用 BySphericalCoordinates 建構函式,指定圓球的半徑、第一個旋轉角度和第二個旋轉角度 (以度為單位指定) 建立一個圓球上的點:
點可以用來建構更高維度的幾何圖形,例如直線。我們可以使用 ByStartPointEndPoint 建構函式在兩個點之間建立一個 Line 物件:
同樣的,直線也可以用來建立更高維度的曲面幾何圖形,例如使用 Loft 建構函式,用一系列直線或曲線,在這之間內插一個曲面。
曲面也可以用來建立更高維度的實體幾何圖形,例如把曲面加厚指定的距離。許多物件都會附加稱為方法的函數,程式設計師可以對該特定物件執行指令。所有幾何圖形都通用的方法包括 Translate 和 Rotate,分別將幾何圖形平移 (移動) 和旋轉指定的量。曲面有一個 Thicken 方法,它採用一個單一的數字輸入,指定曲面的新厚度。
Intersection 指令可以從較高維度的物件萃取出較低維度的幾何圖形。在建立、萃取和重新建立幾何圖形的循環過程中,萃取出的較低維度幾何圖形可以形成較高維度幾何圖形的基礎。在此範例中,我們使用產生的實體 (Solid) 來建立一個曲面 (Surface),並使用曲面 (Surface) 來建立一條曲線 (Curve)。
計算設計中經常會使用曲線和曲面做為後續建構幾何圖形的基礎。為了讓這個早期的幾何圖形能夠做為後期幾何圖形的基礎,腳本必須要能夠萃取品質,例如物件整個區域的位置和方位。曲線與曲面兩種都支援這類萃取,這就是所謂的參數化。
一條曲線上所有的點都可以視為在 0 到 1 的範圍內具有唯一的參數。如果我們根據幾個控制點或內插點建立 NurbsCurve,第一個點的參數會是 0,最後一個點的參數會是 1。我們無法事先知道所有中間點的確切參數是多少,這聽起來像是很嚴重的限制,不過透過一系列的公用程式函數,這個狀況會減輕許多。曲面的參數化與曲線類似,但是有兩個分別稱為 u 和 v 的參數,而不是一個。如果我們要建立一個包含以下幾點的曲面:
pts = [ [p1, p2, p3],
[p4, p5, p6],
[p7, p8, p9] ];p1 會有 u = 0 v = 0 的參數,p9 會有 u = 1 v = 1 的參數。
決定用來產生曲線的點時,參數化並不是特別好用,它的主要用途是決定由 NurbsCurve 和 NurbsSurface 建構函式所產生的中間點的位置。
曲線 (Curve) 有一個 PointAtParameter 方法,採用 0 到 1 之間的一個雙精確度引數,並傳回位於該參數的 Point 物件。例如,此腳本會找出參數 0、.1、.2、.3、.4、.5、.6、.7、.8、.9 和 1 的點 (Point):
pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(6, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(3, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
crv = NurbsCurve.ByPoints(pts);
pts_at_param = crv.PointAtParameter(0..1..#11);
// draw Lines to help visualize the points
lines = Line.ByStartPointEndPoint(pts_at_param,
Point.ByCoordinates(4, 6, 0));同樣的,曲面 (Surface) 有一個 PointAtParameter 方法,採用兩個引數:產生的點的 u 和 v 參數。
在萃取曲線和曲面上的各個點時雖然很好用,但是腳本通常需要知道位於某個參數的特定幾何特性,例如曲線或曲面是朝向哪個方向。CoordinateSystemAtParameter 方法不只會找出位置,也會找出位於曲線或曲面的參數處有方向的 CoordinateSystem。例如,以下腳本會沿著一個迴轉的曲面 (Surface) 萃取出有方向的 CoordinateSystem,並使用 CoordinateSystem 的方位產生插在曲面法線方向上的線條:
如先前所述,參數化在整個曲線或曲面的長度不一定都是均勻的,這表示參數 0.5 不一定會永遠對應到曲線或曲面的中點,0.25 不一定會永遠對應到曲線或曲面四分之一的點。若要避開這種限制,曲線還有另外一組參數化指令,可讓您沿著曲線找出位於特定長度的點。
NurbsCurve 的二維類比是 NurbsSurface,就像自由形式的 NurbsCurve,您可以使用兩種基本方法建構 NurbsSurface:一個是輸入一組基準點,讓 Dynamo 在這些點之間內插,另一個是明確指定曲面的控制點。就像自由形式的曲線,如果設計師很清楚知道要產生的曲面形狀,或如果設計需要曲面通過約束點,內插的曲面會很好用。相反地,如果是要探索各種平滑程度的設計,透過控制點建立的曲面就比較有用。
若要建立內插的曲面,只要產生一些近似曲面形狀的二維點即可。這些點必須是矩形,亦即不是鋸齒狀。NurbsSurface.ByPoints 方法會從這些點建構一個曲面。
// python_points_1 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
surf = NurbsSurface.ByPoints(python_points_1);指定曲面的基本控制點,也可以建立自由形式的 NurbsSurface。就像 NurbsCurve 一樣,控制點可以視為是代表一個有直線段的四邊形網格,這會根據曲面的次數,平滑化成最終的曲面形狀。若要使用控制點來建立 NurbsSurface,請在 NurbsSurface.ByPoints 中包含另外兩個參數,指出基本曲線在曲面兩個方向的次數。
我們可以增加 NurbsSurface 的次數,來變更產生的曲面幾何圖形:
就像我們可以在一組輸入點之間內插來建立 Surface,也可以在一組基準曲線之間內插來建立 Surface。這稱為斷面混成。使用 Surface.ByLoft 建構函式可以建立斷面混成的曲線,一組輸入曲線是唯一的參數。
迴轉的曲面是另外一種曲面類型,環繞一個中心軸掃掠一條基準曲線可以建立這種曲面。如果內插曲面是內插曲線的二維類比,則迴轉的曲面就是圓和弧的二維類比。
迴轉的曲面是由基準曲線 (代表曲面的「邊緣」)、軸原點 (曲面的基準點)、軸方向 (中央「核心」方向)、掃掠起始角度和掃掠結束角度指定。這些是用來做為 Surface.Revolve 建構函式的輸入。
在 Dynamo 中有兩種基本方法可以建立自由形式的曲線:指定一些點,讓 Dynamo 在這些點之間插出一條平滑的曲線,另一個比較低階的方法是指定某個次數的曲線的基本控制點。如果設計師很清楚知道要產生的線條形狀,或如果設計有一些特定的約束讓曲線可以或無法通過,內插的曲線會很好用。透過控制點指定的曲線實際上是一系列的直線段,演算法會將這些線段平滑產生一條最終的曲線形狀。如果是要探索各種不同平滑程度的曲線形狀,或者當曲線段之間的平滑連續性很重要時,透過控制點指定曲線就很好用。
若要建立內插的曲線,只要將一些點傳入 NurbsCurve.ByPoints 方法即可。
產生的曲線會分別與每個輸入點相交,從第一個點開始,在最後一個點結束。這裡可以使用一個選擇性的週期性參數,用來建立一條週期性的封閉曲線。Dynamo 會自動填入缺少的線段,因此不需要複製終點 (與起點相同)。
計算設計中的物件很少會以其最終的位置和形狀明確建立,幾乎都是以既有的幾何圖形為基礎,將它們經過平移、旋轉,或以其他任何方式放在適當位置。向量數學是一種以幾何搭建鷹架的方式,對幾何圖形提供方向和方位,並且將整個 3D 空間的移動概念化而不提供視覺表現法。
從最基礎來說,一個向量代表 3D 空間中的一個位置,而且通常視為從位置 (0,0,0) 到該位置的一個箭頭終點。向量可以使用 ByCoordinates 建構函式建立,採用新建立的向量物件的 x、y、z 位置。請注意,向量物件不是幾何物件,不會出現在 Dynamo 視窗中。但是在主控台視窗中可以列印出新建立或修改過的向量的相關資訊:
向量物件定義了一組數學運算,讓您可以在 3D 空間中相加、相減、相乘,或以其他任何方式移動物件,就像您在 1D 空間中的數線上移動實數一樣。
向量相加是定義為兩個向量的分量總和,可以視為是兩個分量的向量箭頭以尖端接著尾端的方式放置而得到的向量。向量相加是使用
以下 Python 指令碼會為多個範例產生點陣列。請將這些指令碼貼至 Python Script 節點,如下所示:
python_points_1
python_points_2
python_points_3
python_points_4
python_points_5
// create a point with the following x, y, and z
// coordinates:
x = 10;
y = 2.5;
z = -6;
p = Point.ByCoordinates(x, y, z);















out_points = []
for i in range(11):
sub_points = []
for j in range(11):
z = 0
if (i == 5 and j == 5):
z = 1
elif (i == 8 and j == 2):
z = 1
sub_points.append(Point.ByCoordinates(i, j, z))
out_points.append(sub_points)
OUT = out_pointsout_points = []
for i in range(11):
z = 0
if (i == 2):
z = 1
out_points.append(Point.ByCoordinates(i, 0, z))
OUT = out_points
// create a point on a sphere with the following radius,
// theta, and phi rotation angles (specified in degrees)
radius = 5;
theta = 75.5;
phi = 120.3;
cs = CoordinateSystem.Identity();
p = Point.BySphericalCoordinates(cs, radius, theta,
phi);// create two points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
// construct a line between p1 and p2
l = Line.ByStartPointEndPoint(p1, p2);// create points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);
p5 = Point.ByCoordinates(9, -10, -2);
p6 = Point.ByCoordinates(-11, -12, -4);
// create lines:
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
l3 = Line.ByStartPointEndPoint(p5, p6);
// loft between cross section lines:
surf = Surface.ByLoft([l1, l2, l3]);p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
surf = Surface.ByLoft([l1, l2]);
// true indicates to thicken both sides of the Surface:
solid = surf.Thicken(4.75, true);p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
surf = Surface.ByLoft([l1, l2]);
solid = surf.Thicken(4.75, true);
p = Plane.ByOriginNormal(Point.ByCoordinates(2, 0, 0),
Vector.ByCoordinates(1, 1, 1));
int_surf = solid.Intersect(p);
int_line = int_surf.Intersect(Plane.ByOriginNormal(
Point.ByCoordinates(0, 0, 0),
Vector.ByCoordinates(1, 0, 0)));pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(3, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(5, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
pts[7] = Point.ByCoordinates(4, 0, 7);
crv = NurbsCurve.ByPoints(pts);
axis_origin = Point.ByCoordinates(0, 0, 0);
axis = Vector.ByCoordinates(0, 0, 1);
surf = Surface.ByRevolve(crv, axis_origin, axis, 90,
140);
cs_array = surf.CoordinateSystemAtParameter(
(0..1..#7)<1>, (0..1..#7)<2>);
def make_line(cs : CoordinateSystem) {
lines_start = cs.Origin;
lines_end = cs.Origin.Translate(cs.ZAxis, -0.75);
return = Line.ByStartPointEndPoint(lines_start,
lines_end);
}
lines = make_line(Flatten(cs_array));// python_points_1 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
// create a surface of degree 2 with smooth segments
surf = NurbsSurface.ByPoints(python_points_1, 2, 2);// python_points_1 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
// create a surface of degree 6
surf = NurbsSurface.ByPoints(python_points_1, 6, 6);// python_points_2, 3, and 4 are generated with
// Python scripts found in Chapter 12, Section 10
c1 = NurbsCurve.ByPoints(python_points_2);
c2 = NurbsCurve.ByPoints(python_points_3);
c3 = NurbsCurve.ByPoints(python_points_4);
loft = Surface.ByLoft([c1, c2, c3]);pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(3, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(5, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
pts[7] = Point.ByCoordinates(4, 0, 7);
crv = NurbsCurve.ByPoints(pts);
axis_origin = Point.ByCoordinates(0, 0, 0);
axis = Vector.ByCoordinates(0, 0, 1);
surf = Surface.ByRevolve(crv, axis_origin, axis, 0,
360);out_points = []
for i in range(11):
z = 0
if (i == 7):
z = -1
out_points.append(Point.ByCoordinates(i, 5, z))
OUT = out_pointsout_points = []
for i in range(11):
z = 0
if (i == 5):
z = 1
out_points.append(Point.ByCoordinates(i, 10, z))
OUT = out_pointsout_points = []
for i in range(11):
sub_points = []
for j in range(11):
z = 0
if (i == 1 and j == 1):
z = 2
elif (i == 8 and j == 1):
z = 2
elif (i == 2 and j == 6):
z = 2
sub_points.append(Point.ByCoordinates(i, j, z))
out_points.append(sub_points)
OUT = out_points在 Dynamo 中,雖然可以在物件名稱的結尾附加 .Translate 方法平移所有物件,但是還有更複雜的轉換需要將物件從一個基本的 CoordinateSystem 轉換到新的 CoordinateSystem。例如,若要讓物件繞 x 軸旋轉 45 度,我們要使用 .Transform 方法,將物件從其既有無旋轉的 CoordinateSystem,轉換到一個已經繞 x 軸旋轉 45 度的 CoordinateSystem:
除了平移和旋轉,也可以用調整比例或切變方式建立 CoordinateSystem。CoordinateSystem 可以使用 .Scale 方法調整比例:
在 CoordinateSystem 建構函式中輸入非正交的向量可以建立切變的 CoordinateSystem。
比起旋轉和平移,調整比例和切變是相對比較複雜的幾何轉換,所以並非每個 Dynamo 物件都能經過這些轉換。下表概述哪些 Dynamo 物件可以有非等比例調整的 CoordinateSystem,以及切變的 CoordinateSystem。
Arc
否
否
NurbsCurve
是
是
NurbsSurface
否
否

NurbsCurve 以幾乎相同的方式產生,輸入點代表直線段的端點,第二個參數稱為次數,指定平滑化曲線的量和類型。* 1 次的曲線沒有平滑化;它是一條聚合線。
2 次的曲線會平滑化讓曲線相交,而且會與聚合線線段的中點相切:
Dynamo 支援最高到 20 次的 NURBS (非均勻的有理 B 雲形線) 曲線,以下腳本說明增加平滑程度對曲線造型的影響:
請注意,至少要比曲線的次數多一個控制點。
透過控制頂點來建構曲線的另一個好處是,能夠在個別的曲線段之間維持相切。只要萃取出最後兩個控制點之間的方向,然後讓後續曲線的前兩個控制點繼續沿著此方向即可。以下範例會建立兩條獨立的 NURBS 曲線,不過這兩條曲線如一條曲線般平滑:


同樣的,兩個向量物件可以使用 Subtract 方法相減。向量相減可以視為是從第一個向量到第二個向量的方向。
向量相乘可以視為將一個向量的終點沿著自己的方向移動給定的比例係數。
如果要調整一個向量的大小,讓產生的向量長度完全等於調整的量,就經常會這樣做。只要先將一個向量正規化,也就是將向量的長度設定為等於 1,就可以輕鬆達成目標。
c 還是指向與 (1, 2, 3) 相同的方向,但是現在長度等於 5。
向量數學中還有其他兩個與 1D 數學無關的方法,分別是外積和內積。外積是一種從兩個既有向量產生一個與這兩個向量成正交 (90 度) 的向量的方法。例如,x 軸和 y 軸的外積是 z 軸,不過兩個輸入向量不必然要互相正交。外積向量是透過 Cross 方法計算。
向量數學另外一個更進階的函數是內積。二個向量的內積是一個與兩個向量之間的角度有關但不是完全相同的一個實數 (不是 Vector 物件)。內積一個有用的性質是,如果兩個向量互相垂直,則兩個向量之間的內積將為 0。內積使用 Dot 方法計算。

若要使用此功能,我們必須在 DynamoSettings.xml 檔案中加入下列一行。(以記事本編輯)
我們會在當中看到 <PythonTemplateFilePath />,可以直接將它替換為以下內容:
注意:請使用您的使用者名稱替換 CURRENTUSER
接下來,我們需要建置一個樣板,當中含有我們要使用的內建功能。在此範例中,我們嵌入 Revit 相關的匯入,和一些在處理 Revit 時的其他典型項目。
您可以開啟一份空白的記事本文件,在當中貼上以下程式碼:
完成後,請在 APPDATA 位置將此檔案儲存為 PythonTemplate.py。
定義 Python 樣板之後,每當放置了 Python 節點時,Dynamo 都會尋找這裡。如果找不到,看起來就會是預設的 Python 視窗。
如果發現 Python 樣板 (例如我們的 Revit),您會看到您內建的所有預設項目。
您可以在下列位置找到有關此絕佳額外功能 (由 Radu Gidei 提供) 的其他資訊。https://github.com/DynamoDS/Dynamo/pull/8122

雖然 Dynamo 能夠建立各種複雜幾何形狀,但是簡單的幾何基本型是構成任何計算設計的骨架:無論是以最終設計的形式直接表示,或是用來做為產生更複雜幾何圖形的鷹架。
雖然 CoordinateSystem 嚴格來說不算是一個幾何圖形,但卻是建構幾何圖形的一個重要工具。一個 CoordinateSystem 物件可以同時追蹤位置和幾何的轉換,例如旋轉、切變和調整比例。
建立一個中心點位於 x=0,y=0,z=0 的 CoordinateSystem (沒有旋轉、調整比例或切變轉換),只需要呼叫 Identity 建構函式:
具有幾何轉換的 CoordinateSystem 超出本章節的範圍,不過有另一個建構函式 CoordinateSystem.ByOriginVectors 可以讓您在特定的點建立座標系統:
最簡單的幾何基本型是一個點 (Point),代表三維空間中的一個零維位置。如先前所述,在特定座標系統中建立一個點有幾種不同的方式:Point.ByCoordinates 以指定的 x、y、z 座標建立一個點;Point.ByCartesianCoordinates 在特定座標系統中以指定的 x、y、z 座標建立一個點;Point.ByCylindricalCoordinates 在有半徑、旋轉角度和高度的圓柱上建立一個點;Point.BySphericalCoordinates 在有半徑和兩個旋轉角度的圓球上建立一個點。
本範例會顯示在各種座標系統建立的點:
下一個較高維度的 Dynamo 基本型是線段,代表兩個端點之間有無限個點。使用 Line.ByStartPointEndPoint 建構函式明確指出兩個邊界點,或使用 Line.ByStartPointDirectionLength 建構函式指定起點、方向和沿著該方向的長度,可以建立直線。
Dynamo 有幾個物件,代表三維的幾何基本型的最基本類型:使用 Cuboid.ByLengths 建立的立方體 (Cuboid);使用 Cone.ByPointsRadius 和 Cone.ByPointsRadii 建立的圓錐 (Cone);使用 Cylinder.ByRadiusHeight 建立的圓柱 (Cylinder);以及使用 Sphere.ByCenterPointRadius 建立的圓球 (Sphere)。
// create a point at x = 1, y = 2, z = 3
p = Point.ByCoordinates(1, 2, 3);
// translate the point 10 units in the x direction,
// -20 in y, and 50 in z
// p2’s new position is x = 11, y = -18, z = 53
p2 = p.Translate(10, -20, 50);cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
10, 10, 10);
new_cs = CoordinateSystem.Identity();
new_cs2 = new_cs.Rotate(Point.ByCoordinates(0, 0),
Vector.ByCoordinates(1,0,0.5), 25);
// get the existing coordinate system of the cube
old_cs = CoordinateSystem.Identity();
cube2 = cube.Transform(old_cs, new_cs2);cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
10, 10, 10);
new_cs = CoordinateSystem.Identity();
new_cs2 = new_cs.Scale(20);
old_cs = CoordinateSystem.Identity();
cube2 = cube.Transform(old_cs, new_cs2);new_cs = CoordinateSystem.ByOriginVectors(
Point.ByCoordinates(0, 0, 0),
Vector.ByCoordinates(-1, -1, 1),
Vector.ByCoordinates(-0.4, 0, 0));
old_cs = CoordinateSystem.Identity();
cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
5, 5, 5);
new_curves = cube.Transform(old_cs, new_cs);num_pts = 6;
s = Math.Sin(0..360..#num_pts) * 4;
pts = Point.ByCoordinates(1..30..#num_pts, s, 0);
int_curve = NurbsCurve.ByPoints(pts);pts = Point.ByCoordinates(Math.Cos(0..350..#10),
Math.Sin(0..350..#10), 0);
// create an closed curve
crv = NurbsCurve.ByPoints(pts, true);
// the same curve, if left open:
crv2 = NurbsCurve.ByPoints(pts.Translate(5, 0, 0),
false);num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
// a B-Spline curve with degree 1 is a polyline
ctrl_curve = NurbsCurve.ByControlPoints(pts, 1);num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
// a B-Spline curve with degree 2 is smooth
ctrl_curve = NurbsCurve.ByControlPoints(pts, 2);num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
def create_curve(pts : Point[], degree : int)
{
return = NurbsCurve.ByControlPoints(pts,
degree);
}
ctrl_crvs = create_curve(pts, 1..11);pts_1 = {};
pts_1[0] = Point.ByCoordinates(0, 0, 0);
pts_1[1] = Point.ByCoordinates(1, 1, 0);
pts_1[2] = Point.ByCoordinates(5, 0.2, 0);
pts_1[3] = Point.ByCoordinates(9, -3, 0);
pts_1[4] = Point.ByCoordinates(11, 2, 0);
crv_1 = NurbsCurve.ByControlPoints(pts_1, 3);
pts_2 = {};
pts_2[0] = pts_1[4];
end_dir = pts_1[4].Subtract(pts_1[3].AsVector());
pts_2[1] = Point.ByCoordinates(pts_2[0].X + end_dir.X,
pts_2[0].Y + end_dir.Y, pts_2[0].Z + end_dir.Z);
pts_2[2] = Point.ByCoordinates(15, 1, 0);
pts_2[3] = Point.ByCoordinates(18, -2, 0);
pts_2[4] = Point.ByCoordinates(21, 0.5, 0);
crv_2 = NurbsCurve.ByControlPoints(pts_2, 3);// construct a Vector object
v = Vector.ByCoordinates(1, 2, 3);
s = v.X + " " + v.Y + " " + v.Z;a = Vector.ByCoordinates(5, 5, 0);
b = Vector.ByCoordinates(4, 1, 0);
// c has value x = 9, y = 6, z = 0
c = a.Add(b);a = Vector.ByCoordinates(5, 5, 0);
b = Vector.ByCoordinates(4, 1, 0);
// c has value x = 1, y = 4, z = 0
c = a.Subtract(b);a = Vector.ByCoordinates(4, 4, 0);
// c has value x = 20, y = 20, z = 0
c = a.Scale(5);a = Vector.ByCoordinates(1, 2, 3);
a_len = a.Length;
// set the a's length equal to 1.0
b = a.Normalized();
c = b.Scale(5);
// len is equal to 5
len = c.Length;a = Vector.ByCoordinates(1, 0, 1);
b = Vector.ByCoordinates(0, 1, 1);
// c has value x = -1, y = -1, z = 1
c = a.Cross(b);a = Vector.ByCoordinates(1, 2, 1);
b = Vector.ByCoordinates(5, -8, 4);
// d has value -7
d = a.Dot(b);<PythonTemplateFilePath>
<string>C:\Users\CURRENTUSER\AppData\Roaming\Dynamo\Dynamo Core\2.0\PythonTemplate.py</string>
</PythonTemplateFilePath>import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('System')
from System.Collections.Generic import List
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
#Preparing input from dynamo to revit
element = UnwrapElement(IN[0])
#Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
TransactionManager.Instance.TransactionTaskDone()
OUT = element// create a CoordinateSystem at x = 0, y = 0, z = 0,
// no rotations, scaling, or sheering transformations
cs = CoordinateSystem.Identity();Circle
否
否
Line
是
是
Plane
否
否
Point
是
是
Polygon
否
否
Solid
否
否
Surface
否
否
Text
否
否






















// create a CoordinateSystem at a specific location,
// no rotations, scaling, or sheering transformations
x_pos = 3.6;
y_pos = 9.4;
z_pos = 13.0;
origin = Point.ByCoordinates(x_pos, y_pos, z_pos);
identity = CoordinateSystem.Identity();
cs = CoordinateSystem.ByOriginVectors(origin,
identity.XAxis, identity.YAxis, identity.ZAxis);// create a point with x, y, and z coordinates
x_pos = 1;
y_pos = 2;
z_pos = 3;
pCoord = Point.ByCoordinates(x_pos, y_pos, z_pos);
// create a point in a specific coordinate system
cs = CoordinateSystem.Identity();
pCoordSystem = Point.ByCartesianCoordinates(cs, x_pos,
y_pos, z_pos);
// create a point on a cylinder with the following
// radius and height
radius = 5;
height = 15;
theta = 75.5;
pCyl = Point.ByCylindricalCoordinates(cs, radius, theta,
height);
// create a point on a sphere with radius and two angles
phi = 120.3;
pSphere = Point.BySphericalCoordinates(cs, radius,
theta, phi);p1 = Point.ByCoordinates(-2, -5, -10);
p2 = Point.ByCoordinates(6, 8, 10);
// a line segment between two points
l2pts = Line.ByStartPointEndPoint(p1, p2);
// a line segment at p1 in direction 1, 1, 1 with
// length 10
lDir = Line.ByStartPointDirectionLength(p1,
Vector.ByCoordinates(1, 1, 1), 10);// create a cuboid with specified lengths
cs = CoordinateSystem.Identity();
cub = Cuboid.ByLengths(cs, 5, 15, 2);
// create several cones
p1 = Point.ByCoordinates(0, 0, 10);
p2 = Point.ByCoordinates(0, 0, 20);
p3 = Point.ByCoordinates(0, 0, 30);
cone1 = Cone.ByPointsRadii(p1, p2, 10, 6);
cone2 = Cone.ByPointsRadii(p2, p3, 6, 0);
// make a cylinder
cylCS = cs.Translate(10, 0, 0);
cyl = Cylinder.ByRadiusHeight(cylCS, 3, 10);
// make a sphere
centerP = Point.ByCoordinates(-10, -10, 0);
sph = Sphere.ByCenterPointRadius(centerP, 5);可以在程式碼塊中建立函數,然後在 Dynamo 定義中的其他位置重新呼叫函數。此作業會在參數式檔案中建立另一個控制層,可視為自訂節點的文字版本。在此案例中,「父系」Code Block 可隨時存取,可在圖表中的任何位置找到。無需使用線路!
第一行包含關鍵字「def」,然後依次是函數名稱與輸入的名稱 (在括號中)。大括號定義函數的本體。使用「return =」傳回值。定義函數的 Code Block 沒有輸入或輸出埠,因為會從其他 Code Block 呼叫。
使用同一檔案中的其他 Code Block,只需提供名稱與相同數量的引數即可呼叫函數。其工作方式類似於資源庫中的現成節點。
按一下下方的連結下載範例檔案。
附錄中提供完整的範例檔案清單。
在本練習中,我們將進行根據輸入點清單建立圓球的一般定義。這些圓球的半徑由每個點的 Z 性質驅動。
接下來先建立介於 0 到 100 之間的一系列十個值。將這些值插入 Point.ByCoordinates 節點,以建立對角線。
建立 Code Block 並介紹我們的定義。
使用以下程式碼行:
inputPt 是我們為了表示驅動函數的點而提供的名稱。到現在為止,函數不會執行任何作業,但我們將在後續步驟中建置此函數。
加入 Code Block 函數後,我們加上註解和 sphereRadius 變數,它會查詢每個點的 Z 位置。請記住,inputPt.Z 是一個方法,不需要括號。這是 查詢 既有元素的性質,因此不需要任何輸入:
現在,我們呼叫在另一個 Code Block 中建立的函數。如果在圖元區上按兩下以建立新的 Code Block,然後鍵入 sphereB,我們發現 Dynamo 建議使用我們定義的 sphereByZ 函數。您的函數已加入 intellisense 資源庫!太酷了。
現在,我們呼叫函數,並建立一個稱為 Pt 的變數以插入先前步驟中建立的點:
我們看到輸出全部都是空值。為何會發生這種情況?定義函數時,我們會計算 sphereRadius 變數,但沒有定義函數應 傳回 哪些項目做為 輸出。我們可以在下一步修正此問題。
我們需要在 sphereByZ 函數中加入
return = sphereRadius;行定義函數的輸出,這是重要的步驟。現在,我們可以看到 Code Block 的輸出提供每個點的 Z 座標。
現在,我們要編輯 父系 函數以建立實際的圓球。
我們首先使用以下程式碼行定義圓球:
sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);接下來,我們將傳回值變更為 sphere,而不是 sphereRadius:
return = sphere;這會在 Dynamo 預覽中產生一些巨大的圓球!
1.若要調整這些圓球的大小,我們加入圓規來更新圓球半徑值:
sphereRadius = inputPt.Z/20;現在,我們可以看到分開的圓球,並開始了解半徑與 Z 值之間的關係。
在 Point.ByCoordinates 節點上,透過將交織從「最短清單」變更為「笛卡兒積」,我們建立點的格線。sphereByZ 函數仍完全有效,因此所有點會建立半徑以 Z 值為基礎的圓球。
為了進行測試,我們將原始數字清單插入 Point.ByCoordinates 的 X 輸入。我們現在有一個立方塊的圓球。
注意:如果在您的電腦上需要花很長時間執行此計算,請嘗試將 #10 變更為諸如 #5 等數字。
請記住,我們建立的 sphereByZ 函數是一般函數,因此可以回顧先前課程中的螺旋線,並對其套用函數。
最後一步:運用使用者定義的參數驅動半徑比。若要執行,我們需要為函數建立新輸入,並使用參數取代除數 20。
將 sphereByZ 定義更新為:
在輸入
sphereByZ(Pt,ratio);中加入 ratio 變數以更新子系 Code Block。將滑棒插入新建立的 Code Block 輸入,並根據半徑比變更半徑的大小。
到目前為止,許多範例都將重點放在從較低維度的物件建構較高維度的幾何圖形。交集的方法允許這種較高維度的幾何圖形產生較低維度的物件,而修剪和選取修剪的指令則允許腳本在建立幾何圖形後大幅修改幾何形狀。
Dynamo 針對所有幾何圖形都定義了 Intersect 方法,表示理論上,任何幾何圖形部分都可以與其他任何幾何圖形部分相交。某些交集本來就沒有意義,例如牽涉到點 (Point) 的交集,因為產生的物件永遠都是輸入點本身。下表概述物件之間其他可能的交集組合。下表概述各種交集運算的結果:
與:
Surface
下面這個非常簡單的範例示範一個平面與一個 NurbsSurface 的交集。交集產生一個 NurbsCurve 陣列,可以像任何其他 NurbsCurve 一樣使用這個陣列。
Trim 方法與 Intersect 方法非常類似之處在於幾乎是針對每個幾何圖形定義。不過,Trim 的限制遠比 Intersect 還多。
請注意,Trim 方法一定要有「選取」點,這個點決定要捨棄哪個幾何圖形,要保留哪些部份。Dynamo 會找出並捨棄最接近選取點且經過修剪的幾何圖形。
/*This is a multi-line comment,
which continues for
multiple lines*/
def FunctionName(in1,in2)
{
//This is a comment
sum = in1+in2;
return sum;
};













否
Surface
-
是
是
是
是
Solid
-
-
是
是
是
Curve
Plane
Solid
Surface
Curve
Point
Point、Curve
Surface
Curve
Point
Point
Point
Curve
Plane
Curve
Point
Curve
Curve
Solid
Surface
Curve
Curve
Solid
使用: Point
Curve
Plane
Surface
Solid
對: Curve
是
否
否
否
否
Polygon
-
否
是


否
FunctionName(in1,in2);def sphereByZ(inputPt)
{
};def sphereByZ(inputPt,radiusRatio)
{
//get Z Value, ise ot to drive radius of sphere
sphereRadius=inputPt.Z;
};sphereByZ(Pt)def sphereByZ(inputPt,radiusRatio)
{
//get Z Value, use it to drive radius of sphere
sphereRadius=inputPt.Z/radiusRatio;
//Define Sphere Geometry
sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);
//Define output for function
return sphere;
};// python_points_5 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
surf = NurbsSurface.ByPoints(python_points_5, 3, 3);
WCS = CoordinateSystem.Identity();
pl = Plane.ByOriginNormal(WCS.Origin.Translate(0, 0,
0.5), WCS.ZAxis);
// intersect surface, generating three closed curves
crvs = surf.Intersect(pl);
crvs_moved = crvs.Translate(0, 0, 10);// python_points_5 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
surf = NurbsSurface.ByPoints(python_points_5, 3, 3);
tool_pts = Point.ByCoordinates((-10..20..10)<1>,
(-10..20..10)<2>, 1);
tool = NurbsSurface.ByPoints(tool_pts);
pick_point = Point.ByCoordinates(8, 1, 3);
result = surf.Trim(tool, pick_point);現在我們已經示範了如何在 Dynamo 中使用 Python 指令碼,接下來瞭解將 Revit 資源庫連接至指令碼撰寫環境。請記住,我們使用以下 Code Block 的前四行匯入了 Python 標準和 Dynamo 核心節點。若要匯入 Revit 節點、Revit 元素及 Revit 文件管理員,我們只需再加入幾行程式碼:
這會提供 Revit API 的存取權,以及適用於 Revit 工作的自訂指令碼。透過合併視覺程式設計程序與 Revit API 指令碼,將大幅改進協同合作與工具開發。例如,BIM 管理員與線路圖設計者可以針對同一圖表進行合作。透過這種協同合作,他們可以改善模型的設計與執行。
Dynamo 專案的潛在宗旨是拓寬平台的實作範圍。隨著 Dynamo 加入更多程式至事項表,使用者可以從 Python 指令碼撰寫環境存取平台特定 API。雖然在本節中只是對 Revit 進行案例研究,但我們可以預期在將來的更多章節中,會針對在其他平台撰寫指令碼提供全面的自學課程。此外,現在還可以存取許多 IronPython 資源庫,您可以將這些資源庫匯入 Dynamo!
以下範例示範使用 Python 從 Dynamo 實作 Revit 特定作業的方式。若要更詳細地檢閱 Python 與 Dynamo 及 Revit 之間的關係,請參閱Dynamo Wiki 頁面。Python 與 Revit 的另一項有用資源是 Revit Python Shell 專案。
建立新的 Revit 專案。
按一下下方的連結下載範例檔案。
附錄中提供完整的範例檔案清單。
在以下練習中,我們將探索 Dynamo for Revit 中的基本 Python 指令碼。此練習重點是處理 Revit 檔案及元素,以及 Revit 與 Dynamo 之間的通訊。
這是對連結至 Dynamo 階段作業的 Revit 檔案擷取 doc、uiapp 及 app 的現成方法。先前使用 Revit API 的程式設計人員可能會注意到觀看清單中的項目。如果對這些項目不熟悉,沒有問題,我們會在以下練習中使用其他範例。
以下將講述在 Dynamo 中如何匯入 Revit 服務及擷取文件資料。
看一下 Dynamo 中的 Python 節點。您也可以從下方找到程式碼:
按一下下方的連結下載範例檔案。
附錄中提供完整的範例檔案清單。
在本練習中,我們將在 Revit 內使用 Dynamo Python 節點建立簡單的模型曲線。
首先,在 Revit 中建立新的概念量體族群。
開啟 「概念量體」資料夾,然後使用 公制量體.rft 樣板檔。
在 Revit 中,使用鍵盤快速鍵 un 帶出「專案單位」設定,將長度單位變更為公尺。
啟動 Dynamo,然後建立以下影像中的一組節點。我們先在 Revit 中從 Dynamo 節點建立兩個參考點。
建立 Code Block,提供
"0;"的值將此值插入 ReferencePoint.ByCoordinates 節點做為 X、Y 與 Z 輸入。
建立三個滑棒,讓其範圍介於 -100 與 100 之間,且步長大小為 1。
將每個滑棒連接至 ReferencePoint.ByCoordinates 節點。
在工作區中加入 Python 節點,按一下節點上的「+」按鈕以加入另一個輸入,然後將兩個參考點插入每個輸入。開啟 Python 節點。
看一下 Dynamo 中的 Python 節點。在下方尋找完整的程式碼。
System.Array:Revit 需要一個系統陣列做為輸入 (而非 Python 清單)。這只是又一行程式碼,但注意引數類型將有助於在 Revit 中進行 Python 程式設計。
我們已在 Dynamo 中使用 Python 建立以直線連接的兩個參考點。接下來在下一個練習中更進一步。
按一下下方的連結下載範例檔案。
附錄中提供完整的範例檔案清單。
此練習仍很簡單,但講述了在 Revit 與 Dynamo 之間連接資料與幾何圖形的主題。我們從開啟 Revit-StructuralFraming.rvt 開始。開啟後,啟動 Dynamo,並開啟檔案 Revit-StructuralFraming.dyn。
此 Revit 檔案是一個非常基本的檔案。兩條參考曲線:一條繪製在 Level 1 上,另一條繪製在 Level 2 上。我們要將這些曲線匯入 Dynamo 並保持即時連結。
在此檔案中,我們將一組節點插入 Python 節點的五個輸入。
Select Model Element 節點: 按一下每個節點的選取按鈕,然後選取 Revit 中的對應曲線。
Code Block: 使用語法
0..1..#x;, 將介於 0 與 20 之間的整數滑棒連接至 x 輸入。此作業會指定在兩條曲線之間繪製的樑數量。Structural Framing Types: 在此我們將從下拉式功能表中選擇預設的 W12x26 樑。
Levels: 選取「Level 1」。
此 Python 程式碼稍多一些,但程式碼中的註解描述程序的狀況
在 Revit 中,我們有一個跨越兩條曲線的樑陣列做為結構元素。注意:這不是真實範例...結構元素是用做從 Dynamo 所建立原生 Revit 例證的範例。
在 Dynamo 中也可以看到結果。Watch3D 節點中的樑是指從 Revit 元素查詢的幾何圖形。
請注意,我們有一套連續的程序,將資料從 Revit 環境轉換到 Dynamo 環境。總之,程序的工作方式如下:
選取 Revit 元素
將 Revit 元素轉換為 Dynamo 曲線
將 Dynamo 曲線分割為一系列 Dynamo 點
使用兩條曲線之間的 Dynamo 點建立 Dynamo 線
透過參考 Dynamo 線建立 Revit 樑
透過查詢 Revit 樑的幾何圖形,輸出 Dynamo 曲面
這聽上去可能有點笨拙,但指令碼可讓該作業非常簡單,只需在 Revit 中編輯曲線並重新執行解析器即可 (雖然在執行此作業時,您可能不得不刪除先前的樑)。這是因為我們是以 Python 放置樑,因此破壞了 OOTB 節點所擁有的關聯。
在 Revit 中更新參考曲線後,我們得到一個新的樑陣列。

程式碼區塊有一些基本的速寫方法,簡言之,這些方法可以 顯著 降低資料管理的難度。以下我們將分類講解基本知識,並討論如何使用此速寫來建立與查詢資料。
資料類型
標準 Dynamo
Code Block 對等項
數字
定義範圍與序列的方法可以精簡為基本速寫。使用以下影像作為「..」語法的指南,以使用 Code Block 定義一系列數值資料。瞭解此標記法後,建立數值資料就會非常有效率:
在此範例中,數字範圍由定義
beginning..end..step-size;的基本 Code Block 語法所取代。以數字方式表示,我們得到:0..10..1;請注意,語法
0..10..1;相當於0..10;步長大小 1 是速寫標記法的預設值。因此0..10;將產生從 0 到 10 且步長大小為 1 的序列。
藉由建立進階範圍,我們能以簡單方式使用清單的清單。在以下範例中,我們將隔離變數與主要範圍標記,並建立該清單的另一個範圍。
1.建立巢狀範圍,對含與不含「#」的標記進行比較。套用基本範圍內的相同邏輯,只是變得稍複雜一些。
2.可以在主要範圍內的任何位置定義子範圍,請注意我們可以有兩個子範圍。
3.透過控制範圍內的「end」值,我們可以建立長度不同的多個範圍。
比較以上兩個速寫,並嘗試剖析 子範圍 與 # 標記如何產生結果輸出,來作為邏輯練習。
除了使用速寫建立清單外,我們也可以快速建立清單。這些清單可以包含多種元素類型,也可以進行查詢 (請記住,清單本身就是物件)。總而言之,使用 Code Block,您將使用括號 (方括號) 建立清單和查詢清單中的項目:
1.使用字串快速建立清單,並使用項目索引查詢清單。
2.使用變數建立清單,並使用範圍速寫標記查詢清單。
使用巢狀清單進行管理是類似的程序。請注意清單順序,並使用多組方括號呼叫:
1.定義清單的清單。
2.使用單邊括號查詢清單。
3.使用雙邊括號查詢項目。
按一下下方的連結下載範例檔案。
附錄中提供完整的範例檔案清單。
在本練習中,我們將靈活運用新的速寫技能,以建立由範圍與公式定義的炫酷蛋殼曲面。在本練習中,請注意我們如何搭配使用 Code Block 與既有 Dynamo 節點:我們對處理大量資料的工作使用 Code Block,而以視覺方式配置 Dynamo 節點以實現定義的易讀性。
首先,透過連接以上節點以建立曲面。不是使用數字節點來定義寬度與長度,而是按兩下圖元區,然後在 Code Block 中輸入 100;。
在 Code Block 中輸入
0..1..#50,定義介於 0 至 1 之間且分為 50 份的範圍。將該範圍連接至 Surface.PointAtParameter,這會在曲面內為 u 與 v 指定介於 0 與 1 之間的值。請記得在 Surface.PointAtParameter 節點上按一下右鍵,將「交織」變更為「笛卡兒積」。
在此步驟中,我們使用第一個函數在 Z 方向將點的格線上移。此格線將根據基本函數驅動產生的曲面。如以下影像所示新增節點
我們使用包含
(0..Math.Sin(x*360)..#50)*5;這一行的 Code Block。為了快速詳細說明這一點,我們將定義內含公式的範圍。此公式是正弦函數。正弦函數會接收 Dynamo 中輸入的角度,因此為了取得完整的正弦波形,我們將 x 值 (這是 0 到 1 的範圍輸入) 乘以 360。接下來,我們希望份數與每列的控制格線點數量相同,所以使用 #50 定義五十份。最後,乘數 5 只是為了增加平移的振幅,方便我們在 Dynamo 預覽中查看效果。
雖然上一個 Code Block 運作地很好,但它並非完全是參數式方法。我們要動態驅動其參數,因此我們將上一步的程式碼行取代為
(0..Math.Sin(x*360*cycles)..#List.Count(x))*amp;。藉此我們能根據輸入定義這些值。
透過變更滑棒 (範圍從 0 到 10),我們得到一些有趣的結果。
透過對數字範圍執行轉置,我們反轉窗簾波浪的方向:
transposeList = List.Transpose(sineList);
加入 sineList 與 transposeList 後會得到一個扭曲的蛋殼曲面:
eggShellList = sineList+transposeList;
變更下面指定的滑棒值,將此演算法「變平靜」。
最後,我們使用 Code Block 查詢資料的隔離部分。若要重新產生具有特定範圍點的曲面,請在 Geometry.Translate 與 NurbsSurface.ByPoints 節點之間加入以上 Code Block。這包括文字行:sineStrips[0..15..1];。這將選取前 16 列的點 (從 50 個點中)。重新建立曲面,我們可以看到已產生點格線的隔離部分。
在最後一個步驟中,為了讓此 Code Block 的參數式程度更高,我們使用範圍從 0 至 1 的滑棒來驅動該查詢。我們使用這一行程式碼執行此作業:
sineStrips[0..((List.Count(sineStrips)-1)*u)];。這可能有些混亂,但使用該行程式碼可以快速運用介於 0 和 1 之間的乘數來擴充清單長度。
若使用滑棒值 0.53,會建立一個剛好通過格線中點的曲面。
與預期一致,使用滑棒值 1 時,會從完整的點格線建立一個曲面。
查看視覺圖表,我們可以亮顯 Code Block,並查看其中的每項函數。
1.第一個 Code Block 取代 Number 節點。
2.第二個 Code Block 取代 Number Range 節點。
3.第三個 Code Block 取代 List.Transpose、List.Count 和 Number Range 節點。
4.第四個 Code Block 查詢清單的清單,取代 List.GetItemAtIndex 節點。
您可能發現 Dynamo 中節點名稱有一個常見現象:每個節點都使用 . 語法而不含空格。這是因為每個節點頂部的文字都表示指令碼撰寫的實際語法,而 . (或 點標記法 ) 將元素與我們可能呼叫的方法分開。這樣可以從視覺指令碼輕鬆轉換為文字型指令碼。
如果將點標記法做一般的類比,在 Dynamo 中如何處理一個參數式蘋果呢?以下是我們在決定吃蘋果之前先對蘋果執行的一些方法。(注意:這些方法不是實際的 Dynamo 方法)。
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
# Import Revit elements
from Revit.Elements import *
# Import DocumentManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
import System# Load the Python Standard and DesignScript Libraries
import sys
import clr
#Import DocumentManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
#Place your code below this line
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
#Assign your output to the OUT variable
OUT = [doc,uiapp,app]import sys
import clr
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
#Import Revit elements
from Revit.Elements import *
import System
#define inputs
startRefPt = IN[0]
endRefPt = IN[1]
#define system array to match with required inputs
refPtArray = System.Array[ReferencePoint]([startRefPt, endRefPt])
#create curve by reference points in Revit
OUT = CurveByPoints.ByReferencePoints(refPtArray)import clr
#import Dynamo Geometry
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
# Import Revit elements
from Revit.Elements import *
import System
#Query Revit elements and convert them to Dynamo Curves
crvA=IN[0].Curves[0]
crvB=IN[1].Curves[0]
#Define input Parameters
framingType=IN[3]
designLevel=IN[4]
#Define "out" as a list
OUT=[]
for val in IN[2]:
#Define Dynamo Points on each curve
ptA=Curve.PointAtParameter(crvA,val)
ptB=Curve.PointAtParameter(crvB,val)
#Create Dynamo line
beamCrv=Line.ByStartPointEndPoint(ptA,ptB)
#create Revit Element from Dynamo Curves
beam = StructuralFraming.BeamByCurve(beamCrv,designLevel,framingType)
#convert Revit Element into list of Dynamo Surfaces
OUT.append(beam.Faces)











序列 範例很類似,只是我們使用「#」來說明希望清單包含 15 個值,而非清單中的值不超過 15。在此範例中,我們將定義:beginning..#ofSteps..step-size: 序列的實際語法為 0..#15..2
使用上一步的 #,現在將其放在語法的 step-size 部分。現在,我們產生一個從 beginning 到 end 的 數字範圍,step-size 標記將許多值均勻分佈在這兩個值之間:beginning..end..#ofSteps
字串
序列
範圍
取得索引處的項目
建立清單
連接字串
條件陳述式
節點
Code Block 對等項
附註
任何運算子 (+、&&、>=、Not... 等等)
+、&&、>=、!... 等等
請注意,「Not」變成「!」,但節點稱為「Not」以便與「階乘」區分
Boolean True
true;
請注意小寫
Boolean False
false;
請注意小寫



















Apple.isRipe
true
蘋果有多重?
Apple.weight
6 盎司。
蘋果來自何處?
Apple.parent
樹
蘋果建立哪些項目?
Apple.children
種子
這個蘋果是本地生長的嗎?
Apple.distanceFromOrchard
60 英里。
我不知道您覺得如何,但根據以上表格的輸出來判斷,這似乎是一個美味的蘋果。我認為我會執行 Apple.eat()。
記住蘋果的類比,我們來看看 Point.ByCoordinates,並示範如何使用 Code Block 建立一個點。
在 Dynamo 中,Code Block 語法 Point.ByCoordinates(0,10); 產生的結果與 Point.ByCoordinates 節點相同,只是我們可以使用一個節點來建立點。比起將不同節點連接至 X 與 Y,此方法更有效率。
在 Code Block 中使用 Point.ByCoordinates,我們就是以內建節點 (X,Y) 的順序指定輸入。
您可以透過 Code Block 呼叫資源庫中的任何一般節點,只要該節點不是特殊的 「使用者介面」節點 (具有特殊的使用者介面功能) 即可。例如,您可以呼叫 Circle.ByCenterPointRadius,但是呼叫 Watch 3D 節點意義不大。
一般節點 (資源庫中的大多數節點) 通常分為三種類型。您會發現資源庫在組織時也考慮到了這些品類。在 Code Block 中呼叫時,對這三種類型方法 (或節點) 的處理方式不同。
建立 - 建立 (或建構) 項目
動作 - 對某項目執行動作
查詢 - 取得既有項目的性質
「建立」品類將從零開始建構幾何圖形。我們在 Code Block 中以從左至右的順序輸入值。這些輸入的順序與節點中從上到下的輸入順序相同。
將 Line.ByStartPointEndPoint 節點與 Code Block 中對應的語法做比較,可以獲得相同結果。
動作是您對該類型的物件執行的行為。Dynamo 使用許多程式語言中通用的 點標記法 對物件套用動作。確定物件後,輸入點,後接動作名稱。動作類型方法的輸入將放置在括號中,類似於建立類型的方法,只是您不必指定對應節點上看到的第一個輸入。我們改為指定執行動作時所依據的元素:
Point.Add 節點是動作類型節點,因此語法稍有不同。
輸入是 (1) point 以及要加上去的 (2) vector。在 Code Block 中,我們已將點 (物件) 命名為 pt。為了將命名為 vec 的向量加入 pt,我們會撰寫 pt.Add(vec) 或採用「物件, 點, 動作」的格式。加入動作僅有一個輸入,也就是 Point.Add 節點的所有輸入減去第一個輸入。Point.Add 節點的第一個輸入是點本身。
查詢類型的方法會取得物件的性質。由於物件本身就是輸入,因此您不必指定任何輸入。不需要使用括號。
節點的交織與 Code Block 的交織稍有不同。如果是節點,使用者會在節點上按一下右鍵,然後選取要執行的交織選項。如果是 Code Block,使用者對於資料的建構方式會有更多的控制。Code Block 速寫方法使用 複製指南 設定幾個一維清單應採用的配對方式。角括號 <> 中的數字定義所產生巢狀清單的階層:<1>、<2>、<3> 等。
在此範例中,我們使用速寫來定義兩個範圍 (本章的下一節將講述速寫的更多內容)。簡單來說,
0..1;相當於{0,1},-3..-7相當於{-3,-4,-5,-6,-7}。結果將產生包含 2 個 x 值與 5 個 y 值的清單。如果我們不對這些不相符的清單使用複製指南,則會得到包含兩個點的清單,這是長度最短的清單。使用複製指南,我們可以找出 2 個座標與 5 個座標所有可能的組合 (即笛卡兒積)。使用語法 Point.ByCoordinates
(x_vals<1>,y_vals<2>);,可以得到 兩個 清單,每個清單有 五個 項目。使用語法 Point.ByCoordinates
(x_vals<2>,y_vals<1>);,可以得到 五個 清單,每個清單有 兩個 項目。
使用此標記法,我們也可以指定哪個清單佔優勢:2 個清單 (各包含 5 個項目) 還是 5 個清單 (各包含 2 個項目)。在此範例中,若變更複製指南的順序,結果將在格線中產生一列點清單或一欄點清單。
以上 Code Block 方法可能花一點時間才能習慣,而 Dynamo 中提供稱為「將節點轉換為程式碼」功能,可以讓程序更輕鬆。若要使用此功能,請在 Dynamo 圖表中選取一系列節點,在圖元區上按一下右鍵,然後選取「將節點轉換為程式碼」。Dynamo 會將這些節點及所有輸入與輸出濃縮到一個 Code Block 中!這不僅是一個強大的工具可學習 Code Block,也能讓您處理更高效的參數式 Dynamo 圖表。我們將使用「將節點轉換為程式碼」結束以下練習,因此請勿錯過。
按一下下方的連結下載範例檔案。
附錄中提供完整的範例檔案清單。
為了展示 Code Block 的強大功能,我們要將既有的牽引欄位定義轉換為 Code Block 形式。使用既有定義可示範 Code Block 與視覺指令碼如何具有相關性,有助於學習 DesignScript 語法。
先重新建立以上影像中的定義 (或開啟範例檔案)。
請注意,Point.ByCoordinates 的交織已設定為 「笛卡兒積」。
格線中的每個點都會根據其與參考點的距離而沿著 Z 方向上移。
重新建立並增厚曲面,同時在幾何圖形上建立相對於距參考點距離的凸度。
從頭開始,我們先定義參考點:Point.ByCoordinates
(x,y,0);我們使用的 Point.ByCoordinates 語法與參考點節點上方指定的語法相同。將變數 x 與 y 插入 Code Block,以便我們可以使用滑棒動態更新這些內容。
在 Code Block 的輸入加入一些 滑棒,範圍從 -50 到 50。這樣我們可以跨越整個預設 Dynamo 格線。
在 Code Block 的第二行,我們定義速寫以取代數字序列節點:
coordsXY = (-50..50..#11);我們將在下一節詳細討論此內容。現在,請注意此速寫相當於視覺指令碼中的 Number Sequence 節點。
現在,我們將從 coordsXY 序列建立點的格線。為了執行此作業,我們要使用 Point.ByCoordinates 語法,但還需要使用我們在視覺指令碼中採用的方式,創造一個清單的 笛卡兒積。為了執行此作業,我們鍵入行:
gridPts = Point.ByCoordinates(coordsXY<1>,coordsXY<2>,0);角括號表示笛卡兒積參考。請注意,在 Watch3D 節點中,我們有一個橫越 Dynamo 格線的點格線。
現在講解困難的部分:我們希望根據點距參考點的距離,將這些點的格線上移。首先,我們呼叫這一組新點 transPts。由於平移是針對既有元素的動作,因此我們不用
Geometry.Translate...,而是使用gridPts.Translate從圖元區上的實際節點,我們可以看到有三個輸入。要平移的 geometry 已經宣告,因為我們正對該元素執行動作 (使用 gridPts.Translate)。其餘兩個輸入將插入函數 direction 與 distance 的括號內。
direction 很簡單,我們使用
Vector.ZAxis()垂直移動。參考點與每個格線點之間的距離仍需要計算,因此我們使用相同方式對參考點執行此動作:
refPt.DistanceTo(gridPts)程式碼的最後一行得出平移後的點:
transPts=gridPts.Translate(Vector.ZAxis(),refPt.DistanceTo(gridPts));
我們現在已經有資料結構適當的點格線,可以建立 Nurbs 曲面。我們使用
srf = NurbsSurface.ByControlPoints(transPts);建構曲面
最後,為了對取面增加一些深度,我們使用
solid = srf.Thicken(5);建構實體。在此案例中,我們在程式碼中將曲面變厚了 5 個單位,不過也可以將其宣告為變數 (例如將其稱為 thickness),然後使用滑棒控制該值。
只需按一下按鈕,「將節點轉換為程式碼」功能即可自動執行我們剛剛完成的整個練習。這不僅在建立自訂定義及可重複使用的 Code Block 時很有威力,也是瞭解如何在 Dynamo 中撰寫指令碼非常有用的工具。
先使用練習的步驟 1 中使用的既有視覺指令碼。選取所有節點,在圖元區上按一下右鍵,然後選取 「將節點轉換為程式碼」。非常簡單。
Dynamo 已自動建立文字版本的視覺圖表、交織與全部項目。在您的視覺指令碼上試試看,體驗 Code Block 的強大功能!
蘋果的顏色是什麼?
Apple.color
紅色

蘋果成熟了嗎?
















按兩下節點會開啟 Python Script 編輯器 (您也可以在節點上按一下右鍵,然後選取 「編輯...」 )。您會發現頂部有一些模板文字,目的是協助您參考您會需要的資源庫。輸入儲存於 IN 陣列中。為 OUT 變數指定值,值就會傳回到 Dynamo 中
藉由 Autodesk.DesignScript.Geometry 資源庫,您可以使用與程式碼區塊類似的點標記法。如需有關 Dynamo 語法的更多資訊,請參閱 https://github.com/DynamoDS/DynamoPrimerNew/blob/master-cht/coding-in-dynamo/7_code-blocks-and-design-script/7-2_design-script-syntax.md 以及 DesignScript 指南 (若要下載此 PDF 文件,請在連結上按一下右鍵,然後選擇「另存連結為...」)。鍵入幾何圖形類型 (例如「Point.」) 將顯示建立和查詢點的方法清單。
這些方法包括建構函式 (例如 ByCoordinates)、動作 (例如 Add) 以及查詢 (例如 X、Y、Z 座標)。
按一下下方的連結下載範例檔案。
附錄中提供完整的範例檔案清單。
在此範例中,我們將編寫從實體模組建立樣式的 Python 指令碼,然後將其轉換為自訂節點。首先,使用 Dynamo 節點建立實體模組。
Rectangle.ByWidthLength: 建立將做為實體基礎的矩形。
Surface.ByPatch: 將矩形連接至 closedCurve 輸入以建立底部曲面。
Geometry.Translate: 將矩形連接至 geometry 輸入以將其上移,使用程式碼區塊指定實體的基礎厚度。
Polygon.Points: 查詢平移的矩形以擷取角點。
Geometry.Translate: 使用程式碼區塊建立對應到四個點的四個值清單,同時將實體的一個角點上移。
Polygon.ByPoints: 使用平移的點重新建構頂部多邊形。
Surface.ByPatch: 連接多邊形以建立頂部曲面。
現在我們已建立頂部與底部曲面,接下來在兩個輪廓之間進行斷面混成,以建立實體的側面。
List.Create: 將底部矩形與頂部多邊形連接至索引輸入。
Surface.ByLoft: 對兩個輪廓進行斷面混成,以建立實體的側面。
List.Create: 將頂部、側面與底部的曲面連接至索引輸入,以建立曲面清單。
Solid.ByJoinedSurfaces: 接合曲面以建立實體模組。
現在我們已建立實體,接下來將 Python Script 節點放入工作區。
若要在節點中加入其他輸入,請按一下節點上的「+」圖示。輸入命名為 IN[0]、IN[1] 等等,以指出它們代表清單中的項目。
我們先定義輸入與輸出。按兩下節點以開啟 python 編輯器。請依照下面的程式碼,在編輯器中修改程式碼。
在我們進行練習時,此程式碼會更容易理解。接下來,我們需要考慮需要哪些資訊以排列實體模組。首先,我們需要知道實體的標註,以確定平移距離。由於存在邊界框錯誤,我們不得不使用邊曲線幾何圖形來建立邊界框。
看一下 Dynamo 中的 Python 節點。請注意,我們使用的語法與 Dynamo 節點標題中的語法相同。查看下面加上註解的程式碼。
由於我們將平移並旋轉實體模組,因此接下來使用 Geometry.Transform 作業。看一下 Geometry.Transform 節點,我們知道需要來源座標系統與目標座標系統,以平移實體。來源是實體的關聯座標系統,而目標是所排列每個模組的不同座標系統。這表示我們必須循環使用 x 值與 y 值,以便每次以不同方式平移座標系統。
按一下「執行」,然後儲存程式碼。將 Python 節點與既有的指令碼連接,如下所示。
將 Solid.ByJoinedSurfaces 的輸出連接為 Python 節點的第一個輸入,並使用 Code Block 定義其他輸入。
建立 Topology.Edges 節點,並使用 Python 節點的輸出做為其輸入。
最後,建立 Edge.CurveGeometry 節點,並使用 Topology.Edges 的輸出做為其輸入。
請嘗試變更種子值以建立不同的樣式。您也可以變更實體模組本身的參數,以取得不同的效果。
現在我們已建立有用的 Python 指令碼,接下來將其另存成自訂節點。選取 Python Script 節點,在「工作區」上按一下右鍵,然後選取「建立自訂節點」。
指定名稱、描述與品類。
這會開啟一個新的工作區,可從中編輯自訂節點。
Input: 變更輸入名稱以更具描述性,然後加入資料類型及預設值。
Output: 變更輸出名稱
將節點儲存為 .dyf 檔案,您應該會看到自訂節點反映我們剛才所做的變更。















import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
solid = IN[0]
seed = IN[1]
xCount = IN[2]
yCount = IN[3]
solids = []
yDist = solid.BoundingBox.MaxPoint.Y-solid.BoundingBox.MinPoint.Y
xDist = solid.BoundingBox.MaxPoint.X-solid.BoundingBox.MinPoint.X
for i in xRange:
for j in yRange:
fromCoord = solid.ContextCoordinateSystem
toCoord = fromCoord.Rotate(solid.ContextCoordinateSystem.Origin,Vector.ByCoordinates(0,0,1),(90*(i+j%val)))
vec = Vector.ByCoordinates((xDist*i),(yDist*j),0)
toCoord = toCoord.Translate(vec)
solids.append(solid.Transform(fromCoord,toCoord))
OUT = solids# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# The inputs to this node will be stored as a list in the IN variables.
#The solid module to be arrayed
solid = IN[0]
#A Number that determines which rotation pattern to use
seed = IN[1]
#The number of solids to array in the X and Y axes
xCount = IN[2]
yCount = IN[3]
#Create an empty list for the arrayed solids
solids = []
# Place your code below this line
# Assign your output to the OUT variable.
OUT = solids# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# The inputs to this node will be stored as a list in the IN variables.
#The solid module to be arrayed
solid = IN[0]
#A Number that determines which rotation pattern to use
seed = IN[1]
#The number of solids to array in the X and Y axes
xCount = IN[2]
yCount = IN[3]
#Create an empty list for the arrayed solids
solids = []
#Create an empty list for the edge curves
crvs = []
# Place your code below this line
#Loop through edges an append corresponding curve geometry to the list
for edge in solid.Edges:
crvs.append(edge.CurveGeometry)
#Get the bounding box of the curves
bbox = BoundingBox.ByGeometry(crvs)
#Get the x and y translation distance based on the bounding box
yDist = bbox.MaxPoint.Y-bbox.MinPoint.Y
xDist = bbox.MaxPoint.X-bbox.MinPoint.X
# Assign your output to the OUT variable.
OUT = solids# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# The inputs to this node will be stored as a list in the IN variables.
#The solid module to be arrayed
solid = IN[0]
#A Number that determines which rotation pattern to use
seed = IN[1]
#The number of solids to array in the X and Y axes
xCount = IN[2]
yCount = IN[3]
#Create an empty list for the arrayed solids
solids = []
#Create an empty list for the edge curves
crvs = []
# Place your code below this line
#Loop through edges an append corresponding curve geometry to the list
for edge in solid.Edges:
crvs.append(edge.CurveGeometry)
#Get the bounding box of the curves
bbox = BoundingBox.ByGeometry(crvs)
#Get the x and y translation distance based on the bounding box
yDist = bbox.MaxPoint.Y-bbox.MinPoint.Y
xDist = bbox.MaxPoint.X-bbox.MinPoint.X
#Get the source coordinate system
fromCoord = solid.ContextCoordinateSystem
#Loop through x and y
for i in range(xCount):
for j in range(yCount):
#Rotate and translate the coordinate system
toCoord = fromCoord.Rotate(solid.ContextCoordinateSystem.Origin, Vector.ByCoordinates(0,0,1), (90*(i+j%seed)))
vec = Vector.ByCoordinates((xDist*i),(yDist*j),0)
toCoord = toCoord.Translate(vec)
#Transform the solid from the source coord syste, to the target coord system and append to the list
solids.append(solid.Transform(fromCoord,toCoord))
# Assign your output to the OUT variable.
OUT = solids















語言變更部分概述對 Dynamo 每個版本中的語言所做的更新和修改。這些變更可能會影響功能、效能和使用方式,本指南將協助使用者瞭解何時以及為何要適應這些更新。
將 list@level 語法從「@-1」變更為「@L1」
list@level 的新語法是使用 list@L1 而不是 list@-1
動機:讓程式碼語法與預覽/使用者介面一致,使用者測試表明此新語法更容易理解
在 TS 中實施 Int 和 Double 類型,以便與 Dynamo 類型保持一致
不允許其引數僅基數不同的多載函數
使用已移除多載的舊圖表,應預設為等級較高的多載。
動機:消除要執行哪個特定函數的不明確性
使用複製指南時停用陣列提升
讓指令式區塊中的變數對指令式區塊範圍是局部變數
指令式 Code Block 內部定義的變數值,不會因參考它們的指令式區塊內部的變更而改變。
讓變數成為不變,以停用 Code Block 節點中的關聯式更新
將所有使用者介面節點編譯為靜態方法
支援沒有指定的傳回陳述式
函數定義或指令式程式碼中都不需要「=」。
移轉 CBN 中的舊方法名稱
許多節點已更名,提高在資源庫瀏覽器使用者介面中的可讀性和放置
在字典清理時使用清單
已知問題:
指令式區塊中的名稱空間衝突會導致出現意外的輸入埠。請參閱 以取得更多資訊。若要解決此問題,請如下所示定義指令式區塊外部的函數:
我們大量改進 Dynamo 2.0 版的語言。這樣做的主要動機是簡化語言。重點一直是讓 DesignScript 更容易理解和使用,使其更強大和靈活,目的是提高終端使用者的理解。
以下是 2.0 中的變更清單說明:
簡化 List@Level 語法
其參數只有等級不同的多載方法是不合法的
將所有使用者介面節點編譯為靜態方法
與複製指南/交織一起使用時停用清單提升
list@level 的新語法是使用 list@L1 而不是 list@-1
多載函數有問題的原因很多:
圖表中的使用者介面節點指出的多載函數,可能與執行階段所執行的多載不同
方法解析成本高昂,也不適用於多載函數
很難理解多載函數的複製行為
以 BoundingBox.ByGeometry 為例 (舊版 Dynamo 中有兩個多載函數),一個採用單值引數,另一個採用幾何清單作為引數:
如果使用者將第一個節點放在圖元區上並連接一個幾何圖形清單,他希望複製能夠啟動,但這永遠不會發生,因為在執行階段將改為呼叫第二個多載,如下所示:
在 2.0 中,我們不允許由於這個原因僅在參數基數上不同的多載函數。這表示,對於有相同數量和類型的參數但有一個或多個參數只是等級不同的多載函數,先定義的多載永遠優先,編譯器會捨棄其餘多載。進行這種簡化的主要優點是透過一個快速方式選擇候選函數,可以簡化方法解析邏輯。
在 2.0 的幾何圖形資源庫中,棄用了 BoundingBox.ByGeometry 範例中的第一個多載,保留了第二個多載,因此,如果節點是要複製 (亦即用於第一個的環境中),則必須搭配最短 (或最長) 交織選項使用,或在有複製指南的 Code Block 中使用:
在這個例子中,我們可以看到,等級較高的節點既可以在複製呼叫中使用,也可以在非複製呼叫中使用,因此永遠優先於等級較低的多載。因此,根據經驗法則,一律建議節點作者放棄等級較低的多載,而使用等級較高的方法,以便 DesignScript 編譯器永遠會呼叫等級較高的方法,作為它找到的第一個方法 (也是唯一一個方法)。
下面的範例中定義了函數 foo 的兩個多載。在 1.x 中,哪個多載會在執行階段執行並不明確。使用者可能期望執行第二個多載 foo(a:int, b:int),在這種情況下,應該是方法要複製三次並傳回三次 10 的值。實際上傳回的是 10 的單一值,因為呼叫的是帶有 list 參數的第一個多載。
在 2.0 中,永遠是定義的第一種方法而不是其餘方法。先到先贏。
對於以下每種情況,將採用定義的第一個多載。請注意,它純粹基於定義函數的順序,而不是參數等級,但建議針對使用者定義和 ZeroTouch 節點優先使用參數等級較高的方法。
在 Dynamo 1.x 中,分別將 1.x 的使用者介面節點 (非 Code Block) 編譯為實體方法和性質。例如,Point.X 節點編譯為 pt.X,Curve.PointAtParameter 編譯為 curve.PointAtParameter(param)。此行為有兩個問題:
A.使用者介面節點表示的函數並不一定與執行階段所執行的函數相同
一個典型的範例是 Translate 節點。有多個 Translate 節點採用相同數量和類型的引數,例如:Geometry.Translate、Mesh.Translate 和 FamilyInstance.Translate。由於這些節點都是編譯為實體方法,因此將 FamilyInstance 傳入 Geometry.Translate 節點在執行階段意外地仍然有作用,因為它會將呼叫分派到 FamilyInstance 上的 Translate 實體方法。這顯然會誤導使用者,因為該節點並沒有按照它說的進行。
B.第二個問題是實體方法不適用於異質陣列
在執行階段時,執行引擎需要找出應該分派到哪個函數。如果輸入是清單 (例如 list.Translate()),由於完整瀏覽清單中的每個元素並對其類型查詢方法非常耗費資源,因此方法解析邏輯只需假設目標類型與第一個元素的類型相同,然後嘗試查詢針對該類型定義的 Translate() 方法。因此,如果第一個元素類型與方法的目標類型不符 (或者如果它甚至是 null 或空清單),則即使清單中有其他相符的類型,整個清單也會失敗。
例如,如果將具有類型 [Arc, Line] 的清單輸入傳入 Arc.CenterPoint,則如果是弧,結果如預期會包含一個中心點,如果是線,結果則是 null 值。但是如果順序顛倒,則整個結果是空值,因為第一個元素無法通過方法解析檢查:
在 2.0 中,透過將使用者介面節點編譯為靜態性質和靜態方法,可以解決這兩個問題。
使用靜態方法,執行階段方法解析更直接,會反覆運算輸入清單中的所有元素。例如:
foo.Bar() (實體方法) 語義需要檢查 foo 的類型,也會檢查它是否是清單,然後將其與候選函數比對。這很耗費資源。相反地,Foo.Bar(foo) (靜態方法) 語義只需要檢查一個其參數類型為 foo 的函數!
以下是在 2.0 中發生的情況:
使用者介面性質節點編譯為靜態 getter:引擎為每個性質產生 getter 的靜態版本。例如,Point.X 節點編譯為靜態 getter Point.get_X(pt)。請注意,靜態 getter 也可以在 Code Block 節點中使用其別名 Point.X(pt) 來呼叫。
使用者介面方法節點編譯為靜態版本:引擎為節點產生對應的靜態方法。例如,Curve.PointAtParameter 節點編譯為 Curve.PointAtParameter(curve: Curve, parameter:double) 而非 curve.PointAtParameter(parameter)。
注意: 我們尚未移除此變更的實體方法支援,因此 CBN 中使用的現有實體方法 (如上述範例中的 pt.X 和curve.PointAtParameter(parameter)) 仍然有作用。
此範例先前在 1.x 中有作用,因為圖表將編譯為 point.X;,它會尋找點物件的 X 性質。它現在在 2.0 中失敗,因為編譯的程式碼 - Vector.X(point) 只需要一個 Vector 類型:
前後一致/可理解: 靜態方法消除了哪個方法將在執行階段執行的任何不確定性。方法永遠與圖表中使用者預期會被呼叫的使用者介面節點一致。
相容: 程式碼和視覺程式之間有更好的相關性。
提供指導: 將異質清單輸入傳入節點現在會導致節點接受的類型為非空值,而未實作節點的類型為空值。結果更可預測,且更清楚指出哪些是節點允許的類型。
由於 Dynamo 通常支援函數多載,因此如果另一個多載函數有相同數量的參數,可能還是會讓人感到困惑。例如,在以下圖表中,如果我們將一個數值連接到 Curve.Extrude 的 direction 輸入,將一個向量連接到 Curve.Extrude 的 distance 輸入,兩個節點都會繼續運作,這不是預期的狀況。在這種情況下,即使節點編譯為靜態方法,引擎仍然無法在執行階段分辨出差異,並根據輸入類型選擇其中一種。
轉換成靜態方法語義會產生以下副作用,由於相關的 2.0 語言變更,因此在這裡說明這些副作用。
1.喪失多型行為:
我們考慮 ProtoGeometry 中 TSpline 節點的範例 (請注意,TSplineTopology 繼承自基底 Topology 類型):先前編譯為實體方法 object.Edges 的 Topology.Edges 節點現在編譯為靜態方法 Topology.Edges(object)。某個方法在執行階段分派物件類型後,先前的呼叫會以多型方式解析為衍生的類別方法 TsplineTopology.Edges。
而新的靜態行為則被迫呼叫基底類別方法 Topology.Edges。結果,此節點傳回的是基底類別 Edge 物件,而不是類型為 TSplineEdge 的衍生類別物件。
這是一種倒退的結果,因為預期是 TSplineEdges 的下游 TSpline 節點開始失敗。
此問題已透過在方法分派邏輯中增加一個執行階段檢查,針對方法第一個參數的類型或子類型檢查實體類型而解決。對於輸入清單,我們簡化了方法分派,只檢查第一個元素的類型。因此,最終的解決方法是折衷使用部分靜態和部分動態的方法查詢。
2.0 中新的多型行為:
在此案例中,由於第一個元素 a 是 TSpline ,因此在執行階段呼叫的是 TSplineTopology.Edges 衍生方法。結果它針對基底 Topology 類型 b 傳回 null。
在第二個案例中,由於一般的 Topology 類型 b 是第一個元素,因此呼叫基底 Topology.Edges 方法。由於 Topology.Edges 也恰好接受衍生的 TSplineTopology 類型 a 當作輸入,因此它針對 a 和 b 兩個輸入都傳回 Edges。
2.因為外層產生多餘的清單而導致倒退
在複製指南行為方面,實體方法和靜態方法之間有一個主要差異。使用實體方法,帶有複製指南的單值輸入不會提升為清單,而靜態方法會提升。
我們來看看 Surface.PointAtParameter 節點的範例,該節點使用笛卡兒積交織、單一曲面輸入以及 u 和 v 參數值的陣列。實體方法編譯為:
產生一個 2D 點陣列。
靜態方法編譯為:
產生一個 3D 點清單 (最外層多出一個清單)。
將使用者介面節點編譯為靜態方法的這種副作用,可能會導致這類現有使用案例的倒退。此問題已透過在與複製指南/交織一起使用時,停用將單值輸入提升為清單來解決 (請參閱下一項)。
4.使用複製指南/交織時停用清單提升
在 1.x 中,有兩種情況會將單值提升為清單:
將等級較低的輸入傳入需要等級較高輸入的函數時
將等級較低的輸入傳入需要相同等級的函數,但輸入引數使用複製指南裝飾或使用交織時
在 2.0 中,我們阻止且不再支援在後者這類情況下進行清單提升。
在下面的 1.x 圖表中,每個 y 和 z 各有一層複製指南,強制對它們都進行 1 級的陣列提升,這就是為什麼結果有 3 級 (x、y、z 各 1 級)。但是使用者期望結果是 1 級,因為即使單值輸入有複製指南,也不容易看出會讓結果增加層數。
在 2.0 中,每個單值引數 y 和 z 即使有複製指南也不會導致提升,因此清單維度與 x 的 1D 輸入清單相同。
上述因靜態方法編譯而產生外層多餘清單的倒退,也透過這種語言變更而獲得解決。
繼續使用上面同一個範例,我們看到像下面的靜態方法呼叫:
在 Dynamo 1.x 中產生一個 3D 點清單。發生這種情況的原因是,當與複製指南一起使用時,第一個單值引數曲面提升為清單。
在 2.0 中,我們停用與複製指南或交織搭配使用時,將單值引數提升為清單的功能。所以現在呼叫:
只會傳回 2D 清單,因為沒有將曲面提升。
這項變更現在移除額外多出的清單階層,也解決因為轉換為靜態方法編譯所導致的倒退問題。
清楚: 結果符合使用者預期,也更容易理解
相容: 使用者介面節點 (使用交織選項) 和使用複製指南的 CBN 會提供相容的結果
一致:
實體方法和靜態方法一致 (修正靜態方法語義的問題)
使用輸入和使用預設引數的節點行為一致 (請參閱下文)
DesignScript 歷來支援兩種程式設計典範 - 關聯式程式設計和指令式程式設計。關聯式程式碼從變數彼此有相依性的程式陳述句建立相依性圖表。更新某個變數可能會觸發相依於此變數的其他所有變數的更新。這表示關聯式區塊中陳述句的執行順序,不是根據其順序,而是根據變數之間的相依性關係。
在下面的範例中,程式碼的執行順序是行 1 -> 2 -> 3 -> 2。由於 b 相依於 a,因此當第 3 行的 a 更新時,執行會再跳到第 2 行,以使用新的 a 值更新 b。
相反地,如果在指令式環境中執行相同的程式碼,則陳述句會以線性方式、從上到下的流程執行。因此,指令式的 Code Block 適合依序執行 (如迴圈和 if-else 條件) 的程式碼結構。
1.具有循環相依性的變數:
在某些情況下,變數之間的循環相依性可能不像以下案例如此明顯。在編譯器無法靜態偵測循環的這類案例中,可能會導致無限的執行階段循環。
2.相依於自己的變數:
如果變數相依於自己,其值應該要累積?還是應該在每次更新時重設為其原始值?
在此幾何圖形範例中,由於立方體 b 既相依於自己,也相依於圓柱 a,則移動滑棒應該要讓孔沿圖塊移動?還是應該針對每個滑棒位置更新,沿其路徑打出多個孔而產生一個累積性的效果?
3.更新變數的性質:
4.更新函數:
根據經驗,我們發現關聯式更新對節點型的資料流程圖表環境中的 Code Block 節點沒有用處。在任何視覺程式設計環境出現之前,探索選項唯一的方法是明確地更改程式中某些變數的值。文字型程式有變數更新的完整記錄,而在視覺程式設計環境中只顯示變數的最新值。
如果某些使用者真的使用變數,很可能他們是在不知不覺的情況下使用,而導致弊大於利。因此,我們決定在 2.0 的 Code Block 節點讓變數不變來隱藏關聯性,同時繼續讓關聯式更新只作為 DS 引擎的原生功能。這是為簡化使用者的腳本編寫體驗而進行的另一項變更。
透過阻止 CBN 中的變數重新定義,停用關聯式更新:
在 Code Block 中仍允許使用清單編製索引
清單編製索引是一個例外,在 2.0 中仍允許指定索引運算子。
在下一個範例中,我們會看到清單 a 已初始化,但之後可以指定索引運算子來覆寫,且任何相依於 a 的變數都會關聯地更新,如 c 的值所示。而且,在重新定義一個或多個元素之後,節點預覽會顯示 a 的更新值。
我們變更了 2.0 的指令式範圍規則,停用複雜的跨語言更新情境。
在 Dynamo 1.x 中,以下腳本的執行順序會是行 1 -> 2 -> 4 -> 6 -> 4,當中會從外部向內部的語言範圍傳遞變更。由於 y 是在外部的關聯式區塊中更新,而指令式區塊中的 x 相依於 y,因此控制將從外部的關聯式程式轉移到第 4 行的指令式語言。
在下一個範例中,執行順序會是行:1 -> 2 -> 4 -> 2,其中會從內部向外部的語言範圍傳遞變更。
上述情境是指跨語言更新,就像關聯式更新在 Code Block 節點中不是很有用一樣。為了停用複雜的跨語言更新情境,我們已讓指令式範圍中的變數成為局部變數。
在 Dynamo 2.0 的以下範例中:
指令式區塊中定義的 x 現在對於指令式範圍是局部變數
外部範圍中的 x 值和 y 值分別仍是 1 和 2
如果要在外部範圍中存取指令式區塊內的任何局部變數值,則需要傳回該變數。
請參考以下範例:
在指令式範圍內局部複製 y
指令式範圍內 x 的局部值為 4
由於跨語言更新,更新外部範圍中 y 的值,會繼續導致 x 更新,但在 2.0 的 Code Block 中由於變數不變性而停用
在 Dynamo 1.x 中,清單和字典由單一統一的容器表示,透過整數索引和非整數鍵可以對該容器編製索引。下表總結 2.0 中清單和字典之間的區別,以及新字典資料類型的規則:
[] 清單語法在 2.0 中,清單初始化語法從大括號 {} 變更為方括號 []。所有 1.x 腳本在 2.0 中打開時,都會自動移轉成新語法。
關於 Zero Touch 節點上預設引數屬性的注意事項:
但是請注意,自動移轉不適用於預設引數屬性中使用的舊語法。節點作者需要手動更新其 zero-touch 方法定義,才能使用預設引數屬性 DefaultArgumentAttribute 中的新語法 (如有必要)。
關於編製索引的注意事項:
新的編製索引行為在某些情況下變得不同。使用 [] 運算子將索引編製成包含任意索引/鍵清單的清單/字典,現在會保留索引/鍵輸入清單的清單結構。以前永遠會傳回值的 1D 清單:
字典初始化的 {} (大括號語法) 只能用在
的鍵值對格式,其中的 <key> 只能使用一個字串,而且以逗號分隔多個鍵值對。
Dictionary.ByKeysValues zero-touch 方法可透過分別傳入鍵和值的清單,並使用 zero-touch 方法 (如複製指南等) 的所有花俏功能,當作初始化字典一個更多樣的方式。
我們嘗試過在字典鍵值初始化語法中對鍵使用任意表示式的想法,但是發現它可能會導致讓人混淆的結果,尤其是像 {keys : vals} (keys,vals 都表示清單) 這樣的語法會干擾 DesignScript 的其他語言功能 (如複製) 並產生與 zero touch 初始設定式節點不同的結果。
例如,可能會有其他類似此陳述句很難定義預期行為的情況:
進一步增加複製指南語法等而不只是識別項,有違語言簡單性的想法。
我們將來也許_可以_擴充字典鍵以支援任意表示式,但我們也必須確保與其他語言功能的互動是一致且可理解,但代價是提高複雜度,而不是讓系統功能變弱但容易理解。因為總是能使用 Dictionary.ByKeysValues(keyList, valueList) 方法作為替代方法來解決問題,這並不會很困難。
1.傳回 .NET 字典的 Zero Touch 節點會傳回為 Dynamo 字典
請考慮以下傳回 IDictionary 的 zero-touch C# 方法:
對應的 ZT 節點傳回值會編組成 Dynamo 字典:
2.多重傳回節點的預覽形式為字典
以多重傳回屬性傳回 IDictionary 的 Zero Touch 節點會傳回 Dynamo 字典:
3.Dynamo 字典可作為輸入傳入接受 .NET 字典的 Zero-touch 節點
具有 IDictionary 參數的 ZT 方法:
ZT 節點接受 Dynamo 字典作為輸入:
字典是未排序的鍵值對。因此同樣地,傳回字典之節點的鍵值對預覽,也無法保證會按照節點傳回值的順序進行排序。
但是,我們為已定義 MultiReturnAttribute 的多重傳回節點做出例外。在以下範例中,DateTime.Components 節點是一個「多重傳回」節點,節點預覽反映出其鍵值對與節點輸出埠的順序相同,這也是根據節點定義上的 MultiReturnAttribute 指定輸出的順序。
另請注意,與使用者介面節點不同,Code Block 的預覽並未排序,因為 Code Block 節點沒有輸出埠資訊 (以多重傳回屬性的形式):
指令式區塊中的變數對指令式範圍是局部變數
將清單與字典分開
外部關聯式範圍中的 x 值和 y 值分別仍是 1 和 2
a[“foo”] = 1;
b = {“foo” : 1, “bar” : 2, “baz” : 3};
a[“bar”] = 2;
a = {}; // 建立一個空字典
a[“baz”] = 3;
字典編製索引
鍵編製索引
編製索引語法維持不變
b = a[“bar”];
b = a[“bar”];
字典鍵
任何鍵類型都是合法的
只有字串鍵是合法的
a = {};
a = {“false” : 23, “point” : 12};
a[false] = 23;
a[point] = 12;
清單初始化
a = {1, 2, 3};
a = [1, 2, 3];
空清單
a = {};
a = [];
字典初始化
可以動態附加到同一個字典:
只能建立新字典:
a = {};
a = {“foo” : 1, “bar” : 2};



























pnt = Autodesk.Point.ByCoordinates;
lne = Autodesk.Line.ByStartPointEndPoint;
[Imperative]
{
x = 1;
start = pnt(0,0,0);
end = pnt(x,x,x);
line = lne(start,end);
return = line;
};BoundingBox BoundingBox.ByGeometry(geometry: Geometry) {...}
BoundingBox BoundingBox.ByGeometry(geometry: Geometry[]) {...}BoundingBox.ByGeometry(geometry<1>);1)
foo(a: int[], b: int); ✓
foo(a: int, b: int); ✕2)
foo(x: int, y: int); ✓
foo(x: int[], y: int[]); ✕x = [arc, line];
y = x.CenterPoint; // y = [centerpoint, null] ✓x = [line, arc];
y = x.CenterPoint; // y = null ✕surface<1>.PointAtParameter(u<1>, v<2>);Surface.PointAtParameter(surface<1>, u<2>, v<3>);x = 1..5;
y = 0;
z = 0;
p = Point.ByCoordinates(x<1>, y<2>, z<3>); // cross-lacingSurface.PointAtParameter(surface<1>, u<2>, v<3>); Surface.PointAtParameter(surface<1>, u<2>, v<3>);1. a = 1;
2. b = a * 2;
3. a = 2;a = 1;
b = a;
a = b;a = 1;
b = 1;
b = b + a + 2; // b = 4
a = 4; // b = 10 or b = 7?1: def foo(x: A) { x.prop = ...; return x; }
2: a = A.A();
3: p = a.prop;
4: a1 = foo(a); // will p update?1: def foo(v: double) { return v * 2; }// define “foo”
2: x = foo(5); // first definition of “foo” called
3: def foo(v: int) { return v * 3; } // overload of “foo” defined, will x update?1: x = 1;
2: y = 2;
3: [Imperative] {
4: x = 2 * y;
5: }
6: y = 3;1: x = 1;
2: y = x * 2;
3: [Imperative] {
4: x = 3;
5: }x = 1;
y = x * 2;
i = [Imperative] {
x = 3;
return x;
}1: x = 1;
2: y = 2;
3: [Imperative] {
4: x = 2 * y;
5: }
6: y = 3; // x = 1, y = 3Given:
a = {“foo” : 1, “bar” : 2};
1.x:
b = a[{“foo”, {“bar”}}];
returns {1, 2}
2.0:
b = a[[“foo”, [“bar”]]];
returns [1, [2]];dict = {<key> : <value>, …}; dict = {["foo", "bar"] : "baz" };