EaBIM一直以来积极响应国家“十二五”推进建筑业信息化的号召,对建筑领域的信息技术开展深入技术交流和探讨!致力于打造“BIM-建筑师-生态技术”三位一体综合资源交流共享平台,希望为BIM与可持续设计理念及技术的普及做出微小的贡献!!!

EaBIM

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
查看: 890|回复: 0
打印 上一主题 下一主题

ElementQuickFilter-快速过滤器

[复制链接]

1514

主题

7465

帖子

1万

积分

admin

Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10

积分
12404

社区QQ达人

跳转到指定楼层
楼主
发表于 2014-1-9 12:29:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式



In Revit API 2011, a new FilteredElementCollector mechanism is introduced, all previous filters are replaced, and some brand new ones are added. In addition, the filters are splitted into logical filters (ElementLogicalFilter), quick filters (ElementQuickFilter) and slow filters (ElementSlowFilter). There are two logical filters as before (AND and OR), a dozen of quick filters and a bunch of slow filters.

The logical filters are not new and they seem to be renamed from those old versions. In fact, in the new FilteredElementCollector mechanism, they become redundant as the collector has two shortcut methods, UnionWith() and IntersectWith(), and they can do the same work, more nicely and meaningfully, that the two logical filters are supposed to do. Because of this, we will skip them in this article; instead, we will talk about the two methods a bit and use them in some example code. The quick and slow filter split is for performance consideration as stated that the fommer is quicker and the latter is slower.
Quick filters include:
• BoundingBoxContainsPointFilter
• BoundingBoxIntersectsFilter
• BoundingBoxIsInsideFilter
• ElementCategoryFilter
• ElementClassFilter
• ElementDesignOptionFilter
• ElementIsCurveDrivenFilter
• ElementIsElementTypeFilter
• ElementOwnerViewFilter
• ElementStructuralTypeFilter
• ExclusionFilter
• FamilySymbolFilter
They are not exclusive to each other. In some cases, for example, we can use the ElementCategoryFilter or the ElementClassFilter to achieve the same goal. We will demonstrate such a case a bit later with code.
In terms of quick filters and slow filters, this is also true (maybe more true). For example, the slow RoomFilter seems the only way to filter out rooms, but actually we can use the OST_Rooms category filter (plus another filter like excluding element types, maybe) to get to the same point. We are not sure though which means is really quicker, but it is stated again and again that the quick filters should be considered at the first place.
Anyway, the element filtering performance is not our concern in this article. Let’s focus on some aspects of the quick filters now. Assuming we need to fufill a task like filtering out all roofs, ceilings, floors and stairs from a Revit model, which filters should we use and what filter arguments are good and necessary?
It is not arguable that the ElementCategoryFilter or the ElementClassFilter or both should be applied, but the question is how. Here are some more clues that can help us make such a decision: there are Floor, CeilingAndFloor, and RoofBase classes in the API, but there is no Ceiling or Stair class; there are OST_Ceilings, OST_Roofs, OST_Floors, and OST_Stairs values and a lot of more specific ones in the BuiltInCategory enumerator.
If we prefer the ElementClassFilter, we can filter out the roofs, ceilings and floors using the filter with the CeilingAndFloor and the RoofBase classes as arguments respectively and unit them together, then we filter out stairs using the  ElementCategoryFilter with the OST_Stairs BuiltInCategory argument and again unit them together. One thing needs to bear in mind is do not forget to exclude all element types (symbols) from the final FilteredElementCollector.

Here is the example code to demonstrate this approach:
        public static List<Element> FindAllRoofsCeilingsFloorsAndStairs_Approach1(RvtDocument doc)
        {
            List<Element> list = new List<Element>();
            FilteredElementCollector finalCollector = new FilteredElementCollector(doc);
            
            ElementClassFilter filter1 = new ElementClassFilter(typeof(CeilingAndFloor), false);
            finalCollector.WherePasses(filter1);
            ElementClassFilter filter2 = new ElementClassFilter(typeof(RoofBase), false);
            finalCollector.UnionWith((new FilteredElementCollector(doc)).WherePasses(filter2));
            ElementCategoryFilter filter3 = new ElementCategoryFilter(BuiltInCategory.OST_Stairs, false);
            finalCollector.UnionWith((new FilteredElementCollector(doc)).WherePasses(filter3));
            ElementIsElementTypeFilter filter4 = new ElementIsElementTypeFilter(true);
            finalCollector.IntersectWith((new FilteredElementCollector(doc)).WherePasses(filter4));
            list = finalCollector.ToList<Element>();
            return list;
        }
If we prefer the ElementCategoryFilter or it has similar performance as the ElementClassFilter, we can write some other code to do the same thing:

        public static List<Element> FindAllRoofsCeilingsFloorsAndStairs_Approach2(RvtDocument doc)
        {
            List<Element> list = new List<Element>();
            FilteredElementCollector finalCollector = new FilteredElementCollector(doc);
            ElementCategoryFilter filter1 = new ElementCategoryFilter(BuiltInCategory.OST_Ceilings, false);
            finalCollector.WherePasses(filter1);
            ElementCategoryFilter filter2 = new ElementCategoryFilter(BuiltInCategory.OST_Roofs, false);
            finalCollector.UnionWith((new FilteredElementCollector(doc)).WherePasses(filter2));
            ElementCategoryFilter filter3 = new ElementCategoryFilter(BuiltInCategory.OST_Floors, false);
            finalCollector.UnionWith((new FilteredElementCollector(doc)).WherePasses(filter3));
            ElementCategoryFilter filter4 = new ElementCategoryFilter(BuiltInCategory.OST_Stairs, false);
            finalCollector.UnionWith((new FilteredElementCollector(doc)).WherePasses(filter4));
            ElementIsElementTypeFilter filter5 = new ElementIsElementTypeFilter(true);
            finalCollector.IntersectWith((new FilteredElementCollector(doc)).WherePasses(filter5));
            list = finalCollector.ToList<Element>();
            return list;
        }
Personally, I like this approach as the code is more readable and its logic is clearer though one more filter is needed in this particular case. And please do not forget, more importantly, the Revit API does not provide classes for all categories!

This leads to another question: does it indicate that the ElementClassFilter is also redundant if it does not have significant performance gain than the ElementCategoryFilter? It is not something we will or can answer in this post.
Supposing we have another task, retrieving all elements from a document, what should we do?

It needs two filters, one ElementIsElementTypeFilter and one inverted ElementIsElementTypeFilter, as follows:
        public static List<Element> FindAllElements(RvtDocument doc)
        {
            List<Element> list = new List<Element>();
            FilteredElementCollector finalCollector = new FilteredElementCollector(doc);
            ElementIsElementTypeFilter filter1 = new ElementIsElementTypeFilter(false);
            finalCollector.WherePasses(filter1);
            ElementIsElementTypeFilter filter2 = new ElementIsElementTypeFilter(true);
            finalCollector.UnionWith((new FilteredElementCollector(doc)).WherePasses(filter2));
            list = finalCollector.ToList<Element>();
            return list;
        }

It is apparently cumbersome to do the simplest task but that is something we have to sacrifice for the performance gain.

Here is some code to call and test these element finders:
                List<Element> elements = ElementFinder.FindAllRoofsCeilingsFloorsAndStairs_Approach1(CachedDoc);
                MessageBox.Show(string.Format("There are {0} roofs, ceilings, floors and stairs in the model.", elements.Count.ToString()));
                elements = ElementFinder.FindAllRoofsCeilingsFloorsAndStairs_Approach2(CachedDoc);
                MessageBox.Show(string.Format("There are {0} roofs, ceilings, floors and stairs in the model.", elements.Count.ToString()));
                elements = ElementFinder.FindAllElements(CachedDoc);
                MessageBox.Show(string.Format("There are totally {0} elements in the model.", elements.Count.ToString()));
So, most of times, we have to guess out which filters should be used and what filter arguments should be applied, and do a lot of experiments regarding these.

Fortunately, the Element Finder of the RevitAddinWizardcan help you generate similar code and actually much more complex code for any combinations of the filters and their arguments in a moment.

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 转播转播 分享分享 分享淘帖 支持支持 反对反对
工作时间:工作日的9:00-12:00/13:30-18:00,节假日不在线,请勿留言
*滑块验证:
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|EaBIM网 ( 苏ICP备2020058923号-1  苏公网安备32011502011255号

GMT+8, 2024-11-16 18:44

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表