Multiple filters

Multiple filters

atis.sed
Advocate Advocate
1,265 Views
10 Replies
Message 1 of 11

Multiple filters

atis.sed
Advocate
Advocate

Hi, 

is it possible to apply multiple filters to filter out elements without loops?

For example I use ElementMulticlassFilter to filter all Walls, Floors, Ceiling and Roofs, next I would also like to filter out just Basic Walls by WallKind.Basic from that collection of Walls, Floors, Ceiling and Roofs, so that in the end I have BasicWalls, Floors, Ceilings and Roofs.

 

public ICollection<Element> FindEL(Document doc)
{            
IList<Type> types = new List<Type>(); 
types.Add(typeof(FloorType));
types.Add(typeof(RoofType));
types.Add(typeof(WallType));
types.Add(typeof(CeilingType));
 ElementMulticlassFilter filter = new ElementMulticlassFilter(types);

// Apply the filter to the elements in the active document
FilteredElementCollector collector = new FilteredElementCollector(doc);
ICollection<Element> allFamilies = collector.WherePasses(filter).ToElements();
                
return allFamilies;
}

 

 

0 Likes
Accepted solutions (2)
1,266 Views
10 Replies
Replies (10)
Message 2 of 11

architect.bim
Collaborator
Collaborator
Accepted solution

Hi there!

Yes, It is possible. To combine several filters use ElementLogicalFilter (AND, OR).221101_0934_001.jpg


Maxim Stepannikov | Architect, BIM Manager, Instructor
Message 3 of 11

atis.sed
Advocate
Advocate

@architect.bim oh great, thank you!! 

I was trying that ElementLogicalFilter, but couldn't figure out how to create Filter for WallKind.Basic..  

It is not ElementClassFilter or ElementCategoryFilter and there is no ElementTypeFilter / ElementKindFilter.

Message 4 of 11

Yien_Chao
Advisor
Advisor

nvm

0 Likes
Message 5 of 11

atis.sed
Advocate
Advocate

Basically what I want to achieve is this:

And I have found two ways, by 1. Concat lists or by 2. foreach Removing all non Basic walls.

I am not sure which one is faster, I would guess by list concatenation.

public IEnumerable<Element> FindEL(Document doc)
{
                
IList<Type> types = new List<Type>();
Type walls = typeof(WallType);
                
types.Add(typeof(FloorType));
types.Add(typeof(RoofType));
types.Add(typeof(CeilingType));

FilteredElementCollector FRCcollector = new FilteredElementCollector(doc);
FilteredElementCollector WCollector = new FilteredElementCollector(doc);

ElementMulticlassFilter TypeFilter = new ElementMulticlassFilter(types);
                
IList<Element> OtherTypes = FRCcollector.WherePasses(TypeFilter).ToList();

IEnumerable<WallType> BasicWalls = WCollector
                     .OfClass(walls)
                     .Cast<WallType>()
                     .Where(w => w.Kind == WallKind.Basic);


IEnumerable<Element> combined = BasicWalls.Concat(OtherTypes);


                /*  foreach (Element e in allTypes.ToList())
                  {
                      if (e.GetType() == typeof(WallType))
                      {
                          WallType w = e as WallType;
                          if (w.Kind != WallKind.Basic)
                          {
                              allTypes.Remove(e);
                          }
                      }
                  }*/

                return combined;
            }
0 Likes
Message 6 of 11

RPTHOMAS108
Mentor
Mentor

Take wall category out of your multicategory filter and use a logical or filter (wall as the other option).

 

So you have (Floor/Roof/Ceiling) or (and(Wall, Basic Wall).

 

If you first filter for ElementIds of WallType of 'Basic Wall' then you can use those in ElementIdSetFilter i.e.

 

(Floor/Roof/Ceiling) or (ElementIdSetFilter).

 

There are many ways but since you are dealing with Wall types which are few then there is probably a negligible difference.

 

Unfortunately, WallKind isn't a parameter.

Message 7 of 11

atis.sed
Advocate
Advocate

Thank you!

But what filter would you use for Wall, Basic Wall ?

0 Likes
Message 8 of 11

RPTHOMAS108
Mentor
Mentor

I think for that you'll have to use Linq since there is no specific filter for it and it isn't parameter so you can't use ElementParameterFilter. You are dealing with just a small number of wall types.

 

It is generally the case that you would want to separate out the categories of elements and not lump everything together in one set e.g. you may be filtering for type of FloorType but that is also going to cover some forms of structural foundation.

0 Likes
Message 9 of 11

atis.sed
Advocate
Advocate

Thank you for advices!

 

Unfortunately, this does not work:

FilteredElementCollector WCollector = new FilteredElementCollector(doc).OfClass(typeof(WallType)).Where(w => w.Kind == WallKind.Basic);

'Element' does not contain definition  for 'Kind'

 

Also this throws an error:

WallKind WK = WallKind.Basic;
Type WKid = WK.GetType();
ElementClassFilter WTypeFilter2 = new ElementClassFilter(WKid);

After many many tries I am left with combining two lists from two collectors or using foreach loop on all element list and removing non-Basic walls. 

0 Likes
Message 10 of 11

RPTHOMAS108
Mentor
Mentor
Accepted solution

You need to cast the Element to WallType.

 

However I don't see that there is much disadvantage to combining the lists in your case to be honest.

 

public static Result EP_221102a()
        {

            FilteredElementCollector FEC0 = new FilteredElementCollector(IntDoc);
            ElementClassFilter ECF = new ElementClassFilter(typeof(WallType));
            List<ElementId> WL = FEC0.WherePasses(ECF).OfType<WallType>()
                                        .Where(q => q.Kind == WallKind.Basic)
                                        .Select(k => k.Id).ToList();
           
            ElementMulticlassFilter ETF = new ElementMulticlassFilter(new List<Type> { typeof(FloorType), 
                                                                                       typeof(RoofType),
                                                                                       typeof(CeilingType)});

            ElementIdSetFilter EIDF = new ElementIdSetFilter(WL);
            LogicalOrFilter LorF = new LogicalOrFilter(ETF, EIDF);
            FilteredElementCollector FEC = new FilteredElementCollector(IntDoc);

            IList<Element> Res = FEC.WherePasses(LorF).ToElements();

            for (int I = 0; I < Res.Count; I++)
            {
                Debug.WriteLine(Res[I].Name);
            }


            return Result.Succeeded;
        }
Message 11 of 11

atis.sed
Advocate
Advocate
Thank you, sir!
0 Likes