In the previous post, we determined the slab boundary polygons and displayed the resulting polygon data graphically for debugging and better understanding by creating model line segments for them in the Revit database. We did not go into any detail about the code to create those model lines, which is an interesting little topic all in itself. It is packaged in a utility class named Creator, since it encapsulates a small subset of the functionality provided by the Autodesk.Revit.Creation namespace. This post presents and discusses this model line creator. Here is the code for it:
class Creator { // these are // Autodesk.Revit.Creation // objects! Application _app; Document _doc; public Creator( Autodesk.Revit.Application app ) { _app = app.Create; _doc = app.ActiveDocument.Create; } SketchPlane NewSketchPlanePassLine( Line line ) { XYZ p = line.get_EndPoint( 0 ); XYZ q = line.get_EndPoint( 1 ); XYZ norm; if( p.X == q.X ) { norm = XYZ.BasisX; } else if( p.Y == q.Y ) { norm = XYZ.BasisY; } else { norm = XYZ.BasisZ; } Plane plane = _app.NewPlane( norm, p ); return _doc.NewSketchPlane( plane ); } void CreateModelLine( XYZ p, XYZ q ) { if( p.AlmostEqual( q ) ) { throw new ArgumentException( "Expected two different points." ); } Line line = _app.NewLine( p, q, true ); if( null == line ) { throw new Exception( "Geometry line creation failed." ); } _doc.NewModelCurve( line, NewSketchPlanePassLine( line ) ); } public void DrawPolygons( List<List<XYZ>> loops ) { XYZ p1 = XYZ.Zero; XYZ q = XYZ.Zero; bool first; foreach( List<XYZ> loop in loops ) { first = true; foreach( XYZ p in loop ) { if( first ) { p1 = p; first = false; } else { CreateModelLine( p, q ); } q = p; } CreateModelLine( q, p1 ); } } }
This code and the idea to create these kind of model lines for debugging purposes is actually demonstrated by the Revit SDK sample Openings, in its module BoundingBox.cs, which implements the two methods NewSketchPlanePassLine() and NewModelLine(), upon which the methods defined above are based.
Some things to note about this code:
The creation of new instances of many Revit API classes is not performed by the standard constructur, but by special Revit API classes and their methods in the Autodesk.Revit.Creation namespace. The two most important classes defined in the namespace are Application and Document. Note that these are completely different classes than the ones with the same names in the Autodesk.Revit namespace. The latter refer to the normal Revit application and document, whereas the former are used exclusively to instantiate new Revit API object instances. As the help file puts it, the Application creation object is used to create new instances of utility objects, and the Document creation object is used to create new instances of elements within the Autodesk Revit project.
The creation of a Revit database element is often a two-step process: first a geometry object is created to define its geometrical properties, and then a database object is created from that. The geometrical object is memory resident and independent of the database, so it is instantiated by the application creation object. The database object needs to be properly hooked up with the rest of the database, so obviously requires the document creation object. These two objects are stored in the private member variables _app and _doc, and set up by the constructor. Repeat: these are not instances of the Application and Document objects from the Autodesk.Revit namespace, but from the Autodesk.Revit.Creation one.
Revit elements are often linked to other database objects. In this case, the creation of a model line requires a sketch plane to reside on. The sketch plane must contain the line, otherwise unexpected behaviour might occur. To keep it simple, we create a separate sketch plane for every single model line, to ensure that this requirement is fulfilled, using NewSketchPlanePassLine().
Finally, we have the method DrawPolygons(), which is actually custom designed to handle the polygonal slab boundary loop data that we assembled in CmdSlabBoundary, but we have still kept it as generic as possible.
I find the creation of model lines for debugging purposes an efficient way to better understand what my code is actually doing. It is much more reliable to look at these graphical helper objects than try to read and analyse raw coordinate data.
Hello,
beautiful site!
We are trying to publish some code from Revit VSTA in our webiste, so I wanted to know how were you able to find the RSS class that shows it with proper colors and indents...
It is available somewhere?
Thank you in advance for your answer,
Stefano
Posted by: Stefano | January 15, 2009 at 11:21
Dear Stefano,
Thank you for the 'beautiful' attribute.
I guess what you mean is how do I format my blog posts so that the source code is displayed nicely and with colour coding? That has nothing to do with RSS at all. I edit my posts manually in HTML. To obtain the colour coding, I make use of the functionality provided by Visual Studio. In addition, I installed a Visual Studio plug-in to copy the selected code snippet as HTML. It adds support to Visual Studio 2005 for copying source code, syntax highlighting, and line numbers as HTML. I insert the clipboard contents into my HTML blog text and that's it, more or less. I also tried to use some other code colouring systems that are independent of Visual Studio. They also work, but they only colour code the C# keywords, not the classes defined in other namespaces, because they do not actually load and analyse the contents of those other namespaces. That is why I ended up using the Visual Studio plug-in after all, in spite of trying to solve the problem myself externally. Simply search on the web for keywords such as "visual studio copy as html". This will probably not work in VSTA, although I am not sure.
Cheers, Jeremy.
Posted by: Jeremy Tammik | January 15, 2009 at 12:17
Dear Jeremy,
As in DrawPolygons() method of current post, polygons are being drawn using different lines. I am also drawing the polygon like this o nly.
In Revit User Interface, we can draw a polygon like triangle etc. by selecting polygon from model line Draw option.But is there any api method to draw the entire polygon as a single curve instead of set of lines.
Kind Regards,
Shifali
Posted by: shifali | January 08, 2010 at 03:55
Dear Shifali,
Look at such a triangle through the API. What do you see? Is it not composed of individual model lines?
Cheers, Jeremy.
Posted by: Jeremy Tammik | January 08, 2010 at 04:07
Dear Jeremy,
Thanks a lot for your reply.
In Revit User Interface, no doubt the triangle/any polygon is composed of model lines only. That means we can not draw a polygon as a single curve?
Actually my issue is I need to consider this polygon which is being drawn by set of lines as a single curve object. Can we do so?
Regards,
Shifali
Posted by: shifali | January 08, 2010 at 05:04
Dear Shifali,
As said, I see no methods in the Revit API to draw collections of individual model curves to be united into one single object.
You could try creating a group out of them, if that is of any help.
You are of course free to consider the resulting polygon as anything you please :-)
Cheers, Jeremy.
Posted by: Jeremy Tammik | January 13, 2010 at 09:41
Hi Jeremy,
I'm trying to alter the above code to work with 2011 but I keep getting the following error
"Curve must be in the plane parameter name pCurveCopy" this error has me stumped
Thanks
Anthony
---------------------------------------------------
Private Function NewSketchPlanePassLine(ByVal line As Line) As DB.SketchPlane
Dim aps As Document = globalcdata.Application.ActiveUIDocument.Document
Dim app As Autodesk.Revit.ApplicationServices.Application = aps.Application
Dim p As DB.XYZ = line.EndPoint(0)
Dim q As DB.XYZ = line.EndPoint(1)
Dim norm As DB.XYZ
If p.X = q.X Then
norm = DB.XYZ.BasisX
ElseIf p.Y = q.Y Then
norm = DB.XYZ.BasisY
Else
norm = DB.XYZ.BasisZ
End If
Dim plane As DB.Plane = app.Create.NewPlane(norm, p)
'plane = Autodesk.Revit.Creation.Application.NewPlane(norm, p)
Return aps.Create.NewSketchPlane(plane)
End Function
Private Sub CreateModelLine(ByVal p As DB.XYZ, ByVal q As DB.XYZ)
Dim aps As Document = globalcdata.Application.ActiveUIDocument.Document
Dim app As Autodesk.Revit.ApplicationServices.Application = aps.Application
If p.IsAlmostEqualTo(q) Then
Throw New ArgumentException("Expected two different points.")
End If
Dim line As Line = app.Create.NewLine(p, q, True)
If line Is Nothing Then
Throw New Exception("Geometry line creation failed.")
End If
aps.Create.NewModelCurve(line, NewSketchPlanePassLine(line))
End Sub
Posted by: Anthony | August 09, 2010 at 02:29
Dear Anthony,
Please have a look at this post:
http://thebuildingcoder.typepad.com/blog/2010/05/detail-curve-must-indeed-lie-in-plane.html
You should be able solve your issue using the NewSketchPlaneContainCurve method described in
http://thebuildingcoder.typepad.com/blog/2010/05/model-curve-creator.html
By the way, you seem to be obtaining your two line endpoints p and q from an existing line in the first two lines of code. You then proceed to create a new line using the same points. That seems like a waste of effort to me. Finally, you create a model curve based on the latter. Maybe all of that can be achieved in one fell swoop using the CreateModelCurve method I present in the latter post.
Please let us know whether it works. Thank you!
Cheers, Jeremy.
Posted by: Jeremy Tammik | August 09, 2010 at 05:30
Hi Jeremy,
Billiant, My app now works perfectly.
I'm generating some model lines from a topo surface, this enables our users to edit the top of retaining walls etc to follow the ground line cut away by building pads.
See link below for finished code.
http://forums.augi.com/showthread.php?p=1089399#post1089399
Thanks Anthony
Posted by: Anthony | August 09, 2010 at 17:17
Dear Anthony,
Thank you very much for the appreciation and sharing your solution. For easy and complete access, I posted it as well, with the source code that you friendlily provided:
http://thebuildingcoder.typepad.com/blog/2010/08/surface-triangulation-tool.html
Cheers, Jeremy.
Posted by: Jeremy Tammik | August 12, 2010 at 04:36
Dear Jeremy,
Please help me!
How to get area from some points(some Edges)?
or how go create a Face from some points(some Edges)?
I'm a beginner and it's easy with.
Posted by: Fizze | October 03, 2010 at 23:32
Dear Jeremy,
Please help me!
How to get area from some points(some Edges)?
or how to create a Face from some points(some Edges)?
I'm a beginner and it's easy with.
Posted by: Fizze | October 03, 2010 at 23:33
Dear Fizze,
When you say 'get area', do you mean calculate the area? That is a common algorithm which I implemented in the method GetSignedPolygonArea presented in
http://thebuildingcoder.typepad.com/blog/2008/12/2d-polygon-areas-and-outer-loop.html
You cannot create a Face instance yourself, because it is basically a read-only object returned by the Revit geometry library when you query existing building elements for their geometry.
Cheers, Jeremy.
Posted by: Jeremy Tammik | October 04, 2010 at 04:16
How to set the hidden parameter in modelCurve
Posted by: Joseph | April 01, 2011 at 10:58
Dear Joseph,
The same way as in any other element: Parameter.Set.
Cheers, Jeremy.
Posted by: Jeremy Tammik | April 01, 2011 at 12:04
any complete VisualStudio project for creating a 3D model for analysis in Vasari 2.1!?
thank you!
Posted by: Nelson Silva | March 07, 2012 at 05:38
Dear Jeremy,
I'm trying to use this class inside a Revit 2014 Macro, and I'm getting a lot of reference errors and warnings.
Being a complete newbie in this field, I feel lost.
Does this code still apply to 2014 API or should something be changed for it to work?
Posted by: Samer Najjar | March 05, 2014 at 01:27
Dear Samer,
As you can see for yourself above, this code was published in 2008.
It needs adapting to run on Revit 2014.
However, the Creator class introduced and listed above is included in The Building Coder samples, and they are up to date on GitHub:
https://github.com/jeremytammik/the_building_coder_samples
Cheers, Jeremy
Posted by: Jeremy Tammik | March 19, 2014 at 17:24
Is this works in Revit 2015?
Posted by: ananda ns | March 01, 2015 at 23:51
Dear Ananda,
Yes, sure. Just grab the most up-to-date version of The Building Coder samples, get going, and have fun!
Cheers, Jeremy.
Posted by: Jeremy Tammik | March 10, 2015 at 11:07