PDA

View Full Version : test if level exists



sfaust
2007-11-12, 07:10 PM
I'm looking for a way to test if an element has a level associated with it. I know some things don't have an associated level, so I'm looking for a way to filter them out, anyone know a way?

thanks,
Steve

GuyR
2007-11-12, 07:27 PM
What element is of interest that doesn't have an level associated with it?

Guy

sfaust
2007-11-12, 07:41 PM
Actually I'm looking for the ones that do have a level associated. I want to select everything associated with a selected level. I have it so that it gets the levels in the project, lets the user select a level, and stores that level's name as a string. Now I want to run through the elements and test if the level they are associated with is the same as the selected level, but it should run into some elements that don't have associated levels (elevation tags, etc). I don't want it to throw an error when it hits those elements so I would like it to first test if the element has a level, and if it does then test if it matches the selected level.

so is there a way to filter like I want? or a better way to go about it?

GuyR
2007-11-12, 07:59 PM
If you cast everything( except symbols) as elements (Autodesk.Revit.Element) then if the element has no associated level it will return a null.
if (myElement.Level != null)
{
// I've got a level
}

If you've got a large model to walk and you're only interested in model objects. Then it will be more efficient to filter for those and then get their levels.

HTH,

Guy

sfaust
2007-11-12, 08:31 PM
ok, sorry for all the questions, but how do you filter to just model elements?

I put in the null reference and I get the error "object reference not set to an instance of an object." Here is the portion of the code I'm having trouble with (converted to C):

while (elemiter.MoveNext) {
elem = elemiter.Current;
if (elem.Level != null)
{
if (elem.Level.Name == lvlselect)
{
elemset.Insert(elem);
}
}
}

sfaust
2007-11-12, 08:38 PM
ok, nevermind. the problem was with my declaration of elemset. I didn't declare it as a new set and somehow that was throwing it off.

Still wondering about filtering to model elements, though...

GuyR
2007-11-12, 08:50 PM
Steve,

When you walk the object tree using the Element.Iterator what gets returned are .NET objects. So you have to implicitly cast each object depending on it's type or use the 'as' keyword to dynamically cast the object. When you test for the level the current object is still an object you haven't cast it to a Autodesk.Revit.Element.

Are you interested in only model elements? I'll post a c# example for you if you like.

Guy

sfaust
2007-11-12, 09:10 PM
yes, only interested in model elements.

Any help you can give is always appreciated. One more question while you're at it if you don't mind. Can you (and how do you) make Revit select the objects in a set and return execution to Revit. I have it so that elements are added into a set and then displayed by their ID and Name, filtered by level. So I have all of those .net object in a set, but how do I exit the external command and leave Revit with that selection?

Thank you so much for all your help and bearing with a newbie, I appreciate it :)

GuyR
2007-11-12, 09:14 PM
ok, nevermind. the problem was with my declaration of elemset. I didn't declare it as a new set and somehow that was throwing it off.

Still wondering about filtering to model elements, though...

Depending on how far you want to go really depends on how large your projects are IMO. This is the simplest way in C#:

ElementIterator ElemItor = commandData.Application.ActiveDocument.Elements;
while (ElemItor.MoveNext())
{
object elem = ElemItor.Current;
if !(elem is Autodesk.Revit.Symbol)
{
Element ImAnElem = elem as Autodesk.Revit.Element;
if (ImAnElem.Level != null)
{
string levelName = ImAnElem.Level.Name;
}

}
}

In plain english: If the object isn't a symbol then convert it to an Autodesk.Revit.Element. If the level object exists then get the name. If you need to know the type of element then check the category. If you have large projects and this is too slow then it gets trickier but can be done.

You can return element for highlighting by adding elements to the ActiveDocuments Selection.Elements ElementSet. Note however there is no way to change the active view if that's required.

No worries with helping. You're trying it yourself before posting and I'm home looking after sick children and not set up to work from home. Last 6 days has been a good time to post here ;-)

HTH,

Guy

sfaust
2007-11-12, 10:23 PM
Ok, I got that to work, now the last part is the adding to the activedocument selection set. I understand that in concept but I'm missing something I think. I tried to do it and the command runs without errors, but I get no selection back. Here's my code for adding it to activedocument:

Autodesk.Revit.Document activedoc = commandData.Application.ActiveDocument;
if (selecteddialog.DialogResult == DialogResult.OK)
{
foreach ( elem in elemset) {
activedoc.Selection.Elements.Insert(elem);
}
}


Hope your kids get feeling better! 6 days is a while to be sick :(

GuyR
2007-11-12, 10:28 PM
Umm, kinda doing this from memory. I think I'm getting confused. The constructor for IExternalCommand passes an elementSet. Try adding elements to that elementSet?

Guy

sfaust
2007-11-12, 11:06 PM
hm. well, the function text is:
Public Function Execute(ByVal commandData As Autodesk.Revit.ExternalCommandData, _
ByRef message As String, ByVal elements As Autodesk.Revit.ElementSet) _
As Autodesk.Revit.IExternalCommand.Result Implements Autodesk.Revit.IExternalCommand.Execute

I'm assuming it's the "elements" set that I need. i can add to that, but I just read further up and it says "<param name="elements">A set of elements to which the external application
''' can add elements that are to be highlighted in case of failure or cancellation.</param>

Does that mean items can only be highlighted in case of cancellation or failure?

sfaust
2007-11-12, 11:14 PM
if so, that's ok. What I already have does 90% of the work I wanted it to, so if I have to do the other 10% it's probably ok, but would be nice if I could have it select the items found.

Let me know if you can think of anything. I will work with what I have for now (and will share if we can't get it figured out or if it's not possible.

thanks again.

Steve

GuyR
2007-11-13, 12:22 AM
Sorry Steve, I've been sending you down the wrong path. Document.ShowElements method and overloads are the one you want.

HTH,

Guy

sfaust
2007-11-13, 04:07 PM
no worries, I probably wouldn't be very far down any path without your help :)

Ok, cool, I got that to work, and it's a step up but still doesn't quite show what I wanted. That allows me to zoom the window to fit the elements on the screen but doesn't highlight them or select them. Am I doing something wrong?

I also noticed that there is a selelementset class that has methods to add and clear. When I put them in VB recognizes the lines, but tells me "Reference to a non-shared member requires an object reference." I'm not sure what that means...

Elizabeth Shulok
2007-11-13, 08:33 PM
Ok, I got that to work, now the last part is the adding to the activedocument selection set. I understand that in concept but I'm missing something I think. I tried to do it and the command runs without errors, but I get no selection back. Here's my code for adding it to activedocument:

Autodesk.Revit.Document activedoc = commandData.Application.ActiveDocument;
if (selecteddialog.DialogResult == DialogResult.OK)
{
foreach ( elem in elemset) {
activedoc.Selection.Elements.Insert(elem);
}
}



Steve - I think you were on the right track here. I'm doing something similar (although in C#) with selecting elements, but I use the Add() method rather than Insert(). I'm not sure what the difference is, but try using:

activedoc.Selection.Elements.Add(elem)

I also use the Clear() function to clear out anything that might already be selected.

Good luck,

sfaust
2007-11-13, 08:39 PM
SWEET! Ok, that worked. I used the clear and then added the elements in via the add that you said, and it works :). I will post my app in a new thread :) thanks for the tip

Steve

sfaust
2007-11-13, 10:57 PM
hmm... alright I spoke too soon. I tried this on an actual project and ran into a problem. I tried it on one of my main levels, and it returned the "object reference not set to an instance of an object" error. I did try it on some other levels with not near as many objects on them and it worked great. Is there a maximum amount of objects that a set can contain? I'll test some more, but it seems like it's the levels with a whole lot associated with them that create errors.

That's actually not that bad because what I originally wanted it for was to check a level before deleting it to see if any model elements would disapear with it. Presumably you wouldn't be checking that on a main level, just a secondary with a limited number of objects so maybe it's ok. Still shouldn't be making errors though...

Here's the code that is looking for elements on a certain level:

Dim elemset As New Autodesk.Revit.ElementSet
elemiter.Reset()
Do While elemiter.MoveNext
elem = elemiter.Current
If Not TypeOf elem Is Autodesk.Revit.Symbol Then 'filter for non-model elements
If elem.Level IsNot Nothing Then
If elem.Level.Name = lvlselect Then
elemset.Insert(elem)
End If
End If
End If
Loop

and converted to C#

Autodesk.Revit.ElementSet elemset = new Autodesk.Revit.ElementSet();
elemiter.Reset();
while (elemiter.MoveNext) {
elem = elemiter.Current;
if (!elem is Autodesk.Revit.Symbol)
{
//filter for non-model elements
if (elem.Level != null)
{
if (elem.Level.Name == lvlselect)
{
elemset.Insert(elem);
}
}
}
}

Elizabeth Shulok
2007-11-14, 12:01 AM
When exactly do you get the "object reference not set to an instance of an object" error? Usually I get that when I'm trying to access something that is null, but you seem to be checking for that before using your objects.

sfaust
2007-11-14, 12:06 AM
I select a level from a dialog, which it saves as a string (lvlselect), then goes through this part of the code. It's somewhere in here that it gives the error. Like I said, it works fine when there aren't many objects on the level, but if there are a lot it thinks for a good 4 or 5 seconds and then gives the error. On the levels without many objects it returns all of them within a second or two.

Elizabeth Shulok
2007-11-14, 12:15 AM
The number of elements shouldn't be an issue. Probably there is something wrong with one of the elements. I always check that my element is not null before doing anything with it (although you'd hope that the iterator wouldn't give you a null element). I would try this:

Autodesk.Revit.ElementSet elemset = new Autodesk.Revit.ElementSet();
elemiter.Reset();
while (elemiter.MoveNext) {
elem = elemiter.Current;
if (elem != null
{
if (!elem is Autodesk.Revit.Symbol)
{
//filter for non-model elements
if (elem.Level != null)
{
if (elem.Level.Name == lvlselect)
{
elemset.Insert(elem);
}
}
}
}
}

Let me know if that resolves your error on larger models.

sfaust
2007-11-14, 03:19 PM
nope, same error. It actually seemed to come a little quicker this time even, although I'm not sure about that.

Elizabeth Shulok
2007-11-14, 05:55 PM
Are you able to debug the project so you can pu in breakpoints? (I wasn't sure since in another post it looked like you have the Express version of VS2005.) If you can, I'd try putting a try...catch statement around this section of code and then put a breakpoint in your catch statement so you can try to see which element it is choking on and possibly why.

GuyR
2007-11-14, 08:40 PM
nope, same error. It actually seemed to come a little quicker this time even, although I'm not sure about that.

.NET will cache the command so the first time it runs is always the slowest. Find attached quick hack tried against m_Conference.rvt from the training files.No errors on that model. What have you modelled ;-)

In C# but if you do download sharpdevelop then you can automagically the project to VB.NET.

HTH,

Guy

sfaust
2007-11-14, 09:18 PM
seems to be working. it gets the number of elements on the level associated with the current view, right? It gave an error when I first tried it but I happened to be in a sheet view, so that would make sense. Anyway, seemed to work on the same file that failed before. I'll convert to VB and take a look and see if I can get apply it to my code. thanks, I'll report back later...

GuyR
2007-11-14, 09:51 PM
seems to be working. it gets the number of elements on the level associated with the current view, right?

Yeah sorry, works on the active view.

sfaust
2007-11-19, 04:26 PM
Ok, well I'm still having some issues with the larger projects. I'm going to keep working on that and look more at GuyR's example, but here's the code and the program as it is if anyone wants to use it and/or look at the code.

Thanks all for your help!

Steve

sfaust
2007-11-20, 01:41 AM
woo hoo! Go me! I figured it out! Well, kind of anyway. What it is choking on is stacked walls. Everything else works just fine, but stacked walls kill it. Guy I'm not sure why it kills mine and not yours, but that's definitely what it is. Does anyone know if there is a way to seperate out stacked walls, or why it would be having an issue with these?

Elizabeth Shulok
2007-11-20, 02:22 AM
Add a test for stacked walls after your test for Revit symbols. So building on your earlier example:


Autodesk.Revit.ElementSet elemset = new Autodesk.Revit.ElementSet();
elemiter.Reset();
while (elemiter.MoveNext)
{
elem = elemiter.Current;
if (elem != null
{
if (!elem is Autodesk.Revit.Symbol)
{
//filter for non-model elements
// filter out stacked walls
if (elem is Wall)
{
Wall wall = elem as Wall;
if (wall.WallType.Kind == Autodesk.Revit.Symbols.WallType.WallKind.Stacked)
{
continue;
}
}
if (elem.Level != null)
{
if (elem.Level.Name == lvlselect)
{
elemset.Insert(elem);
}
}
}
}
}

GuyR
2007-11-20, 06:01 AM
Well, kind of anyway. What it is choking on is stacked walls. Everything else works just fine, but stacked walls kill it.

Well done Steve ;-) You've found a bug. It's raising an exception while trying to get the orientation of the wall. As long as you're not just processing the elementset from the ActiveView and walking the whole tree. You'll still catch the walls that make up the stacked wall but maybe you don't want to count them individually (2 walls)?

I'll file it with ADN and see what they say.

Guy

sfaust
2007-11-20, 05:08 PM
Ok, thanks to help from you guys it's ready to go! It still doesn't handle stacked walls great, it basically skips them and warns the user that it's doing it, but the pieces show up. Interestingly, they show up twice; once as a wall and once as a curtain panel. Either way, it doesn't create an error anymore and the program continues normally and all elements can still be selected. I also tested it on a large project and it seems to work well, albeit slow if there are really a lot of elements.

So Guy let me know what ADN says, but in the mean time, THANKS TO BOTH OF YOU!

Elizabeth Shulok
2007-11-20, 10:43 PM
Congrats on getting it working Steve. Guy seems to be the expert around here, but I'm glad if I was able to help you out. It's fun stuff.

GuyR
2007-11-20, 10:54 PM
Guy seems to be the expert around here, but I'm glad if I was able to help you out. It's fun stuff.

I'm no expert, the experts are the x number of uber programmers sitting in the Factory. The more the merrier. And nice to see Steve sharing the command and the source. Everyone learns when the source is available.

Guy

sfaust
2007-11-20, 10:59 PM
Thanks :) I'm excited, it's the first thing I've been able to create that's actually useful with my newfound programming "knowledge" :). As far as sharing, no problem. You guys practically wrote about half of it anyway. Speaking of which, here is the final working code with the stacked wall updates.

GuyR
2007-11-24, 03:33 AM
I'll file it with ADN and see what they say.

Yep, it's a bug in the API. Issue is logged.

Guy

sfaust
2007-11-26, 11:32 PM
ok, well good that they're aware of it. Let me know if there are any updates...

NKramer
2008-05-23, 07:50 PM
Steve,

I cant seem to get this to work with 09. Is there something that I need to change or do you have an update?

thanks,

Nick

sfaust
2008-05-27, 10:21 PM
I just plugged in the ini info in 2009 and it seemed to work, what issues are you having?

NKramer
2008-05-27, 11:08 PM
I just plugged in the ini info in 2009 and it seemed to work, what issues are you having?

Just figured it out. I had the ECClassName set to 1 by accident.

thanks

Nick

sfaust
2008-05-28, 03:57 PM
Glad it was that because I wasn't going to know where to start looking for the error :).

BTW, GuyR, do you know if they fixed the error in the stacked walls for 2009? If so, I could take that part out of the code...

GuyR
2008-05-28, 09:18 PM
I haven't tested extensively, nor do I have confirmation from ADN but this bug seems to be fixed.

Also , if you are rewriting for RAC2009 , refactor to use filters for a massive improvement in speed on large models.

HTH,

Guy

sfaust
2008-05-28, 10:51 PM
ok, thanks for the tip. I can't do it right now, but I'll try to look into it...

oswbus739049
2011-08-31, 08:20 PM
Thank you Steve for sharing the code, and all the members that helped him to build it. I am a beginner and this is really helpful to all of us that want to learn about the "Add-ins" development.

dbartlett
2012-01-11, 10:54 AM
Hi Steve, I wonder if this is updated for 2012? It is a really helpful tool so thank you for your efforts. Dale

sfaust
2012-01-11, 04:38 PM
Dale,

This has actually been expanded and updated for 2012 and is now for sale on my website under the name 'Selection Master'. You can check it out here (http://www.software.revolutiondesign.biz/selectionmaster).

Thanks,
Steve