Chia sẽ BCDD lên mạng xã hội nhé !

1. Bộ khởi dựng (constructor)

Nhìn vào tài liệu RevitAPI chúng ta thấy, FilteredElementCollector rõ ràng là một class nằm trong namespace: Autodesk.Revit.DB. Về cơ bản thì Class này dùng để tìm kiếm, lọc, duyệt và trả về một danh sách (list) các đối tượng để sử dụng cho các mục đích sau đó.

Class này có đến ba bộ khởi dựng (constructors) hay nói cách khác là class này có thể được sử dụng bởi ba cách. Nhưng thông thường chúng ta hay sử dụng constructor đầu tiên (chỉ cần cung cấp cho nó cái document hiện hành là khởi tạo được). Constructor thứ hai dùng để tìm kiếm và lọc những đối tượng nhìn thấy được (tức không bị ẩn đi) trong một view. Constructor thứ ba dùng để tìm kiếm và lọc một tập đối tượng nhất định. Bộ khởi dựng thứ ba này cũng cần một document và một ICollection id của các đối tượng.

Dưới đây là đoạn code kinh điển về FilteredElementCollector

#Import thu vien
import clr
clr.AddReference("RevitServices") 
import RevitServices 
from RevitServices.Persistence import DocumentManager 
clr.AddReference("RevitAPI") 
from Autodesk.Revit.DB import FilteredElementCollector, Level

doc = DocumentManager.Instance.CurrentDBDocument

#FilteredElementCollector
elementCollector = FilteredElementCollector(doc).OfClass(Level).WhereElementIsNotElementType().ToElements()

OUT = elementCollector

Nó tương đương với việc dùng 2 nodes Element Types với All Elements of Type trong Dynamo để lấy ra các levels.

2. Phương thức (Method)

FilteredElementCollector có khá nhiều phương thức khác nhau, tuy nhiên trong phạm vi bài viết này BCDD sẽ chỉ trình bày các phương thức được sử dụng phổ biến nhất.

OfCategory(): dùng để lọc một category nhất định trong Revit như walls, floors, columns…

FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)

OfClass(): dùng để lọc những class trong Revit như ViewDrafting, View, Family…

FilteredElementCollector(doc).OfClass(Family)

ToElementIds(): phương thức này là đầu ra một danh sách id của các đối tượng lọc được

FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).ToElementIds()
FilteredElementCollector(doc).OfClass(Family).ToElementIds()

ToElements(): khá giống với method ToElementIds() ở trên, nhưng đầu ra là một list những đối tượng thật chứ không phải là id.

FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).ToElements()
FilteredElementCollector(doc).OfClass(Family).ToElements()

WhereElementIsElementType(): đầu ra chỉ nhận type elements như walls type.

WhereElementIsNotElementType(): ngược lại với method ở trên, đầu ra chỉ nhận instances mà không nhận type.

WherePasses(): phương thức này cần có một bộ lọc (filter), sau đó lọc ra những đối tượng nào thỏa bộ lọc. Có lẻ đây là phương thức phức tạp nhất và BCDD sẽ phân tích sâu hơn ở các ví dụ bên dưới.

3. Thuộc tính (Property)

FilteredElementCollector class chỉ có một thuộc tính là IsValidObject nhưng mà hầu như rất ít khi được sử dụng.

4. Các kiểu filters

Tra RevitAPI chúng ta thấy có 3 loại filters bao gồm:

  • ElementQuickFilter
  • ElementSlowFilter 
  • ElementLogicalFilter

Khúc này hơi phức tạp để giải thích cặn kẻ mà tự nhiên admin lười quá nên làm biếng viết khúc này. Mong đọc giả thông cảm và tiếp tục đọc phần bên dưới vì vẫn còn nhiều điều hấp dẫn ở phía sau.

4. FilteredElementCollector: OfClass().OfCategory()

import clr
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager 
clr.AddReference("RevitAPI") 
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory, FamilyInstance

doc = DocumentManager.Instance.CurrentDBDocument

builtInCollector = FilteredElementCollector(doc, doc.ActiveView.Id).OfClass(FamilyInstance).OfCategory(BuiltInCategory.OST_StructuralFraming).WhereElementIsNotElementType().ToElements()

OUT = builtInCollector

5. FilteredElementCollector: Dùng filter

import clr 
clr.AddReference("RevitServices") 
from RevitServices.Persistence import DocumentManager 
clr.AddReference("RevitAPI") 
import Autodesk
from Autodesk.Revit.DB import FilteredElementCollector, Wall, ElementId, ElementLevelFilter

doc = DocumentManager.Instance.CurrentDBDocument

filter = ElementLevelFilter(Autodesk.Revit.DB.ElementId(IN[0].Id))

elementAtLevelCollector = FilteredElementCollector(doc).WherePasses(filter).WhereElementIsNotElementType().ToElements()

OUT = elementAtLevelCollector

Lưu ý: Nếu lấy id của level theo kiểu IN[0].Id như ảnh phía dưới thì có lỗi sau TypeError: expected ElementId, got int

6. FilteredElementCollector: ByParameter

Lọc các đối tượng có giá trị tham số thỏa một quy tắc lọc. Mọi chuyện bắt đầu bằng việc tra class ElementParameterFilter trong RevitAPI. Chúng ta thấy có bốn bộ khởi dựng, ở bài viết này BCDD dùng bộ khởi dựng đầu tiên. Vậy tiếp theo chúng ta cần một FilterRule

Vì là filter paramter nên chúng ta cần chú ý đến kiểu dữ liệu trong parameter là gì? là Integer, String hay Double…tương ứng với các kiểu dữ liệu chúng ta có các class rules tương ứng như: FilterIntegerRule, FilterStringRule, FilterDoubleRule…

filter = ElementParameterFilter(FilterRule)

Trong bài viết này BCDD sẽ lọc ra những vách có thickness dày hơn 200mm nên sẽ can thiệp vào parameter Width của wall có kiểu dữ liệu là Double

Tiếp tục tra class FilterDoubleRule trong RevitAPI thì thấy có một bộ khởi dựng để dựng nên class này. Xem cú pháp của nó trong C# thì thấy nó cần bốn tham số đầu vào gồm: 

  • valueProvider
  • evaluator
  • ruleValue (đơn vị hệ imperial ở python Dynamo)
  • epsilon (dung sai)

Vì kiểu dữ liệu của ruleValue và epsilon là Double nên chúng ta chỉ cần cung cấp kiểu dữ liệu Double cho hai tham số trên. Còn lại chúng ta cần quan tâm đến tham số:

  • valueProvider có kiểu dữ liệu trả về là FilterableValueProvider 
  • evaluator có kiểu dữ liệu trả về là FilterNumericRuleEvaluator

valueProvider: Tra class FilterableValueProvider trong RevitAPI thì thấy class ParameterValueProvider có kế thừa từ class này 

Lại tiếp tục click vào class này để tra thì phát hiện ra một bộ khởi dựng, click vào bộ khởi dựng thì thấy cú pháp C# như hình bên dưới. Từ đó, chúng ta thấy bộ khởi dựng này cần một tham số là parameter có kiểu dữ liệu là ElementId nên cần cung cấp parameter id cho bộ khởi dựng này. Mà cụ thể là id của parameter Width của wall như đã nói ở trên.

Tiếp tục click vào ElementId ở RevitAPI thì thấy nó có ba bộ khởi dựng như hình.

Chúng ta sẽ cần cái thứ 3 vì chúng ta cần id của parameter Width nên chúng ta tiếp tục click vào bộ khởi dựng này thì thấy kiểu dữ liệu là BuiltInParameter. 

Click tiếp vào nó thì thấy đây là một Enumeration. Sau đó kiếm tên builtin của parameter Width của Wall

Sau khi đã có parameter rồi thì ta lấy được id và cuối cùng là có valueProvider

param = BuiltInParameter.WALL_ATTR_WIDTH_PARAM
valueProvider = ParameterValueProvider(ElementId(param))

evaluator: Tra class FilterNumericRuleEvaluator trong RevitAPI thì thấy class FilterNumericGreater có thể sử dụng được, vì đang kiếm những wall dày hơn 200mm

Tra tiếp thì thấy bộ khởi dựng của class FilterNumericGreater có cú pháp trong C# như hình bên dưới (không có paramter nào bên trong).

evaluator = FilterNumericGreater()

Sau khi đã có valueProvider và evaluator chúng ta tiến hành tạo rule, có rule rồi thì filter, có filter rồi thì dùng class huyền thoại FilteredElementCollector

rule = FilterDoubleRule(valueProvider,evaluator , 200.00*0.00328084, 0.0001)
filter = ElementParameterFilter(rule)

wallCollector = FilteredElementCollector(doc).WherePasses(filter).WhereElementIsNotElementType().ToElements()

OUT = wallCollector 

Cuối cùng chúng ta Import thư viện để chạy code ở trên.

import clr 
clr.AddReference("RevitServices") 
from RevitServices.Persistence import DocumentManager 
clr.AddReference("RevitAPI") 
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument

Code nhìn chung sẽ như sau:

Truoc tien la import thu vien

#provider 
param = BuiltInParameter.tra builtin parameter enum
provider = ParameterValueProvider(ElementId(param))

#evaulators cho kieu du lieu so
evaluatorEq = FilterNumericEquals()
evaluatorGr = FilterNumericGreater()
evaluatorGoEq = FilterNumericGreaterOrEqual()
evaluatorLess = FilterNumericLess()
evaluatorLoEq = FilterNumericLessOrEqual()

#evaulators cho kieu du lieu string
evalBegins = FilterStringBeginsWith()
evalCon = FilterStringContains()
evalEnds = FilterStringEndsWith()
evalEq = FilterStringEquals()
evalGreat = FilterStringGreater()
evalGoEq = FilterStringGreaterOrEqual()
evalLess = FilterStringLess()
evalLoEq = FilterStringLessOrEqual()

#rules
rule = FilterDoubleRule(provider, evaluator, ruleValue, epsilon)
rule = FilterStringRule(provider, evaluator, test, caseSensitive)

#tao filter
filter = ElementParameterFilter(rule)

#collector
Collector = FilteredElementCollector(doc).WherePasses(filter).WhereElementIsNotElementType ().ToElements()

Nếu thấy bài viết này hữu ích, hãy cân nhắc việc ủng hộ BCDD tại đây

Bài viết do admin 1 Nghia Nguyen và cộng sự BCDD biên soạn.

Tài liệu tham khảo (reference source): Amoursol/dynamoPython