🎁

PythonとC#で始めるRevit API

2021/03/13に公開

作成したコードのGithubはこちらです

ISelectionFilterについて

例1 DB classのFamilyInstanceでフィルタリング

C#の場合

    public class ClassISelectionFilter : ISelectionFilter
    {
        public bool AllowElement(Element elem)
        {
            if (elem is FamilyInstance) return true;
            return false;
        }

        public bool AllowReference(Reference refer, XYZ pos)
        {
            return false;
        }
    }

Pythonの場合

class ClassISelectionFilter(UI.Selection.ISelectionFilter):
    def AllowElement(self, e):
        if isinstance(e, DB.FamilyInstance):
            return True
        else:
            return False

例2 Categoryの名前でフィルタリング

C#の場合

    public class CategoryISelectionFilterByName : ISelectionFilter
    {
        string catName = String.Empty;

        public CategoryISelectionFilterByName(String selectedCatName)
        {
            catName = selectedCatName;
        }

        public bool AllowElement(Element elem)
        {
            if (elem.Category.Name == catName ) return true;
            return false;
        }

        public bool AllowReference(Reference refer, XYZ pos)
        {
            return false;
        }
    }

Pythonの場合

class CategoryISelectionFilterByName(UI.Selection.ISelectionFilter):
    def __init__(self, bi_cat):
        self.bi_cat = bi_cat

    def AllowElement(self, e):
        if e.Category.Name == self.bi_cat:
            return True
        else:
            return False

例3 BuiltInCategoryでフィルタリング

    public class CategoryISelectionFilterByName : ISelectionFilter
    {
        string catName = String.Empty;

        public CategoryISelectionFilterByName(String selectedCatName)
        {
            catName = selectedCatName;
        }

        public bool AllowElement(Element elem)
        {
            if (elem.Category.Name == catName ) return true;
            return false;
        }

        public bool AllowReference(Reference refer, XYZ pos)
        {
            return false;
        }
    }

Pythonの場合

class CategoryISelectionFilterByBuiltInCategory(UI.Selection.ISelectionFilter):
    def __init__(self, bi_cat):
        self.bi_cat = bi_cat

    def AllowElement(self, e):
        if e.Category.Id.IntegerValue == int(self.bi_cat):
            return True
        else:
            return False

FilteredElementCollectorについて

特定のFamilyTypeをコレクトする

C#の場合

リスト内はFamilyInstance classであるため違うタイプとして利用するためにはキャストする必要があります。

List<FamilyInstance> selectedElements = new FilteredElementCollector(doc)
                .OfClass(typeof(FamilyInstance))
                .WhereElementIsNotElementType()
                .Where(e => e.GetTypeId() == sourceFI.GetTypeId())
                .Cast<FamilyInstance>()
                .ToList();

Pythonの場合

Revit Python Wrapper(rpw)を使用しています。rpwはpyRevitの標準機能としてついていますので、追加設定をする必要なく使用可能です。get_elements()によりDBクラスのElementではなく、rpwクラスのElementになります。どのようなことができるかはこちらをご参照ください。

from rpw import db
selected_elements = db.Collector(
        of_class="FamilyInstance",
        is_not_type = True,
        where=lambda x: x.GetTypeId() == source_fi.GetTypeId()).get_elements()

FamilyInstanceクラスのRoom Propertyについて

例 選択したRoomに所属するものだけ条件分岐する

C#の場合

    foreach (FamilyInstance fi in selectedElements)
    {
        if (fi.Room.Id == sourceRoom.Id)
        {
            do something
        }
        else
        {
            do other stuff
        }
    }

Pythonの場合

Pythonで使う場合にはPhaseを指定する必要があります。様々なPhaseの取得方法はあるかと思いますが、ここでは一例を紹介してます。

    def get_phase(phase_name):
        phases = doc.Phases
        for p in phases:
            if p.Name == phase_name:
                return p
    
    phase = get_phase(phase_name)
    

    for e in selected_elements:
        if e.Room[phase].Id == source_room.Id:
	    do something
        else:
	    do other stuff

Transactionについて

選択したElementのパラメータに値をセットする

C#の場合

Transaction tx = new Transaction(doc, "Selected Element by CSharp");
tx.Start();
((Element)fi).LookupParameter("Selected Comment").Set("Selected");
tx.Commit();

Pythonの場合

with db.Transaction("Selected Element by Python"):
    e.parameters['Selected Comment'].value = "Selected"

TaskDialogについて

取得結果の表示

C#の場合

    TaskDialog dialog = new TaskDialog("Selected Elements/Room");
    dialog.TitleAutoPrefix = false;
    dialog.MainInstruction = $"Room Name: {sourceRoom.Name} Room Number: {((SpatialElement)sourceRoom).Number}";
    dialog.MainContent = $"Family Name: {sourceFI.Name}\nType Name: {((FamilyInstance)sourceFI).Symbol.FamilyName}\nFamily Count: {selectedElementByRoom.Count}";
    dialog.Show();

Pythonの場合

from rpw import ui
ui.forms.Alert(
        "Family Name: {}\nType Name: {}\nFamily Count: {}".format(source_fi.Symbol.FamilyName, db.Element(source_fi).name, len(selected_element_by_room)), title="Selected Elements/Room", header="Room Name: {} Room Number: {}".format(db.Room(source_room).name, source_room.Number))

Selection.SetElementIdsについて

List[]の使い方

C#の場合

List<ElementId> selectedElementByRoom = new List<ElementId>();

foreach (FamilyInstance fi in selectedElements)
{
    selectedElementByRoom.Add(fi.Id);
}

uidoc.Selection.SetElementIds(selectedElementByRoom);

Pythonの場合

from System.Collections.Generic import List

selected_element_by_room = []

for e in selected_elements:
    selected_element_by_room.append(e)

uidoc.Selection.SetElementIds(List[DB.ElementId](e.Id for e in selected_element_by_room))

参考

作成したコード

C#の場合

#region Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
#endregion

namespace Selector.pushbutton
{
    [Transaction(TransactionMode.Manual)]
    public class Command : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Application app = uiapp.Application;
            Document doc = uidoc.Document;

            List<ElementId> selectedElementByRoom = new List<ElementId>();

            ISelectionFilter classFilter = new ClassISelectionFilter();
            Reference familyInstanceReference = uidoc.Selection.PickObject(ObjectType.Element, classFilter, "Select FamilyInstance");

            ISelectionFilter catFilterByName = new CategoryISelectionFilterByName("Rooms");
            Reference roomReference = uidoc.Selection.PickObject(ObjectType.Element, catFilterByName, "Select Room");
            
            ISelectionFilter catFilterByBuiltInCategory = new CategoryISelectionFilterByBuiltInCategory(BuiltInCategory.OST_Rooms);
            // Reference roomReference = uidoc.Selection.PickObject(ObjectType.Element, catFilterByBuiltInCategory, "Select Room");

            Element sourceFI = doc.GetElement(familyInstanceReference.ElementId);
            Element sourceRoom = doc.GetElement(roomReference.ElementId);

            List<FamilyInstance> selectedElements = new FilteredElementCollector(doc)
                .OfClass(typeof(FamilyInstance))
                .WhereElementIsNotElementType()
                .Where(e => e.GetTypeId() == sourceFI.GetTypeId())
                .Cast<FamilyInstance>()
                .ToList();

            View view = uidoc.ActiveView;

            Transaction tx = new Transaction(doc, "Selected Element by CSharp");
            tx.Start();
            foreach (FamilyInstance fi in selectedElements)
            {
                if (fi.Room.Id == sourceRoom.Id)
                {
                    selectedElementByRoom.Add(fi.Id);
                    ((Element)fi).LookupParameter("Selected Comment").Set("Selected");
                }
                else
                {
                    ((Element)fi).LookupParameter("Selected Comment").Set("");
                }
            }
            tx.Commit();

            TaskDialog dialog = new TaskDialog("Selected Elements/Room");
            dialog.TitleAutoPrefix = false;
            dialog.MainInstruction = $"Room Name: {sourceRoom.Name} Room Number: {((SpatialElement)sourceRoom).Number}";
            dialog.MainContent = $"Family Name: {sourceFI.Name}\nType Name: {((FamilyInstance)sourceFI).Symbol.FamilyName}\nFamily Count: {selectedElementByRoom.Count}";
            dialog.Show();


            uidoc.Selection.SetElementIds(selectedElementByRoom);
            return Result.Succeeded;
        }
    }

    public class ClassISelectionFilter : ISelectionFilter
    {
        public bool AllowElement(Element elem)
        {
            if (elem is FamilyInstance) return true;
            return false;
        }

        public bool AllowReference(Reference refer, XYZ pos)
        {
            return false;
        }
    }

    public class CategoryISelectionFilterByName : ISelectionFilter
    {
        string catName = String.Empty;

        public CategoryISelectionFilterByName(String selectedCatName)
        {
            catName = selectedCatName;
        }

        public bool AllowElement(Element elem)
        {
            if (elem.Category.Name == catName ) return true;
            return false;
        }

        public bool AllowReference(Reference refer, XYZ pos)
        {
            return false;
        }
    }

    public class CategoryISelectionFilterByBuiltInCategory : ISelectionFilter
    {
        BuiltInCategory BIC = BuiltInCategory.INVALID;

        public CategoryISelectionFilterByBuiltInCategory(BuiltInCategory bic)
        {
            BIC = bic;
        }

        public bool AllowElement(Element elem)
        {
            if (((BuiltInCategory)elem.Category.Id.IntegerValue) == BIC) return true;
            return false;
        }

        public bool AllowReference(Reference refer, XYZ pos)
        {
            return false;
        }
    }
}

Pythonの場合

# -*- coding: utf-8 -*-
from Autodesk.Revit import DB, UI
from rpw import db, ui
from System.Collections.Generic import List

uiapp = __revit__ # noqa F821
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
doc = uidoc.Document


class ClassISelectionFilter(UI.Selection.ISelectionFilter):
    def AllowElement(self, e):
        if isinstance(e, DB.FamilyInstance):
            return True
        else:
            return False

class CategoryISelectionFilterByName(UI.Selection.ISelectionFilter):
    def __init__(self, bi_cat):
        self.bi_cat = bi_cat

    def AllowElement(self, e):
        if e.Category.Name == self.bi_cat:
            return True
        else:
            return False

class CategoryISelectionFilterByBuiltInCategory(UI.Selection.ISelectionFilter):
    def __init__(self, bi_cat):
        self.bi_cat = bi_cat

    def AllowElement(self, e):
        if e.Category.Id.IntegerValue == int(self.bi_cat):
            return True
        else:
            return False


def main():

    selected_element_by_room = []

    family_instance_reference = uidoc.Selection.PickObject(
        UI.Selection.ObjectType.Element,
        ClassISelectionFilter(),
        "Select FamilyInstance")

    room_reference = uidoc.Selection.PickObject(
        UI.Selection.ObjectType.Element,
        CategoryISelectionFilterByName("Rooms"),
        "Select Room")

    """
    room_reference = uidoc.Selection.PickObject(
        UI.Selection.ObjectType.Element,
        CategoryISelectionFilterByBuiltInCategory(
            DB.BuiltInCategory.OST_Rooms),
        "Select Room")
    """

    source_fi = doc.GetElement(family_instance_reference.ElementId)
    source_room = doc.GetElement(room_reference.ElementId)
    # print(source_fi)

    selected_elements = db.Collector(
        of_class="FamilyInstance",
        is_not_type = True,
        where=lambda x: x.GetTypeId() == source_fi.GetTypeId()).get_elements()

    view = uidoc.ActiveView
    phase_name = view.get_Parameter(DB.BuiltInParameter.VIEW_PHASE).AsValueString()

    phase = get_phase(phase_name)

    with db.Transaction("Selected Element by Python"):
        for e in selected_elements:
            if e.Room[phase].Id == source_room.Id:
                selected_element_by_room.append(e)
                e.parameters['Selected Comment'].value = "Selected"
            else:
                e.parameters['Selected Comment'].value = ""

    ui.forms.Alert(
        "Family Name: {}\nType Name: {}\nFamily Count: {}".format(source_fi.Symbol.FamilyName, db.Element(source_fi).name, len(selected_element_by_room)), title="Selected Elements/Room", header="Room Name: {} Room Number: {}".format(db.Room(source_room).name, source_room.Number))

    uidoc.Selection.SetElementIds(List[DB.ElementId](e.Id for e in selected_element_by_room))

def get_phase(phase_name):
    phases = doc.Phases
    for p in phases:
        if p.Name == phase_name:
            return p

if __name__ == "__main__":
    main()

Discussion