Autocad Civil There Are No Tin Surfaces on the Drawing
Time flies when you are busy, and this week between holidays and all the work we are doing, I didn't have much time to work on the installment of the "21 Weeks of Jay Peak". Still, I didn't want to let the week go by without some good material. Thankfully, Augusto came up with a great article that demonstrates how to find the closest point in a Surface to another point outside of the Surface.
It seems that some of you have asked about this in the past, and now it is a good chance to take a look at Augusto's post about it. Always good stuff coming from those ADN guys.
I am very happy to introduce the new, updated Civil 3D API Reference Guide. The new Reference Guide is the result of many months of work trying to improve the entire experience and make us more efficient in order to provide the best possible documentation. Is it perfect? No. But it is a big step forward that will allow us to work efficiently and be able to improve the documentation at a faster pace.
For the past few months, we have been researching tools that will allow us to improve the process of generating the documentation. We have established processes to create, review, and produce the materials that we will expose to you. And, we will keep working to make the experience even better.
It has been a lot of work and many people involved to get us to this point, but things will just get better moving forward. I want to thank everyone involved in this project, from the technical writers, to the UX engineers, and the development and QA team who also participated in the process. Great job everyone!
Update: Apparently, I was too quick posting about this. The updated version was still sitting on the Staging Servers waiting for us to give the OK to go live, which explains why I was able to access it, but not you. We are pushing it live now, and it takes around 24 hours for the new content to be cached around the globe; therefore, you should be able to start accessing it tomorrow January, 6th. I will update this post when we are sure the docs are live, and sorry for the inconvenience.
Again, I have to thank Drew Avis for feeding me blog material. He sent me some code for a very handy utility that automates the process of turning display representations on and off in a style. In his sample, he uses the surface style, but this technique can be applied to any of the Civil 3D styles.
Style objects expose display components that can be turned on and off either of the plan and model views. This functionality is available through the style methods 'GetDisplayStylePlan()' and 'GetDisplayStyleModel()', and both return a 'DisplayStyle' object representing a display component which exposes a 'Visible' property to get and set the state. To access each of the supported display representations, the API provides an enum type for each of the individual styles.
In this example, we will use the surface style. The surface style is represented through the 'SurfaceStyle' class, and the supported display representations are defined in the 'SurfaceDisplayStyleType' enum. We create an array of 'SurfaceDisplayStyleType' values to store the display representations we will like to turn on. Then we will apply those settings to the style. (I omitted how the style object is accessed for clarity, but the full source code is available for download in C# and VB.NET versions).
C#
using (Transaction tr = startTransaction())
{
SurfaceStyle style = styleId.GetObject(OpenMode.ForWrite)
as SurfaceStyle;
SurfaceDisplayStyleType[] settings =
new SurfaceDisplayStyleType[]
{
SurfaceDisplayStyleType.MajorContour,
SurfaceDisplayStyleType.MinorContour,
SurfaceDisplayStyleType.Points,
SurfaceDisplayStyleType.Triangles
};applySettings(style, settings);
tr.Commit();
}
VB.NET
Using tr As Transaction = startTransaction()
Dim style As SurfaceStyle =
TryCast(styleId.GetObject(OpenMode.ForWrite), SurfaceStyle)
Dim settings As SurfaceDisplayStyleType() =
New SurfaceDisplayStyleType() _
{
SurfaceDisplayStyleType.MajorContour,
SurfaceDisplayStyleType.MinorContour,
SurfaceDisplayStyleType.Points,
SurfaceDisplayStyleType.Triangles
}applySettings(style, settings)
tr.Commit()
End Using
As you can see, we open the style for write and we create an array of 'SurfaceDisplayStyleType' values adding the representations we will like to turn on. The 'applySettings()' method is the one that does the work, and you can see the implementation here.
C#
private void applySettings(SurfaceStyle style,
IList<SurfaceDisplayStyleType> settings)
{
IEnumerable<SurfaceDisplayStyleType> displayTypes =
Enum.GetValues(typeof(SurfaceDisplayStyleType))
as IEnumerable<SurfaceDisplayStyleType>;foreach (SurfaceDisplayStyleType displayType in displayTypes)
{
bool state = settings.Contains(displayType);
style.GetDisplayStylePlan(displayType).Visible = state;
style.GetDisplayStyleModel(displayType).Visible = state;
}
}
VB.NET
Private Sub applySettings(style As SurfaceStyle, _
settings As IList(Of SurfaceDisplayStyleType))
Dim displayTypes As IEnumerable(Of SurfaceDisplayStyleType) =
TryCast([Enum].GetValues(GetType(SurfaceDisplayStyleType)),
IEnumerable(Of SurfaceDisplayStyleType))For Each displayType As SurfaceDisplayStyleType In displayTypes
Dim state As Boolean = settings.Contains(displayType)
style.GetDisplayStylePlan(displayType).Visible = state
style.GetDisplayStyleModel(displayType).Visible = state
Next
End Sub
The 'applySettings()' method retrieves all the enum values defined in 'SurfaceDisplayStyleType' and loops through them. If the value is contained in the settings collection, it means that we want to turn it on. We do so by getting the display representation (DisplayStyle) in plan and model and setting its 'Visible' property to true. If the value is not contained in the settings collection, the 'state' variable is set to false, and so it is the 'Visible' property of the display representation.
This is a very handy technique that can save a lot of time when several styles need to be modified, but it also demonstrates the use of the style objects and their display representations. Thanks again to Drew for providing me with this code.
P.S. You can download the entire source for Civilized Development from its BitBucket repository or by cloning the repository with mercurial using the command: "hg clone https://bitbucket.org/IsaacRodriguez/civilizeddevelopment "
After reviewing the sample code I have been generating for this blog, it has become obvious that there is certain functionality that is being used in every single example. When I started the blog, my goal was to start putting common functionality and reusable code into the Colibra library, so my readers and my-self can benefit from it. Don't worry, Colibra still a go, and I will be extending the functionality and posting it here.
But there is some other repetitive code that I need to include in every example. It is so simple that it is not worth the effort to abstract it and make it part of Colibra, but it is so useful, that I end-up including it with every post.
In order to avoid code duplication, I created a base class 'SimpleDrawingCommand' that implements methods and properties I use in most posts. These are properties to access the Document or Database objects, or methods that perform simple functionality like start a new transaction. I am sure, as I create new samples, the functionality of this class will be extended, and I'll make sure I make it available.
Here is the code for this simple base class, and I hope you find it useful in your short scripts:
C#
/// <summary>
/// Base class for simple command classes that implement commands
/// that access a single drawing. This class implements an interface
/// with basic, redundant functionality that derived classes can
/// leverage to simplify coding.
/// </summary>
public class SimpleDrawingCommand
{
/// <summary>
/// Returns the document object from where the command was
/// launched.
/// </summary>
protected Document _document
{
get
{
return Application.DocumentManager.MdiActiveDocument;
}
}/// <summary>
/// Return the Civil 3D Document instance.
/// </summary>
protected CivilDocument _civildoc
{
get
{
return CivilApplication.ActiveDocument;
}
}/// <summary>
/// Returns the current database from where the command
/// was launched.
/// </summary>
protected Database _database
{
get
{
return _document.Database;
}
}/// <summary>
/// Returns the Editor instance for the current document.
/// </summary>
protected Editor _editor
{
get
{
return _document.Editor;
}
}/// <summary>
/// Starts a new transaction in the current database.
/// </summary>
/// <returns></returns>
protected Transaction startTransaction()
{
return _database.TransactionManager.StartTransaction();
}/// <summary>
/// Writes the specified message to the Editor output window.
/// </summary>
/// <param name="message"></param>
protected void write(string message)
{
_editor.WriteMessage(message);
}
}
VB.NET
''' <summary>
''' Base class for simple command classes that implement commands
''' that access a single drawing. This class implements an interface
''' with basic, redundant functionality that derived classes can
''' leverage to simplify coding.
''' </summary>
Public Class SimpleDrawingCommand
''' <summary>
''' Returns the document object from where the command was
''' launched.
''' </summary>
Protected ReadOnly Property _document() As Document
Get
Return Application.DocumentManager.MdiActiveDocument
End Get
End Property''' <summary>
''' Return the Civil 3D Document instance.
''' </summary>
Protected ReadOnly Property _civildoc() As CivilDocument
Get
Return CivilApplication.ActiveDocument
End Get
End Property''' <summary>
''' Returns the current database from where the command
''' was launched.
''' </summary>
Protected ReadOnly Property _database() As Database
Get
Return _document.Database
End Get
End Property''' <summary>
''' Returns the Editor instance for the current document.
''' </summary>
Protected ReadOnly Property _editor() As Editor
Get
Return _document.Editor
End Get
End Property''' <summary>
''' Starts a new transaction in the current database.
''' </summary>
''' <returns></returns>
Protected Function startTransaction() As Transaction
Return _database.TransactionManager.StartTransaction()
End Function''' <summary>
''' Writes the specified message to the Editor output window.
''' </summary>
''' <param name="message"></param>
Protected Sub write(message As String)
_editor.WriteMessage(message)
End Sub
End Class
As the class name implies, this should serve as base class for Command Classes that only access the current active drawing and are used as simple scripts. If you are doing more involved development, you should spend some time thinking about the abstraction you should provide in your application to achieve a more solid solution.
Augusto Goncalves, Senior Developer Consultant at ADN, has created a nice little tool that should come very helpful for developers and customers of Civil 3D. The tool currently works with AutoCAD Civil 3D 2012, and uses the API to grab information about the objects in a drawing. Here is the information about the tool, as well as the links to download the binaries and the source code.
Snoop Civil3D 2012 Database is now Live in Civil 3D Developer Center Page http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=8007696
This tool allows developers inspect the Civil3D Database without writing code. Everything that is shown is accessible through the API, but this tool does not show everything is accessible on the API. It works by showing the root objects of Civil3D 2012 (i.e. Styles, Alignments, Corridors, Assemblies, Subassemblies, Pipe networks and Surfaces) listing them on the left with all objects on each collections, such as all alignments on the active drawing, and once click on each item, list all its properties on right. To use this tool, start AutoCAD Civil 3D 2012, type NETLOAD at the command line and load the 'SnoopCivil3DObjects.dll'. Run snoopCivil3DDB command. Once the DLL is loaded, you can invoke the command from right mouse click 'Snoop Civil3D'.
SnoopCivil3DTool | SnoopCivil3DVSProj
Give it a shot and let us know how you like it.
Mr. Avis is on a roll. He not only co-author a previous post (Using Water-drops to Analyze Rainfall), he has now provided me with a very simple, easy to follow snippet of code that demonstrates how to create new elevation ranges in surfaces through the new .NET API. The command is very simple. It prompts the user for a TIN surface object and then calls a method to create the elevation regions. Here is the code:
C#
public void CDS_CreateElevationRanges() { AcadDb.ObjectId surfaceId = promptForTinSurface(); if (surfaceId == AcadDb.ObjectId.Null) { return; } using (AcadDb.Transaction tr = startTransaction()) { TinSurface surface = surfaceId.GetObject(AcadDb.OpenMode.ForWrite) as TinSurface; // Get the existing analysis, if any. SurfaceAnalysisElevationData[] data = surface.Analysis.GetElevationData(); _editor.WriteMessage("\nExisting analysis length: {0}", data.Length); SurfaceAnalysisElevationData[] newData = CreateElevationRegions(surface, 10, 100); surface.Analysis.SetElevationData(newData); tr.Commit(); } }
VB.NET
Public Sub CDS_CreateElevationRanges() Dim surfaceId As AcadDb.ObjectId = promptForTinSurface() If surfaceId = AcadDb.ObjectId.Null Then Return End If Using tr As AcadDb.Transaction = startTransaction() Dim surface As TinSurface = _ TryCast(surfaceId.GetObject(AcadDb.OpenMode.ForWrite), _ TinSurface) ' Get the existing analysis, if any. Dim data As SurfaceAnalysisElevationData() = _ surface.Analysis.GetElevationData() _editor.WriteMessage(vbLf & "Existing analysis length: {0}", _ data.Length) Dim newData As SurfaceAnalysisElevationData() = _ CreateElevationRegions(surface, 10, 100) surface.Analysis.SetElevationData(newData) tr.Commit() End Using End Sub
The nuts and bolts is the 'CreateElevationRegions()' method, which calculate the ranges based on the number of steps passed, creates the elevation data, and sets the color for each of the ranges. The implementation looks like this:
C#
private SurfaceAnalysisElevationData[] CreateElevationRegions( Surface surface, int steps, short startColor) { GeneralSurfaceProperties props = surface.GetGeneralProperties(); double minElevation = props.MinimumElevation; double maxElevation = props.MaximumElevation; double increment = (maxElevation - minElevation) / steps; SurfaceAnalysisElevationData[] newData = new SurfaceAnalysisElevationData[steps]; for (int i = 0; i < steps; i++) { Color color = Color.FromColorIndex(ColorMethod.ByLayer, (short)(100 + (i * 2))); newData[i] = new SurfaceAnalysisElevationData( minElevation + (increment * i), minElevation + (increment * (i + 1)), color); } return newData; }
VB.NET
Private Function CreateElevationRegions(surface As Surface, _ steps steps As Integer, _ startColor startColor As Short) _ As SurfaceAnalysisElevationData() Dim props As GeneralSurfaceProperties = _ surface.GetGeneralProperties() Dim minElevation As Double = props.MinimumElevation Dim maxElevation As Double = props.MaximumElevation Dim increment As Double = (maxElevation - minElevation) / steps Dim newData As SurfaceAnalysisElevationData() = _ New SurfaceAnalysisElevationData(steps - 1) {} For i As Integer = 0 To steps - 1 Dim color__1 As Color = Color.FromColorIndex( _ ColorMethod.ByLayer, CShort(100 + (i * 2))) newData(i) = New SurfaceAnalysisElevationData( _ minElevation + (increment * i), _ minElevation + (increment * (i + 1)), _ color__1) Next Return newData End Function
That's it. Thanks again to Drew Avis for providing the code for this great example.
NOTE: As you may have noticed, I have been very busy lately, which has prevented me from posting more often to this blog. The good news is that while I have been slacking on my articles, a couple colleagues have put together a great example on how to use the API to create water-drops and analyze rainfall. I want to thank Matt Anderson (@MattAnderson) and Drew Avis for this great contribution on what it is the first guest post to Civilized Development, and hopefully, the first of many more.
The new Surface APIs introduced in Civil 3D 2012 expose a lot of useful functionality and allow us to do some interesting things. In this post I will walk through using the SurfaceAnalysis.CreateWaterdrop() method to write a command that creates a rainfall analysis for a TIN surface. This sample also uses the Triangles collection of a TIN surface, another part of the new API.
In the Civil 3D GUI, the Waterdrop command is a tool to verify flow paths of a surface. You select or enter a point on a surface, and Civil draws a polyline representing the flow path of water from that point. This example creates a water-drop path from the centroid of all triangles in a surface, which can help you visualize the path rainwater runoff takes across a surface. There are a few reasons to perform this sort of analysis:
The collection of water-drop endpoints could be used as Discharge Points for the Catchment Command.
This command can provide a visualization of the surface and Civil 3D Inlets locations- Does the surface drain to the inlet, or is the inlet in the incorrect location?
The density of flow paths provides a visualization of flow accumulation. An interruption of that flow might be a "sink" or a watershed term for a "puddle", or simply the need to verify the TIN triangles and/or the need to add break-lines along valleys.
Let's look at some code. I've left out the tedious bits but you can download the complete source here.
First, we prompt for a TIN surface to operate on, and iterate through all the triangles in the surface. For each triangle, we calculate the 2d point that is the centroid (the geometric center) of the triangle. The CreateWaterdrop() method takes a 2d point, so we do not need to calculate the z dimension of the centroid. CreateWaterdrop() returns a collection of ObjectIds for any created polylines (and will be empty if there are none, for example if the target location is on a flat area). We save all of these in the "drops" collection to look at later.
C#
ObjectIdCollection drops = new ObjectIdCollection();foreach (TinSurfaceTriangle triangle in surface.Triangles){Point2d centroid = getTriangleCentroid(triangle);// calculate water-drop for the centroidObjectIdCollection oid =surface.Analysis.CreateWaterdrop(centroid,Autodesk.Civil.Land.WaterdropObjectType.Polyline3D);// Save all the water-dropsforeach (ObjectId id in oid){drops.Add(id);}}
VB.NET
Dim drops As New ObjectIdCollection()For Each triangle As TinSurfaceTriangle In surface.TrianglesDim centroid As Point2d = _getTriangleCentroid(triangle)' calculate water-drop for the centroidDim oid As ObjectIdCollection = _surface.Analysis.CreateWaterdrop(centroid, _Autodesk.Civil.Land.WaterdropObjectType.Polyline3D)' Save all the water-dropsFor Each id As ObjectId In oiddrops.Add(id)NextNext
The centroid is calculated in the following way:
C#
private Point2d getTriangleCentroid(TinSurfaceTriangle triangle){// The centroid is calculated from the cx and cy being:// cx = (v1x + v2x + v3x) / 3// cy = (v1y + v2y + v3y) / 3double cx = (triangle.Vertex1.Location.X+ triangle.Vertex2.Location.X+ triangle.Vertex3.Location.X)/ 3;double cy = (triangle.Vertex1.Location.Y+ triangle.Vertex2.Location.Y+ triangle.Vertex3.Location.Y)/ 3;return new Point2d(cx, cy);}
VB.NET
Private Function getTriangleCentroid(triangle As TinSurfaceTriangle) As Point2d' The centroid is calculated from the cx and cy being:' cx = (v1x + v2x + v3x) / 3' cy = (v1y + v2y + v3y) / 3Dim cx As Double = (triangle.Vertex1.Location.X _+ triangle.Vertex2.Location.X _+ triangle.Vertex3.Location.X)/ 3Dim cy As Double = (triangle.Vertex1.Location.Y+ triangle.Vertex2.Location.Y+ triangle.Vertex3.Location.Y)/ 3Return New Point2d(cx, cy)End Function
Now we can do some processing on the collection of water-drops. First we find the longest one, and then we filter out any that are shorter than 25% the length of the longest, and save the endpoints in a collection of 3D points called "sinks". Of course, a better implementation would be to make the 25% figure user-configurable, but I'll leave that as an exercise for you to try.
The following code shows how we calculate the longest.
C#
private double calculateLongestWaterDrop(ObjectIdCollection drops){double longest = 0;foreach (ObjectId id in drops){Polyline3d drop = id.GetObject(OpenMode.ForRead)as Polyline3d;longest = drop.Length > longest ? drop.Length : longest;}return longest;}
VB.NET
Private Function calculateLongestWaterDrop(drops As ObjectIdCollection)As DoubleDim longest As Double = 0For Each id As ObjectId In dropsDim drop As Polyline3d =TryCast(id.GetObject(OpenMode.ForRead), Polyline3d)longest = If(drop.Length > longest, drop.Length, longest)NextReturn longestEnd Function
And now, we filter the sinks:
C#
private Point3dCollection filterSinks(ObjectIdCollection drops,double longest){Point3dCollection sinks = new Point3dCollection();foreach (ObjectId id in drops){Polyline3d drop = id.GetObject(OpenMode.ForRead)as Polyline3d;if (drop.Length > (longest * .25)){sinks.Add(drop.EndPoint);string msg = String.Format("Sink located at: ({0},{1})\n",drop.EndPoint.X, drop.EndPoint.Y);write(msg);}}return sinks;}
VB.NET
Private Function filterSinks(drops As ObjectIdCollection, _longest As Double) As Point3dCollectionDim sinks As New Point3dCollection()For Each id As ObjectId In dropsDim drop As Polyline3d = _TryCast(id.GetObject(OpenMode.ForRead), Polyline3d)If drop.Length > (longest * 0.25) Thensinks.Add(drop.EndPoint)Dim msg As String = [String].Format( _"Sink located at: ({0},{1})" & _vbLf, drop.EndPoint.X, drop.EndPoint.Y)write(msg)End IfNextReturn sinksEnd Function
We cast each ObjectId in the drops collection to a Polyline3d because we specified that CreateWaterdrop() should create 3D polylines. You can also create 2d polylines if you do not care about the z-dimension elevation of the water-drop endpoint. In this case we do, because we want to create a collection of 3D points and mark them. Also, the 3D polyline water-drop is "draped" over the surface, which makes for a better visualization in model view.
Finally, we mark each endpoint with a marker in MODELSPACE. This part is just to demonstrate using the collection of water-drop endpoints, and there are probably more useful things you can do with this data. For example, you could export the collection of "sinks" to a file, which you can later use to create catchments. Unfortunately, catchment creation is not yet exposed in the API, so we can't create them automatically in code.
C#
private void markSinks(Transaction ts, Point3dCollection sinks){// now lets mark each endpointBlockTable acBlkTbl = _currentDb.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;BlockTableRecord acBlkTblRec =acBlkTbl[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite) as BlockTableRecord;// set the point style_currentDoc.Database.Pdmode = 35;_currentDoc.Database.Pdsize = 10;foreach (Point3d sink in sinks){DBPoint sinkPoint = new DBPoint(sink);sinkPoint.Color = Color.FromRgb(0, 255, 255);sinkPoint.SetDatabaseDefaults();acBlkTblRec.AppendEntity(sinkPoint);ts.AddNewlyCreatedDBObject(sinkPoint, true);}}
VB.NET
Private Sub markSinks(ts As Transaction, sinks As Point3dCollection)' now lets mark each endpointDim acBlkTbl As BlockTable = TryCast(ts.GetObject( __currentDoc.Database.BlockTableId, OpenMode.ForRead), _BlockTable)Dim acBlkTblRec As BlockTableRecord = TryCast(ts.GetObject( _acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite), _BlockTableRecord)' set the point style_currentDoc.Database.Pdmode = 35_currentDoc.Database.Pdsize = 10For Each sink As Point3d In sinksDim sinkPoint As New DBPoint(sink)sinkPoint.Color = Color.FromRgb(0, 255, 255)sinkPoint.SetDatabaseDefaults()acBlkTblRec.AppendEntity(sinkPoint)ts.AddNewlyCreatedDBObject(sinkPoint, True)NextEnd Sub
And that's it, a simple rainfall visualization.
A surface before:
And after (zooming into the marked areas):
You can download the complete example here.
Just happens, I was helping one of the interns that is working with us this summer, and she needed some demo code to work with TIN Surfaces. I prepared a small demo, to help her understand the concepts, and I thought it will be a good example also, to explain some of the concepts in the new design of the Surfaces .NET API that I started to talk about in my previous post.
In the demo, I created a small command "CDS_TinSurfacePropertiesDemo" that will prompt the user for a TIN Surface and display some properties. TIN Surfaces are one of the four type of surfaces supported by Civil 3D. Here is the implementation of the command.
C#
[CommandMethod("CDS_TinSurfacePropertiesDemo")]public void CDS_TinSurfacePropertiesDemo(){ObjectId surfaceId = promptForTinSurface();if (ObjectId.Null == surfaceId){_write("\nNo TIN Surface object was selected.");return; // We don't have a surface; we can't continue.}using (Transaction tr = startTransaction()){TinSurface surface = surfaceId.GetObject(OpenMode.ForRead) as TinSurface;_write("\nInformation for TIN Surface: " + surface.Name);writeGeneralProperites(surface.GetGeneralProperties());writeTerrainProperties(surface.GetTerrainProperties());writeTinSurfaceProperties(surface.GetTinProperties());}}
VB.NET
<CommandMethod("CDS_TinSurfacePropertiesDemo")> _Public Sub CDS_TinSurfacePropertiesDemo()Dim surfaceId As ObjectId = promptForTinSurface()If ObjectId.Null = surfaceId Then_write(vbLf & "No TIN Surface object was selected.")' We don't have a surface; we can't continue.ReturnEnd IfUsing tr As Transaction = startTransaction()Dim surface As TinSurface = TryCast(surfaceId.GetObject( _
OpenMode.ForRead), TinSurface)
_write(vbLf & "Information for TIN Surface: " + surface.Name)writeGeneralProperites(surface.GetGeneralProperties())writeTerrainProperties(surface.GetTerrainProperties())writeTinSurfaceProperties(surface.GetTinProperties())End UsingEnd Sub
The command opens the selected TIN Surface object and displays some of it properties. This is done in the 'write***' methods that we will implement, but notice how the properties are being access by methods exposed in the TIN Surface object.
General Properties
All Surface object in Civil 3D expose a 'GetGeneralProperties() method that returns a structure with general properties of the surface. We can see in the implementation of 'writeGeneralProperties()' the properties that are exposed.
C#
private void writeGeneralProperites(GeneralSurfaceProperties p){_write("\nGeneral Properties:");_write("\n-------------------");_write("\nMin X: " + p.MinimumCoordinateX);_write("\nMin Y: " + p.MinimumCoordinateY);_write("\nMin Z: " + p.MinimumElevation);_write("\nMax X: " + p.MaximumCoordinateX);_write("\nMax Y: " + p.MaximumCoordinateY);_write("\nMax Z: " + p.MaximumElevation);_write("\nMean Elevation: " + p.MeanElevation);_write("\nNumber of Points: " + p.NumberOfPoints);_write("\n--");}
VB.NET
Private Sub writeGeneralProperites(p As GeneralSurfaceProperties)_write(vbLf & "General Properties:")_write(vbLf & "-------------------")_write(vbLf & "Min X: " & Convert.ToString(p.MinimumCoordinateX))_write(vbLf & "Min Y: " & Convert.ToString(p.MinimumCoordinateY))_write(vbLf & "Min Z: " & Convert.ToString(p.MinimumElevation))_write(vbLf & "Max X: " & Convert.ToString(p.MaximumCoordinateX))_write(vbLf & "Max Y: " & Convert.ToString(p.MaximumCoordinateY))_write(vbLf & "Max Z: " & Convert.ToString(p.MaximumElevation))_write(vbLf & "Mean Elevation: " & Convert.ToString(p.MeanElevation))_write(vbLf & "Number of Points: " & Convert.ToString( _
p.NumberOfPoints))
_write(vbLf & "--")End Sub
We can see that Minimum/Maximum values for X/Y/Elevation have been provided, as well as the mean elevation point in the Surface. The 'GeneralSurfaceProperties' structure also exposes the number of points in the Surface.
Terrain Surface Properties
TIN Surfaces implement the 'ITerrainSurface' interface. This interface exposes the 'GetTerrainProperties()' method, which returns a 'TerrainSurfaceProperties' structure containing Terrain specific properties. The implementation of 'writeTerrainProperties()' shows the contents of 'TerrainSurfaceProperties'.
C#
private void writeTerrainProperties(TerrainSurfaceProperties p){_write("\nTerrain Surface Properties:");_write("\n---------------------------");_write("\nMin Grade/Slope: " + p.MinimumGradeOrSlope);_write("\nMax Grade/Slope: " + p.MaximumGradeOrSlope);_write("\nMean Grade/Slope: " + p.MeanGradeOrSlope);_write("\n2D Area: " + p.SurfaceArea2D);_write("\n3D Area: " + p.SurfaceArea3D);_write("\n--");}
VB.NET
Private Sub writeTerrainProperties(p As TerrainSurfaceProperties)_write(vbLf & "Terrain Surface Properties:")_write(vbLf & "---------------------------")_write(vbLf & "Min Grade/Slope: " & Convert.ToString(p.MinimumGradeOrSlope))_write(vbLf & "Max Grade/Slope: " & Convert.ToString(p.MaximumGradeOrSlope))_write(vbLf & "Mean Grade/Slope: " & Convert.ToString(p.MeanGradeOrSlope))_write(vbLf & "2D Area: " & Convert.ToString(p.SurfaceArea2D))_write(vbLf & "3D Area: " & Convert.ToString(p.SurfaceArea3D))_write(vbLf & "--")End Sub
Terrain Surface properties will tell you the minimum, maximum, and mean grade/slope. They also expose the surface area in 2D, and in 3D.
TIN Surface Properties
Of course, TIN Surfaces implement the 'ITinSurface' interface, which exposes a 'GetTinProperties()' that returns a 'TinSurfaceProperties' structure with properties about the TIN. The 'writeTinSurfaceProperties()' implementation shows the exposed properties in 'TinSurfaceProperties'.
C#
private void writeTinSurfaceProperties(TinSurfaceProperties p){_write("\nTIN Surface Properties:");_write("\n-----------------------");_write("\nMin Triangle Area: " + p.MinimumTriangleArea);_write("\nMin Triangle Length: " + p.MinimumTriangleLength);_write("\nMax Triangle Area: " + p.MaximumTriangleArea);_write("\nMax Triangle Length: " + p.MaximumTriangleLength);_write("\nNumber of Triangles: " + p.NumberOfTriangles);_write("\n--");}
VB.NET
Private Sub writeTinSurfaceProperties(p As TinSurfaceProperties)_write(vbLf & "TIN Surface Properties:")_write(vbLf & "-----------------------")_write(vbLf & "Min Triangle Area: " & Convert.ToString(p.MinimumTriangleArea))_write(vbLf & "Min Triangle Length: " & Convert.ToString(p.MinimumTriangleLength))_write(vbLf & "Max Triangle Area: " & Convert.ToString(p.MaximumTriangleArea))_write(vbLf & "Max Triangle Length: " & Convert.ToString(p.MaximumTriangleLength))_write(vbLf & "Number of Triangles: " & Convert.ToString(p.NumberOfTriangles))_write(vbLf & "--")End Sub
TIN Surface properties give access to minimum and maximum triangle area and length. The structure also exposes the number of triangles in the surface.
Conclusion
We saw in the previous post there are four type of surface objects in Civil 3D. Some types share properties, and these properties are exposed by implementing four different interfaces: 'ITerrainSurface', 'IVolumeSurface', 'ITinSurface', and 'IGridSurface'. These interfaces expose methods that allow to access specific properties.
You can download the complete source code and play with it as you please. Maybe, you want to tweak the code so it works for all four types of surfaces and send it to me. If you do, make sure you put the "BLOG:" prefix in the subject.
In this article, we will take a look at some of the design concepts we used during the implementation of the Surfaces .NET API for the 2012 release of Civil 3D. The goal is to give you an overview of the main classes and basic concepts that will allow you to use the API and port the code to .NET if you were using the previous COM API.
As you may already know, there are four types of surfaces in Civil 3D. These types are the result of combining a couple of concepts, the first one being TIN (Triangulated Irregular Network) vs. Grid surfaces. TIN surfaces contain a set of points within the surface boundary, which are triangulated to generate the surface faces. Grid surfaces contain points at specific distances, each one of them containing an elevation. These two different behaviors are exposed through a couple of interfaces: 'ITinSurface' and 'IGridSurface'.
The second concept with surfaces in Civil 3D is Terrain vs. Volume surfaces. Terrain surfaces represent a single layer of terrain where Volume surfaces represent the elevation delta between two surfaces. These two representations are exposed in the API through the 'ITerrainSurface' and 'IVolumeSurface' interfaces.
All surface types in the API derive from a common base class 'Surface', which exposes properties and methods common to all surfaces. Each individual surface type will implement the necessary interfaces according to their representation. The following diagram shows the design of the main classes and interfaces.
As you can see, the design allows you to work with concrete surface types, the 'Surface' base type, and through the exposed interfaces. This gives you a lot of flexibility in the way you can operate with the different surface objects depending on your needs.
In subsequent posts, we will take a deeper look at the different properties and methods exposed by the 'Surface' class as well as the provided interfaces.
Last year at AU, I presented a class about COM/.NET Interoperability. The class demonstrated how to use the Civil 3D COM API from a .NET Civil 3D extension. In general, you will want to use the .NET API when writing applications for Civil 3D, but there are times when a certain API is not available through .NET, and it is only exposed in COM. This was the case with AutoCAD Civil 3D 2011 and the Surfaces API back then. Today, the Surfaces API is available in .NET, and you should start planning to port your code.
It should be no secret, by now, that when I prepared my AU class, I knew the Surfaces .NET API will ship in the next release of Civil 3D.My ultimate goal in the presentation was to show how to encapsulate the surface functionality, so when the .NET API became available, the code was easy to port.
Now, the Surfaces .NET API is publicly available, so I ported the code, which you can download from here. The 'SurfacesDemo' solution contains two projects that implement the same set of commands. The COM project uses the Surfaces COM API. In the .NET sample, all COM related code and references have been removed, and the code has been ported to the .NET API.
If you do a delta of both projects, you will see how the majority of the changes happen in the surface wrapper class 'CivilTinSurface'. This was the goal when the code was written; to insure an easy port of the code from COM to .NET.
It might be helpful to go through my AU class materials to understand the concepts I explained in the presentation. I posted the materials, which contain the source code in C# and VB.NET, as well as the class presentation and handout. I hope you enjoy reviewing the materials, and that you send me any feedback you might have.
Source: https://civilizeddevelopment.typepad.com/civilized-development/c3d2012/
0 Response to "Autocad Civil There Are No Tin Surfaces on the Drawing"
Post a Comment