Revit 2013 has been released, and I presented an overview of the Revit 2013 API two days ago.
As always, the use of most of the API features is demonstrated by various SDK samples. For a better understanding of the use and contents of the Revit SDK in general, please refer to the getting started and self-preparation guides.
Here is an overview of the new samples:
- ModelessForm_ExternalEvent and ModelessForm_IdlingEvent (ModelessDialog)
- ProgressNotifier (Events)
- RoutingPreferenceTools
- UIAPI
- WorkThread (MultiThreading)
These samples are all related to the new add-in integration functionality, except for the RoutingPreferenceTools which obviously demonstrate some of the MEP related enhancements.
By the way, the 'VSTA Samples' folder was renamed to 'Macro Samples' since VSTA was replaced by the open source SharpDevelop IDE.
ModelessForm_ExternalEvent and ModelessForm_IdlingEvent
Both of these display and show how to interact with a modeless form. One way to do this is to use the Idling event initially provided in Revit 2012, which we have discussed so much and in such depth in the past.
The ModelessForm_IdlingEvent sample should clarify many of the issues we dealt with, and is also related the material presented by Arnošt Löbel in his Autodesk University 2011 class CP5381 on asynchronous interactions and managing modeless UI.
The ModelessForm_ExternalEvent sample demonstrates an easier way to implement this interaction using the new external event interface.
ProgressNotifier
The ProgressNotifier sample displays progress information for an action in a stack data structure for easier analysis. It demonstrates how to subscribe to the ProgressNotify related events, access properties in the event handler arguments, and organize the subtransaction progress information into a stack.
RoutingPreferenceTools
The RoutingPreferenceTools sample provides a number of MEP pipe routing preference tools.
This sample contains three commands, one for analysis and reporting purposes, two for importing and exporting routing preferences to XML:
- Routing Preference Analysis: Analyze the routing preferences of a given pipe type to check for common problems, using the routing preferences API to look at all rules and criteria for a given PipeType.
- Routing Preference Builder with its two commands CommandReadPreferences and CommandWritePreferences: Set pipe type, fitting, and routing preferences in a project from data in an XML file and export these preferences to XML for archival, documentation, and collaboration purposes, allowing a user to work with routing preference data in a shareable XML format suitable for reuse in a wide variety of BIM management environments.
UIAPI
The UIAPI sample demonstrates a number of the new add-in integration API features that I already listed, including embedding a Revit view as WPF control inside its own dialogue, the new drag and drop API, and the Options dialogue support for custom extensions using arbitrary WPF components. This sample was also shown at the DevDays 2011 conferences.
WorkThread
The WorkThread sample demonstrates utilizing the Idling event in a multi-threaded application to communicate with the Revit API from an external work thread.
Congratulations to the Revit API team for an outstanding release :)
Posted by: Phillip Miller | April 01, 2012 at 18:32
Hello, Jeremy.
In Revit 2013 API added new class - DataStorage - an element which provide storage for entities with any data for whole project. But there are no examples to demonstrate how does it work and how to use it properly.
I think it would be perfect if you explain it.
Best regards, Victor.
Posted by: Account Deleted | April 02, 2012 at 01:13
Dear Phillip,
Thank you for your appreciation! I forwarded it to the whole team.
Cheers, Jeremy.
Posted by: Jeremy Tammik | April 02, 2012 at 05:25
Dear Victor,
It should be straightforward enough. Just look at the description of the DataStorage class and the DataStorage.Create method in the Revit API help file RevitAPI.chm.
If you have a minimal sample up and running and any additional interesting insights, I'll happily post them.
Cheers, Jeremy.
Posted by: Jeremy Tammik | April 02, 2012 at 05:30
Hello, Jeremy.
I've already tried to use it. As I understand, DataStorage is a very simple element which can have one ore more Entity. That was easy to create it. But how can I retrieve entity from DataStorage. I.e. how to get DataStorage from Document?
I think to use FilteredElementCollector to retrieve DataStorage Elements in document. But what if I want to have two ore more DataStorages in document, how can I differ them? Set parameter or additional entity with some unique attribute?
Best regards, Victor.
Posted by: Account Deleted | April 02, 2012 at 05:51
Dear Victor,
Yes, that thought did cross my mind, or my subconscious, as I was answering you, and in the past as well when looking at this topic...
Thank you for bringing it out into the open.
I guess yes, using a parameter, or the element id, or the unique id. Lots of options. Have a play around with it, let us know what you find out, raise an ADN case if you run into trouble, and we'll publish the result asap, ok?
I mean, for instance, you could simply put a descriptive comment into the 'Comment' parameter and use that to search for it. That should be very simple and foolproof, should work, and you could use regular expressions for complex searches over large numbers of DataStorage elements, if you insist, which I hope you will not :-)
Cheers, Jeremy.
Posted by: Jeremy Tammik | April 02, 2012 at 05:58
Ok. I'll try to explore features of DataStorage and write a little post about it)
Best regards, Victor.
Posted by: Account Deleted | April 02, 2012 at 06:18
Hi Jeremy..
I am trying to create NewFamilyInstance using NewFamilyInstance Method (Reference, Line, FamilySymbol) constructor. sample code...
LocationCurve wallCurve = wall.Location as LocationCurve;
XYZ startPt = wallCurve.Curve.get_EndPoint(0);
XYZ endPt = wallCurve.Curve.get_EndPoint(1);
XYZ dir = endPt - startPt;
XYZ cutVec = dir.CrossProduct(XYZ.BasisZ);
ReferencePlane rp = doc.Create.NewReferencePlane(startPt, endPt, cutVec, doc.ActiveView);
famIns = doc.Create.NewFamilyInstance(rp.Reference, Line.get_Bound(startPt, endPt), familySymbol);
Revit shows error "Family cannot be placed on this line as it does not coincide with the input face."
But in Revit 2012, it works fine.
Is there any change in NewRefPlane() or NewFamilyInst() internally in revit 2013?
If any please share any sample..
Thanks..
Posted by: sangsen | April 10, 2012 at 08:11
Dear Sangsen,
Two things strike me here.
1. I don't know whether your NewReferencePlane bubble end, free end and cut vector arguments make sense like that. Are you sure they are appropriate?
2. How does the active view relate to these three points?
I am not aware of any changes, but there have been methods in past API updates whose argument checking was more strictly enforced and thus stopped working as previously, e.g.
http://thebuildingcoder.typepad.com/blog/2010/05/detail-curve-must-indeed-lie-in-plane.html
Cheers, Jeremy.
Posted by: Jeremy Tammik | April 17, 2012 at 05:08
Hi Jeremy,
First thank you for this wonderful blog.
With the 2012 API I used PipeSizeSettings listPipeSizeSettings = PipeSizeSettings.GetPipeSizeSettings(document) to get the list of PipeSize, but I can not find PipeSizeSettings in 2013 API.
Have you an idea how to do that?
Thank you
Posted by: Fre | May 15, 2012 at 07:51
Dear Fre,
Thank you for your appreciation!
I think the new routing preferences classes replace the Revit 2012 PipeSizeSettings class.
Look at the RoutingPreferenceTools sample mentioned above:
http://thebuildingcoder.typepad.com/blog/2012/03/new-revit-2013-sdk-samples.html#3
Please let me know how you end replacing your code.
Thank you.
Cheers, Jeremy.
Posted by: Jeremy Tammik | May 16, 2012 at 07:04
I am having problems with Revit MEP 2013, I can not edit any fire pipes and when ever I try the program just hangs and evntually I have to restart. When I was using Revit MEP 2012 this never happened.
Posted by: Innocent Svodziwa | November 28, 2012 at 05:13
Dear Innocent,
Sorry, to hear that. Sorry, I cannot help. I do not deal with product issues at all.
Cheers, Jeremy.
Posted by: Jeremy Tammik | November 28, 2012 at 08:27
Dear Jeremy,
I played a little bit with the PreviewControl in a modal Dialog. I changed the orientation of a perspective View3d with a user input (a trackbar) in that PreviewControl but I have problems to redraw the PreviewControl! The changes are only visible after clicking with the mouse on the control and scrolling with the mouse wheel! Is their a possible to redraw the PrieviewControl automatically?
Jörg
Posted by: Jörg Braunes | August 30, 2013 at 07:11
Dear Jörg,
Sorry, I have no idea why you should be seeing that kind of behaviour. Never heard of it before. No, there is no way to redraw the control. That should happen automatically. Afaik, your only way to influence it is to dispose of it and re-instantiate a new instance.
By the way, here is the most recent discussion related to this topic:
http://thebuildingcoder.typepad.com/blog/2013/08/issue-using-a-preview-control-in-a-macro.html
Cheers, Jeremy.
Posted by: Jeremy Tammik | August 30, 2013 at 07:28
I was looking for a list of pipe sizes in a project and thought I would let you know what I used:
private void GetPipeSegmentSizesFromDocument(Document document)
{
FilteredElementCollector collectorPipeType = new FilteredElementCollector(document);
collectorPipeType.OfClass(typeof(Segment));
IEnumerable segments = collectorPipeType.ToElements().Cast();
foreach (Segment segment in segments)
{
StringBuilder strPipeInfo = new StringBuilder();
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\REVIT\WriteLines.txt", true))
{
file.WriteLine(Convert.ToString(segment.Name));
}
foreach (MEPSize size in segment.GetSizes())
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\REVIT\WriteLines.txt", true))
{
file.WriteLine(Convert.ToString(Math.Round(size.NominalDiameter * 25.4 * 12, 0)) + " " + Convert.ToString(Math.Round(size.InnerDiameter * 25.4 * 12, 0)) + " " + Convert.ToString(Math.Round(size.OuterDiameter * 25.4 * 12, 0)));
}
}
}
}
Posted by: Drew | January 26, 2015 at 16:27
Dear Drew,
Thank you very much for sharing this!
It looks perfect: succinct, effective, easy.
I will happily promote this little sample snippet to a main blog post to ensure that it is easy to find.
Cheers, Jeremy.
Posted by: Jeremy Tammik | January 27, 2015 at 09:19
Dear Drew,
I just noticed that a code snippet very similar to yours is also provided in the Revit API help file RevitAPI.chm description of the Segment class.
Cheers, Jeremy.
Posted by: Jeremy Tammik | January 27, 2015 at 10:34
Dear Drew,
I added the code as a new external command to The Building Coder samples:
http://thebuildingcoder.typepad.com/blog/2015/02/list-pipe-sizes-and-more-obsolete-api-usage-removal.html
Thank you!
Cheers, Jeremy.
Posted by: Jeremy Tammik | February 02, 2015 at 06:05