The day before yesterday, I demonstrated the use of the Mirror method. Henrik Bengtsson of Lindab immediately came back with a question on this. Funnily enough, the reason I quickly posted the article the day before yesterday was because someone completely different asked the exact same two questions as Henrik in the exact same sequence. There seems to be some kind of morphogenetic resonance going on among Revit developers. Anyway, here is Henrik's question:
Question: The mirror command works all right according to the description. I now face another issue that I had not thought of before. How can I get a reference to the newly created mirrored objects? Those are actually the objects that I want to continue working with.
Answer: Because this question was already asked once this morning, I had some time to meditate deeply on how to retrieve the newly created elements generated by the mirroring operation. My first idea was to grab them by parsing the tail of the journal file, but unfortunately they are not listed there. My second idea works, however:
- Ask the document for all its elements before the mirroring operation and remember the total number n.
- Call the Mirror method, generating a number of new elements.
- Ask the document for all its elements again, and retrieve the ones whose index exceeds n.
I make use of two helper methods for this:
- GetElementCount determines the total number of document elements before the mirroring operation.
- GetElementsAfter returns a list of all document elements whose index exceeds a given number.
Here is the implementation of these two methods:
int GetElementCount( Document doc ) { int count = 0; ElementIterator it = doc.Elements; while( it.MoveNext() ) { ++count; } return count; } List<Element> GetElementsAfter( int n, Document doc ) { List<Element> a = new List<Element>( n ); ElementIterator it = doc.Elements; int i = 0; while( it.MoveNext() ) { ++i; if( n < i ) { a.Add( it.Current as Element ); } } return a; }
Here is the code for the new external command implementing this. It is a simple extension of the mirroring command CmdMirror presented on Wednesday:
Application app = commandData.Application; Document doc = app.ActiveDocument; ElementSet els = doc.Selection.Elements; Line line = app.Create.NewLine( XYZ.Zero, XYZ.BasisX, true ); int n = GetElementCount( doc ); doc.Mirror( els, line ); List<Element> a = GetElementsAfter( n, doc ); string s = "The following elements were mirrored:\r\n"; foreach( Element e in a ) { s += string.Format( "\r\n {0}", Util.ElementDescription( e ) ); } Util.InfoMsg( s ); return CmdResult.Succeeded;
Here is version 1.1.0.41 of the complete Visual Studio solution including the mirroring command CmdMirror and the new command CmdMirrorListAdded.
Disclaimer: Please note that there is nothing in the Revit API documentation stating that the iterator returned by doc.Elements will traverse the elements in the order they were added to the database. That happens to be the case today and has been so in the past. This behaviour may change without notice in the future.