Hi,
I am trying to write an add-in with C# to automate the process of sequentially labeling structural columns to match the sequence in the graphical column schedule.
I have written the following code to get all the concrete columns in the project and then create a list of their Column Location Marks (ie A(2000)-1(2150) ) (Built-in Category):
ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns);
StructuralMaterialTypeFilter filter_mat = new StructuralMaterialTypeFilter(StructuralMaterialType.Concrete);
IList<Element> columns = collector.WherePasses(filter).WherePasses(filter_mat).WhereElementIsNotElementType().ToElements();
List<XYZ> locations = new List<XYZ>();
List<string> colmarks = new List<string>();
foreach (Element ele in columns)
{
string colmark = ele.get_Parameter(BuiltInParameter.COLUMN_LOCATION_MARK).AsString();
colmarks.Add(colmark);
}
colmarks.Sort();
My trouble comes at this point. The colmarks.Sort() method does not match the order of the columns in the graphical column schedule.
I have also tried sorting the columns by their XYZ location which doesn't match the order in the graphical column schedule either.
Can anyone provide any insight into how the graphical column schedule orders the columns and how I can replicate this.
Thanks
Solved! Go to Solution.
Solved by FAIR59. Go to Solution.
See attached screenshots.
I've tried a few different ways which involve creating a list of the parameter as strings and then sorting or using orderby as below:
List<Element> sortedElements = columns.OrderBy(x => x.get_Parameter(BuiltInParameter.COLUMN_LOCATION_MARK).AsString()).ToList();
I have the same issue in dynamo too, the order seems to match my code but not the graphical column schedule... (screenshot attached).
sorry to say, It is a well known limitation to this feature see this link
I was able to reproduce the same as well.
LocationMark syntax :
A(xxxx)-1(yyyy)
sort order:
List<FamilyInstance> colums = new FilteredElementCollector(doc) .WhereElementIsNotElementType() .OfCategory(BuiltInCategory.OST_StructuralColumns) .OfClass(typeof(FamilyInstance)) .Cast<FamilyInstance>() .ToList(); colums.Sort(new ColumnMarkComparer());
helper classes:
public static class Extensions { public static string GetColumnLocationMark(this FamilyInstance f) { Parameter p = f.get_Parameter(BuiltInParameter.COLUMN_LOCATION_MARK); if (p==null) return string.Empty; return p.AsString(); } }
public class ColumnMarkComparer: IComparer<FamilyInstance> { int IComparer<FamilyInstance>.Compare(FamilyInstance x, FamilyInstance y) { if( x ==null) { return y==null? 0 : -1 ; } if (y ==null ) return 1; string[] mark1 = x.GetColumnLocationMark().Split('(' ,')'); string[] mark2 = y.GetColumnLocationMark().Split('(',')'); if (mark1.Length<4) { return mark2.Length<4? 0 : -1; } if(mark2.Length<4) return 1; //gridsequence A int res = string.Compare(mark1[0],mark2[0]); if( res!=0) return res ; //gridsequence 1 string m12 = mark1[2].Remove(0,1); string m22 = mark2[2].Remove(0,1); res = string.Compare(m12,m22); if(res!=0) return res ; // value xxxx double d1 = 0; double d2=0; double.TryParse(mark1[1],out d1); double.TryParse(mark2[1], out d2); if (Math.Round(d1-d2,4)!=0) { if ( d1<0 ^ d2<0) { return d1<0? 1 : -1; } else{ return Math.Abs(d1) < Math.Abs(d2) ? -1 : 1 ; } } // value yyyy double.TryParse(mark1[3],out d1); double.TryParse(mark2[3], out d2); if (Math.Round(d1-d2,4)!=0) { if ( d1<0 ^ d2<0) { return d1<0? 1 : -1; } else{ return Math.Abs(d1) < Math.Abs(d2) ? -1 : 1 ; } } return 0; } }
Many thanks to Fair59 for yet another brilliant and succinct answer.
Edited and saved for posterity on the blog:
Can't find what you're looking for? Ask the community or share your knowledge.