We talked about all kinds of element parameter filters, rules and evaluators and demonstrated their use with sample code in both C# and VB.NET in early posts. We also talked a little bit about their limitations. In this article, let us look at a relatively complex sample case.
Say, we want to find all walls with length more than or equal to 5 feet but less than 10 feet, OR more than or equal to 15 feet but less than 20 feet, OR more than or equal to 25 but less than 30 feet, OR more than or equal to 35 but less than 40 feet, OR more than or equal to 45 but less than 50 feet, …, following the same pattern, what should we do with the existing element parameter filter rules and evaluators?
I can think of the following way:
public static ICollection<ElementId> FindWallsUsingElementParameterFilter(RvtDocument doc)
{
ParameterValueProvider provider = new ParameterValueProvider(new ElementId((int)BuiltInParameter.CURVE_ELEM_LENGTH));
FilteredElementCollector wallCollector = new FilteredElementCollector(doc).OfClass(typeof(Autodesk.Revit.DB.Wall));
FilterDoubleRule rule1 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 5, 10e-8);
ElementParameterFilter filter1 = new ElementParameterFilter(rule1);
FilterDoubleRule rule2 = new FilterDoubleRule(provider, new FilterNumericLess(), 10, 10e-8);
ElementParameterFilter filter2 = new ElementParameterFilter(rule2);
LogicalAndFilter andfiler1 = new LogicalAndFilter(filter1, filter2);
FilterDoubleRule rule3 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 15, 10e-8);
ElementParameterFilter filter3 = new ElementParameterFilter(rule3);
FilterDoubleRule rule4 = new FilterDoubleRule(provider, new FilterNumericLess(), 20, 10e-8);
ElementParameterFilter filter4 = new ElementParameterFilter(rule4);
LogicalAndFilter andfilter2 = new LogicalAndFilter(filter3, filter4);
FilterDoubleRule rule5 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 25, 10e-8);
ElementParameterFilter filter5 = new ElementParameterFilter(rule5);
FilterDoubleRule rule6 = new FilterDoubleRule(provider, new FilterNumericLess(), 30, 10e-8);
ElementParameterFilter filter6 = new ElementParameterFilter(rule6);
LogicalAndFilter andfilter3 = new LogicalAndFilter(filter5, filter6);
FilterDoubleRule rule7 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 35, 10e-8);
ElementParameterFilter filter7 = new ElementParameterFilter(rule7);
FilterDoubleRule rule8 = new FilterDoubleRule(provider, new FilterNumericLess(), 40, 10e-8);
ElementParameterFilter filter8 = new ElementParameterFilter(rule8);
LogicalAndFilter andfilter4 = new LogicalAndFilter(filter7, filter8);
FilterDoubleRule rule9 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 45, 10e-8);
ElementParameterFilter filter9 = new ElementParameterFilter(rule9);
FilterDoubleRule rule10 = new FilterDoubleRule(provider, new FilterNumericLess(), 50, 10e-8);
ElementParameterFilter filter10 = new ElementParameterFilter(rule10);
LogicalAndFilter andfilter5 = new LogicalAndFilter(filter9, filter10);
FilterDoubleRule rule11 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 55, 10e-8);
ElementParameterFilter filter11 = new ElementParameterFilter(rule11);
FilterDoubleRule rule12 = new FilterDoubleRule(provider, new FilterNumericLess(), 60, 10e-8);
ElementParameterFilter filter12 = new ElementParameterFilter(rule12);
LogicalAndFilter andfilter6 = new LogicalAndFilter(filter11, filter12);
FilterDoubleRule rule13 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 65, 10e-8);
ElementParameterFilter filter13 = new ElementParameterFilter(rule13);
FilterDoubleRule rule14 = new FilterDoubleRule(provider, new FilterNumericLess(), 70, 10e-8);
ElementParameterFilter filter14 = new ElementParameterFilter(rule14);
LogicalAndFilter andfilter7 = new LogicalAndFilter(filter13, filter14);
FilterDoubleRule rule15 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 75, 10e-8);
ElementParameterFilter filter15 = new ElementParameterFilter(rule15);
FilterDoubleRule rule16 = new FilterDoubleRule(provider, new FilterNumericLess(), 80, 10e-8);
ElementParameterFilter filter16 = new ElementParameterFilter(rule16);
LogicalAndFilter andfilter8 = new LogicalAndFilter(filter15, filter16);
FilterDoubleRule rule17 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 85, 10e-8);
ElementParameterFilter filter17 = new ElementParameterFilter(rule17);
FilterDoubleRule rule18 = new FilterDoubleRule(provider, new FilterNumericLess(), 90, 10e-8);
ElementParameterFilter filter18 = new ElementParameterFilter(rule18);
LogicalAndFilter andfilter9 = new LogicalAndFilter(filter17, filter18);
FilterDoubleRule rule19 = new FilterDoubleRule(provider, new FilterNumericGreaterOrEqual(), 95, 10e-8);
ElementParameterFilter filter19 = new ElementParameterFilter(rule19);
FilterDoubleRule rule20 = new FilterDoubleRule(provider, new FilterNumericLess(), 100, 10e-8);
ElementParameterFilter filter20 = new ElementParameterFilter(rule20);
LogicalAndFilter andfilter10 = new LogicalAndFilter(filter19, filter20);
LogicalOrFilter finalOrFilter = new LogicalOrFilter(andfiler1, andfilter2);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter3);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter4);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter5);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter6);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter7);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter8);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter9);
finalOrFilter = new LogicalOrFilter(finalOrFilter, andfilter10);
return wallCollector.WherePasses(finalOrFilter).ToElementIds();
}
…
DateTime time = DateTime.Now;
ICollection<ElementId> wallsFound1 = FindWallsUsingElementParameterFilter(CachedDoc);
TimeSpan timespan = DateTime.Now - time;
MessageBox.Show(string.Format("Found {0} such walls in {1} seconds.", wallsFound1.Count, timespan.TotalSeconds), "Using ElementParameterFilter");
…
The test code will report the following for a test model:
As can be noticed, a lot of different filters, rules, and evaluators have to be used in this approach, but still it only covers a small portion of those walls of interest, e.g. which length are less than 100 feet. If we want to cover more, we have to add some more filters, rules, and evaluators, but it will never be possible to cover all cases in this way.
Ok, let us try our own way:
public static List<ElementId> FindWallsUsingOurOwnWay(RvtDocument doc)
{
List<ElementId> finalwalls = new List<ElementId>();
foreach (Element wall in new FilteredElementCollector(doc).OfClass(typeof(Autodesk.Revit.DB.Wall)).ToElements())
{
Parameter lengthParam = (from Parameter p in wall.Parameters where p.Id==new ElementId((int)BuiltInParameter.CURVE_ELEM_LENGTH) select p).FirstOrDefault();
if (lengthParam != null)
{
if( ((int)(lengthParam.AsDouble()/5))%2 == 1 )
finalwalls.Add(wall.Id);
}
}
return finalwalls;
}
…
time = DateTime.Now;
List<ElementId> wallsFound2 = FindWallsUsingOurOwnWay(CachedDoc);
timespan = DateTime.Now - time;
MessageBox.Show(string.Format("Found {0} such walls in {1} seconds.", wallsFound2.Count, timespan.TotalSeconds), "Using Our Own Way");
…
As can be seen, it is much simpler and can cover all possible cases. Here is what the test code will report about the same test model:
It surely uses a bit more time, 19.5% more, than the first approach, but it can find the two walls that the first approach misses. For bigger models, it may miss more. And its performance will become poorer and poorer if more cases have to be covered.
Our own way does not have this issue at all. Its code is the same for all different walls; its performance is good enough and pretty consistent; it can be adjusted very easily to address different situations.
So it is obvious which way to choose in this situation, isn’t it?
ElementParameterFilter Creator of RevitAddinCoder can help create code combining various existing filter rules and evaluators to filter element parameters.
Recent Comments