Tuesday, June 28, 2011

Point Cloud Fix in Revit 2012 Web Update 1

One of the biggest problems that people have had with the new Point Cloud capabilities of Revit 2012 is how it dealt with multiple point clouds inserted into your Revit project.
If you had multiple scans that all were from the same origin, and you inserted them all origin-to-origin, then they would all line up, right? wrong...Some of the problem related to how Revit handled large coordinate values (as you may know, Revit doesn't like it when elements start showing up miles from the model origin). If you inserted a PCG file which was indexed from something where the coordinates were in state-plane (which is not all that uncommon) - Revit would basically reset the coordinates and insert it center-to-center. And then how are you going to insert the next one so that it is consistent?
The answer was supposed to be the third insert option: Auto - Origin to Last Placed (meaning that it would make sure that the origin matched the origin of the previous model). But it didn't work :).

So what's new in 2012 Web Update 1? It works!
Before:


After:



While no one likes to see bugs like this, it's nice to see decent turnaround on it. I had been worried it was going to involve having to re-index all of the PCG files - that would have been bad.

[Editor's Note: Jason Seck just pointed out to me... you might still be annoyed that they haven't addressed the "first cloud" issue... Your first large coordinate cloud is still going to come in Center-to-Center. All they have fixed is the "relative placement" of clouds issues. I think it will be a while before the "first cloud" issue is fixed, because to do that they would need to fix the "two-miles-from-the-origin issue", and that seems like a big one.]

Saturday, May 28, 2011

An oddity with Drafting View mirroring

So I was asked if it was possible to mirror a drafting view using the API (apparently the built-in project mirroring doesn't cover drafting views).

It seemed straightforward enough... so I wrote a quick test... and it didn't work...
- it worked fine in a floor plan view
- it didn't work in a drafting view
- the code completed just fine - it just didn't really seem to show any difference.

My initial code is below...
- Get all the elements in the current view
- Use the new ElementTransformUtil class to figure out which could be mirrored, and mirror them.



FilteredElementCollector coll =
new FilteredElementCollector(uiDoc.Document, uiDoc.ActiveView.Id);

IList elems = coll.ToElements();

// make sure that stuff can be mirrored
List toMirror = new List();

foreach (Element elem in elems)
{
if (ElementTransformUtils.CanMirrorElement(uiDoc.Document, elem.Id) == false) continue;
toMirror.Add(elem.Id);
}



So why did this complete successfully, but not show any difference?
The answer is one of those great undocumented elements in the wilds of the Revit database. When I looked in the debugger at what I was actually attempting to mirror, I saw this:




What I see here is a mystery element called "ExtentElem" which is being copied. I have a sneaking suspicion that it might be telling the view the actual extent of what is in it... So how can we exclude it? well - it has no actual category (which is probably a sign that in general we don't want to mirror an element like that!).


So - we add a line like:

if (elem.Category == null) continue;

and voila! we have our drafting view being mirrored.



I wish that I could say that all Revit database mysteries are "easily" solvable like this - there's plenty of times where you just run into a wall, and can't get to what you want... but today's story has a happy ending!

Monday, May 16, 2011

DWFplus for Revit 2012

Well, it has been forever since I've last posted... I missed the release of the 2012 API and a variety of other announcements. But I'm trying to get back on the horse.

To that end - a quick video to show what I think is a cool new feature of our Utilities for Revit 2012 product - a new utility called "DWFplus".

If you've ever looked at distributing a DWF file, and figuring that Revit ought to be making it chock-full of all my BIM data... you may have been slightly disappointed. The rules for when Revit published a parameter or didn't were arcane - and I'm still not sure if we've accurately reverse engineered them. And certain features like hyperlinks... how is it that AutoCAD can have hyperlinks but not Revit!

So DWFplus is an attempt to change that. It starts with a regular DWF export, but adds in a variety of neat stuff:


  • All parameters (or selected parameters) that you want to publish

  • Parameters are attached to Tags - not just the elements

  • Includes 2D Hyperlinks for any URL parameters (even multiples)

  • Parameters are published in 3D as well as 2D.

  • Includes some neat 3d viewpoints for 3D DWF views.

Here's a little video to demonstrate:






Note: IMAGINiT Utilities for Revit is available here, and is free for clients that keep their Revit subscription with IMAGINiT.

Thursday, April 22, 2010

Revit API 2011: Revit AddIn Manager – Almost Edit & Continue

(part of our ongoing series)
If you’ve been developing for Revit for a while – you groaned significantly when, in Revit 2010, changes were made to Revit that disabled the “Edit-and-Continue” capability within a Revit add-in. That is to say – if you wanted to make a minor code change while Revit was debugging – you had to close Revit (wait for Revit to be totally closed), perform the change, then restart Revit, re-load your model, and then try to get back to the same location. Argh – seems like 2+ minutes down the drain any time this happens.

Enter the “Revit AddIn Manager” – part of the Software Development Kit. This tool has been around since 2009, I think – it historically provided handy mechanism for a developer to test External commands or applications – even when they forgot to add them to the REVIT.INI file. It could both update the INI file for you, or even just launch the command in session.

image

What’s Different in 2011?

I suspect due to some conversations and posts that were had on Jeremy Tammik’s blog late in the development process, the AddIn Manager has been notably improved – such that while you can’t support edit-and-continue, you can now support updating your code while Revit is running, and just re-running your command inside of Revit.

How does this work? The Addin utility is doing some lifting behind the scenes, including copying the DLL and related files to a temporary folder, and loading the .NET assembly DLL from that location.

What does this mean for us? That when we start up Revit with the debugger attached, we can run the AddInManager. From the AddInManager we can launch our command in a way that loads it into memory before starting the debug process.

While we still cannot edit and continue, we CAN open a second copy of Visual Studio, and make changes by rebuilding the project.

- it allows us to overwrite the project, because the running project was copied to somewhere else.

- we are now able to just re-start the AddIn Manager in order to start our updated version of the command.

The Features of the AddIn Manager

The behind-the-scenes mechanics are described above. It also has (obviously) been enhanced to support the new “.addin file” mechanism rather than the Revit.INI mechanism of registering addins. The command also supports some additional options which can be a little confusing at first. The list of AddIn Manager commands looks like this:

image

What’s the deal with all this manual, automatic and faceless?

The Manual vs. Automatic entries refer to the new TransactionMode and RegenerationMode that must be assiged to each command. Because the AddIn Manager is going to invoke your AddIn, it would be a problem if AddInManager specified Automatic mode but your code specified manual mode. So you have to pick automatic or manual based on what YOUR command is defined as. NOTE: No mix/match on transaction and regeneration mode… you have to be either Auto/Auto or Manual/Manual. The application will stop you if you pick the wrong one (although the error message leaves something to be desired).

Faceless, while the mechanism seems a little clumsy – is a nice little feature. Fundamentally – it remembers the last command that you executed, and will just execute that again (no user interface, it just does it – that way you don’t need to re-browse, re-select, and re-run the command in question).

Conclusion

If you occasionally work with API developers – get a copy of the AddIn Manager to make it easier to test and setup API AddIns! If you’re a developer, there are now many good reasons to set up the AddIn Manager. So get to it! It’s in the Revit SDK installation folder.

Revit 2011 API: What’s New in Element Creation

(part of our ongoing series)
Each new version, I go through what is new in the specific API area of element creation. Every CAD API has some logical divisions, from information retrieval, to element creation, to interactivity – and you can tell from how strong each area is what the factory’s focus is in the API.

Revit’s start in this area was weak – the API was more about finding elements and updating parameters than actually creating new elements and geometry. In recent releases, Revit really played catch up – I believe it now supports 101 different element creation methods.

So what’s new in 2011 in this area: in short, not much… This was not an area of focus in 2011, so there’s only a few new things in this specific area:

  1. NewTruss() – now available in architecture
  2. NewRebarType()
  3. NewRebarHookType()
  4. NewRebarCoverType()
  5. FaceWall.Create()

The last one is of the greatest interest to me personally. This enables you to create a wall based on a face (typically a face that is on a mass element). This is an advanced technique used in Revit to create complex wall shapes.

Two other items deserve honorable mention here as well:

  • UIDocument.PromptForFamilyInstancePlacement() – while not technically a “Element Creation” capability, it opens up some significant doors to more interactive design applications within Revit – by letting the end-user help the developer place the family instance visually.
  • SolidSolidCutUtils – A new utility class to help with doing solid-to-solid cuts in the modeling environment. This is typically used either for GenericForm kind of family solids or family instances.

All in all, while this category doesn’t seem like it got much attention in 2011, the fact is that with 101 element types that can be created, it has attained a certain level of maturity. For example, if I scan the Home ribbon in 2011 – it is possible to create almost everything that is available on that toolbar (I think the exceptions are: Ceiling, Model Group (you can’t create a new one), Railing, Ramp, Stairs. That’s really not too bad – and the remaining ones are a little on the obscure/complex side.

So let me hear from you by comments? Are you really waiting for one of the missing elements that can’t be created? or are you just reluctant to do API work with geometry creation until it supports 100%? How many different kinds of elements are YOU creating in your app?

Saturday, April 17, 2010

Revit 2011 API Series: RevitLookup: The New Name for RvtMgdDbg

(part of our ongoing series)
Since the beginning of Revit development time – in the 8.0/8.1 range, the best way to learn about what is possible with the Revit API was to use a “Snoop Tool” – something that could interrogate all of the elements in the model and all of their properties.

In the beginning, there was RevitDbg – a tool by Fenton Webb at Autodesk. It used reflection to browse through a massive tree structure of all the elements in the model. It was slow, but cool.

Later, Jim Awe of Autodesk brought his Snoop tool (called “RvtMgdDbg”) from AutoCAD to Revit – bringing not just browsing of elements but also event testing as well as some test commands. This became the tool that most Revit developers cut their teeth on. That said – I’m still amazed at the number of developers who have tried to learn the API without the benefit of RvtMgdDbg… I have to imagine it’s like developing in the dark!

For all of its importance to Revit developers, RvtMgdDbg was always somewhat of a step-child at Autodesk… No one really owned it (so it was nice that they provided the source – at least 3 times over the past few years I had to upgrade it myself to support the latest version before someone at Autodesk took care of it). It was also unclear over time how it was going to be distributed – was it only for ADN members? Did you have to attend a particular AU session? Or did you just have to know the right people? Thankfully, in the past year or so Autodesk has caught on to how important RvtMgdDbg is to getting developers up-to-speed and has made it available to anyone, usually via Jeremy Tammik’s blog.

Which brings us to 2011… While not revolutionary – it is an important evolution for RvtMgdDbg. It has been adopted by the Revit API team – which means that there are resources devoted to updating it and providing it along with the SDK – under a new, more accessible name: RevitLookup. Kevin Vandecar as well as some of the Shanghai developers have done yeoman’s work in upgrading it (it is a grueling task – I know because I had to do it myself at least twice during the 2011 alpha/beta cycle).

RevitLookup can be found in the SDK folder under RevitLookup – it appears that you’ll have to build it yourself (binaries were not shipped) – but it’s great to see that this tool getting its proper due from Autodesk.

Thursday, April 08, 2010

Revit 2011 API: SDK Posted (a while ago)

We’re all still waiting anxiously for the official Revit 2011 product to become available… They set the expectation for today – but it’s not there yet! and it’s 7:58 AM! What’s the deal? :)

That said – I noticed last night that the final Revit 2011 SDK is available as a standalone download on the ADN page (posted back on 4/1 – and I didn’t notice).

In other news, I hope to get back onto posting the rest of my 2011 articles – I’m just temporarily buried in project work.

[Editor: And I can see that I have to go back and add to a few previously written articles. I can see at least 15 enhancements in the new SDK that were added late enough in the process that I was unaware of them! Woo-hoo, more toys!]

Sunday, March 28, 2010

Revit API 2011: The New Way to Find Elements

(Part of our Revit API 2011 Series)
[Editor’s Note: Updated with some late-breaking additions that will only be documented in the released documentation]

For the uninitiated, much of the core work in a Revit application involves finding elements within the Revit database. Whether it’s finding exterior walls, 3D Views, or wall types – it’s always the same concept… Doing a lookup from the Revit to get a list of elements.

This is an area that “the factory” has improved upon release-after-release… From the early days, where you always had to cycle through everything – through the newest incarnation, today. I think I’m counting right that this is the 4th generation of the element iteration API. And no more ignoring what’s new – because you’re required to use the new method in 2011!

The 2011 Approach

The factory has really created something great here – something that is mature and answers almost anything you could want in an element iteration API. And they’ve really tried to do it in a way that matched the best and most modern approaches in .NET – such as LINQ.

The fundamental concept for iteration is the FilteredElementCollector class.

Getting Started

You construct the class in one of three ways:

// get ready to filter across an entire document
FilteredElementCollector coll =
     new FilteredElementCollector( myDoc );

or

// get ready to filter across just my pre-selected set of
// elements!
FilteredElementCollector coll =
     new FilteredElementCollector( myDoc, myElementCollection );

This is great when you’d rather not search your entire model when you’ve already got the subset you want…

or

// get ready to filter across just the elements visible in a view
FilteredElementCollector coll =
    new FilteredElementCollector( myDoc, viewId );

This is equivalent to the old mechanism of the View.Elements collection – which is now gone.

These constructors just get you started… Then it’s time to move on to the filtering.

Filtering Mechanisms with FilteredElementCollection

The factory has introduced three different categories of filtering in 2011:

  • Logical (operations like AND/OR)
  • Quick (operations that are FAST)
  • Slow (operations that take a bit longer)

While these kinds of things have probably conceptually always existed, but they were found out by experimentation rather than Autodesk documenting and sharing them up front…

  • Quick
    • ElementCategoryFilter / OfCategoryId()
    • ElementTypeFilter / OfType()
    • ElementIsElementTypeFilter /
          WhereElementIsElementType()
          WhereElementIsNotElementType()
    • ElementOwnerViewFilter / OwnedByView(), WhereElementIsViewIndependent()
    • ElementDesignOptionFilter / ContainedInDesignOption()
    • ElementIsCurveDriven / WhereElementIsCurveDriven()
    • ElementStructuralTypeFilter
    • BoundingBoxContainsPointFilter
    • BoundingBoxIntersectsFilter
    • BoundingBoxIsInsideFilter
    • ExclusionFilter
    • FamilySymbolFilter
  • Slow
    • ElementParameterFilter
    • ElementLevelFilter
    • FamilyInstanceFilter
    • FamilyStructuralMaterialTypeFilter
    • PrimaryDesignOptionMemberFilter
    • StructuralInstanceUsageFilter
    • StructuralMaterialTypeFilter
    • StructuralWallUsageFilter
    • CurveElementFilter
    • RoomFilter
    • SpaceFilter
    • AreaFilter
    • RoomTagFilter
    • SpaceTagFilter
    • AreaTagFilter

These are documented further in the API help file in its own introductory section called “Element Iteration API”.

I’ll give some of the typical situations here:

If you know the type:

// we want walls
coll.OfClass( typeof(Wall) );

or if you know the category:

// we want Curtain Wall Panels:
coll.OfCategoryId( BuiltInCategory.OST_CurtainWallPanels );

Now here’s where it starts to get interesting… If you want to put different filters together, it can look something like this:

// We want door instances
coll.OfCategoryId( BuiltInCategory.OST_Doors ).OfClass( typeof(FamilyInstance));

What’s going on here? each filter ADDs requirements to the collector. And to make the whole thing more friendly towards combining, the methods return a pointer to their object, so that you can “chain” them together. For example, the code above would be equivalent to:

// we want door instances
coll.OfCategoryId( BuiltInCategory.OST_Doors);
coll.OfClass( typeof(FamilyInstance) );

We are updating our collector two times with the filter requirements.

The ElementType Topic

The ElementType / NotElementType can be a little confusing at first… There are two filters, the short-hand versions are:

  • WhereElementIsElementType()
  • WhereElementIsNotElementType()

What is ElementType? This is the renamed Symbol class in the API (re-named to match better what interactive users call things). So an “ElementType” refers to a symbol/type/definition kind of thing (a “block definition” for you AutoCAD-types). Something which is “Not an ElementType”, on the other hand – is typically something which is physically IN the model – like a specific door, line, or wall. Technically it’s a bit more broad – because it also includes items like views, etc.

That said – these two can be key filters to use to distinguish between whether you want Doors vs. Door Types, for example.

What’s the Deal with Rooms/Areas/Spaces/Tags?

Here’s a place where Autodesk’s new strategy of matching up more closely with the internal API will cause you a little bit of hassle. With Rooms/Areas/Spaces and their tags (as well as about 9 other types – see the API Introduction for the list) – there is no internal Revit type which matches them.

For example, if you look at the Room class in the 2011 API, you’ll see that it is actually a descendant of the Enclosure Class. Enclosure covers Rooms, Spaces, and Areas… Here’s the trick – Revit’s internals are obviously modeled on the “Enclosure” class – so if you’re querying by type – you can’t query on
typeof( Room ), for example.

There are some specially designed filters to compensate for this – like RoomFilter, AreaFilter, SpaceFilter, etc… These would be called as follows:

coll.WherePasses( new RoomFilter() );

The WherePasses method is another mechanism for specifying filters – you can use any filter with it.

Final Requirements of the Filter

Ok, ok – we’re almost to the payoff… But one thing I should note before we go on… If you’re used to being able to just query the whole model (for whatever reason) – you’ll find that a little bit tricky with this mechanism… Why? Because the rule is that after you construct the collector – you MUST apply at least one filter before you attempt to retrieve from it. You can’t (easily) just retrieve everything.

The closest I’ve come to it is:

// get EVERYTHING – like in the bad-old-days…
// get all the ElementTypes + all the non-ElementTypes
coll.WhereElementIsElementType().UnionWith( new
         ElementIsElementTypeFilter( false ) );


Finally – Retrieving from the Filter

Sorry to make you go through all this to get to the good part! Once you have constructed your collector and applied filter(s), then it’s time to request the contents of the collector and see what you get. Autodesk has really done a nice job of implementing some .NET 3.5 goodies here, so there are a variety of options.

coll.ToElements(); Return an IList<Element> of the contents.
coll.ToElementIds(); Return an ICollection<ElementId> of the contents.
coll.FirstElement() Return the first Element found that matches.

But that’s only the first part – the other thing I love is that the .NET 3.5 tricks that get around another annoyance – that these query routines return pointers to “Element” – which you immediately have to convert/cast down into, say “Room” to be able to easily access the properties and methods of that class.

// get all the wall types as wall type objects:
coll.OfClass (typeof(WallType));
IEnumerable<WallType> types = coll.Cast<WallType>();

foreach (WallType wt in types )
{
    // do something with the wall type
}

 

Using with LINQ

Because the FilteredElementCollector supports the IEnumerable interface – it easily  can make the jump to LINQ – being able to write full-fledged queries directly in code.

This looks something like:

FilteredElementCollector coll = new FilteredElementCollector(doc);
coll.OfClass(typeof(WallType));

var bigEnoughWallTypes =
from element in coll
where element.get_Parameter(BuiltInParameter.WALL_ATTR_WIDTH_PARAM).AsDouble() > 0.5 &&
   element.get_Parameter(BuiltInParameter.FUNCTION_PARAM).AsInteger() == 1
                         select element;

IEnumerable<WallType> types = bigEnoughWallTypes.Cast<WallType>();

ok, so the thin screen doesn’t lend itself to this… In any case – it’s not magic, it’s nothing you couldn’t have done before – but it DOES make your code a bit tighter and arguably easier to maintain because it’s clear what you’re doing (as opposed to doing the same thing in a query then loops with if statements).

The Final Analysis

In the final analysis – the new FilteredElementCollector is a fantastic new way of accessing data within Revit. It does take a little bit of adjustment, but once you’re there, I’d say it’s nicer than what existed before – and it has nice room to grow.

I still need to run the new things through a performance test (my impression is that they run faster than their 2010 equivalents – but I haven’t put a stopwatch to it yet). This post is already too long – so I’ll save that for another post…