Author Topic: Programmatically Apply Style to Existing Civil 3D Surface  (Read 10527 times)

0 Members and 1 Guest are viewing this topic.

stevenh0616

  • Guest
Programmatically Apply Style to Existing Civil 3D Surface
« on: June 01, 2012, 08:14:14 AM »
I am working on a command to change the surface style programmatically with vb.NET and am having issues. I work with a lot of surfaces in my drawings at times and they are pasted into one compiled surface. When making modifications, you have to go through each surface and change the styles indivually from 'No Display' to 'Something that Displays'. So my thought was design a menu that lists the surface styles in the drawing and lists all the surfaces. Then pick what style you want and which surfaces to apply it to. Seems simple... but it's not working.

Under Autodesk.Civil.Land.DatabaseServices, Surface, TinSurface, & GridSurface are all exposed. They all list the StyleID as ObjectID and the StyleName as String that says it is a Public Overridable Property. However when trying to change their current values I receive an Unhandled Exception stating "need to override property StyleID()/StyleName". I would think that this would work.

I have done some research and saw that there is another option down the COM route with Surface.Style. However, I am unfamiliar with programming in COM and I was under the impression most of Civil3D has been ported to vb.NET.

Anyone know what I'm doing wrong?? Here is a little snippet of my code.

Code - vb.net: [Select]
  1. For Each Style As ObjectId In Styles
  2.                 Dim oStyle As SurfaceStyle = TryCast(Style.GetObject(OpenMode.ForRead), SurfaceStyle)
  3.                 If cbxSurfStyles.Text = oStyle.Name Then
  4.                     Dim oStyleId As ObjectId = oStyle.ObjectId
  5.                     'Dim oStyleNm As String = oStyle.Name
  6.                    
  7.                     For Each SelSurfName In clbSurfaces.CheckedItems
  8.                         Dim surfaces As ObjectIdCollection = m_CivilDoc.GetSurfaceIds
  9.  
  10.                         For Each surfaceId As ObjectId In surfaces
  11.                             Dim oSurface As ACLB.TinSurface = TryCast(SelSurfID.GetObject(OpenMode.ForWrite), ACLB.TinSurface)
  12.                             If oSurface.Name = SelSurfName Then
  13.                                 oSurface.StyleId = oStyleId
  14.                                 'oSurface.StyleName = oStyleNm
  15.                                 tr.Commit()
  16.                             End If
  17.                         Next
  18.                     Next
  19.                 End If
  20.             Next

Thanks!!

Steve
Windows 7
Civil3D 2011


Delegate

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #1 on: June 01, 2012, 08:56:42 AM »
Just to say in 2011 some of Civil 3D not covered by .NET:

Read the developer guide here for more info - quote below:

http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=16766674

Quote
The .NET API does not expose all the functionality of AutoCAD Civil 3D, and it exposes less than the COM
API. The following areas are not yet exposed in .NET:
■ Survey
■ Points
■ Surfaces
■ Sites and Parcels
■ Sections
■ Data Bands
■ Labels (except Alignment, Profile and Profile View labels)

Looks like improvements in later versions though.

BlackBox

  • King Gator
  • Posts: 3770
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #2 on: June 01, 2012, 09:15:46 AM »
When making modifications, you have to go through each surface and change the styles indivually from 'No Display' to 'Something that Displays'. So my thought was design a menu that lists the surface styles in the drawing and lists all the surfaces. Then pick what style you want and which surfaces to apply it to.

I also work with Civil 3D (2011/2012), and really like this idea.. it (this concept) seems applicable to many other Aecc* Objects as well.

It would be greatly appreciated if you were to post the source code, or VS project here (before or after completion at your discretion)... Either way, thanks for the idea!

Cheers!
"How we think determines what we do, and what we do determines what we get."

Delegate

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #3 on: June 01, 2012, 09:35:38 AM »
From the developers guide - does not use style ID.

Code: [Select]
Dim oSurfaceStyle As AeccSurfaceStyle
oSurfaceStyle = oDocument.SurfaceStyles.Add("New Style")
' The surface is displayed according to the
' oSurfaceStyle style we have just created.
oSurface.Style = oSurfaceStyle.Name

stevenh0616

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #4 on: June 01, 2012, 09:42:23 AM »
Grrrr....Thanks for looking into. I started working with the COM method, but am unfamiliar with it. I was getting object issues if I remember correctly. I think I was having issues referencing the active document with the COM method. I'll have to dig deeper.
« Last Edit: June 01, 2012, 01:15:13 PM by stevenh0616 »

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #5 on: June 01, 2012, 10:15:43 AM »
I think your code should work fine in 2011. I don't use VB much so I can't quickly write something to test/debug with unless I do it in C#. If you could share some code I could run I could probably advise you how to get it to work without needing COM.

Scratch that, I just setup a quick test and am getting the same error you are. I think I know how to work around it, but I need to go out in the field for a bit. Will try to have something later today.
« Last Edit: June 01, 2012, 11:06:08 AM by Jeff_M »

stevenh0616

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #6 on: June 01, 2012, 12:13:27 PM »
Thanks everyone.

So now I've attempted to go the COM route, which I am unfamiliar with. Below is my code. This is the same error I was getting the first time around with COM - "Object not set to an instance of an object" on the 3rd line down in the code below 'm_oAeccApp = m_oAcadApp.GetInterfaceObject(m_sAeccAppProgId)'. And this was all done following the COM .net development guide on Autodesk's website and via the Sample project in the Civil 3D API/COM folder.   http://docs.autodesk.com/CIV3D/2012/ENU/API_Reference_Guide/com/dotnet_dev.htm

Any ideas what I'm doing wrong here? Thanks.

Code - vb.net: [Select]
  1. m_sAcadProdID = "AutoCAD.Application"
  2.         m_sAeccAppProgId = "AeccXUiLand.AeccApplication.7.0"
  3.         m_oAeccApp = m_oAcadApp.GetInterfaceObject(m_sAeccAppProgId)
  4.         m_oAeccDb = m_oAeccApp.ActiveDocument.Database
  5.  
  6.         Using tr As Autodesk.AutoCAD.DatabaseServices.Transaction = db.TransactionManager.StartTransaction
  7.             Dim oStyles As AeccLandLib.AeccSurfaceStyles = m_oAeccDb.SurfaceStyles
  8.             For Each oStyleID As ObjectId In oStyles
  9.                 Dim oStyle As AeccLandLib.AeccSurfaceStyle = TryCast(oStyleID.GetObject(OpenMode.ForRead), AeccLandLib.AeccSurfaceStyle)
  10.                 If cbxSurfStyles.Text = oStyle.Name Then
  11.                     Dim oSelStyle As AeccLandLib.AeccSurfaceStyle = oStyle
  12.  
  13.                     For Each SelSurfName In clbSurfaces.CheckedItems
  14.                         Dim oSurfaces As AeccLandLib.AeccSurfaces = m_oAeccDb.Surfaces
  15.  
  16.                         For Each oSurfaceID As ObjectId In oSurfaces
  17.                             Dim oSurface As AeccLandLib.AeccSurface = TryCast(oSurfaceID.GetObject(OpenMode.ForWrite), AeccLandLib.AeccSurface)
  18.                             If oSurface.Name = SelSurfName Then
  19.                                 oSurface.Style = oSelStyle
  20.                                 tr.Commit()
  21.                             End If
  22.                         Next
  23.                     Next
  24.                 End If
  25.             Next
  26.         End Using
  27.         ed.Regen()
« Last Edit: June 01, 2012, 01:14:58 PM by stevenh0616 »

huiz

  • Swamp Rat
  • Posts: 919
  • Certified Prof C3D
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #7 on: June 01, 2012, 12:47:14 PM »
Surfaces are accessible via .NET since 2012, not 2011. But you could do via COM.

A developer's guide for 2011 can be found here: http://images.autodesk.com/adsk/files/civil_api_developers_guide0.pdf


The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

stevenh0616

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #8 on: June 01, 2012, 01:12:50 PM »
Right, but when attempting the COM method I cannot connect to the current drawing. The following code is right from the Autodesk Document explaining how to Root Objects in COMM. See code below, ThisDrawing in Line 9 is not exposed. How do I access it?

Code - vb.net: [Select]
  1. Imports AutoCAD = Autodesk.AutoCAD.Interop
  2. Imports AeccLandLib = Autodesk.AECC.Interop.Land
  3. Imports AeccUiLandLib = Autodesk.AECC.Interop.UiLand
  4. Imports AecUIBase = Autodesk.Aec.Interop.UIBase
  5. Imports Autodesk.AECC.Interop.UiLand
  6. Imports Autodesk.AutoCAD.Interop
  7.  
  8. Dim oAcadApp As AcadApplication
  9.         oAcadApp = ThisDrawing.Application
  10.         ' Specify the COM name of the object we want to access.
  11.         ' Note that this always accesses the most recent version
  12.         ' of AutoCAD Civil 3D installed.
  13.         Const sCivilAppName = "AeccXUiLand.AeccApplication.7.0"
  14.         Dim oCivilApp As AeccApplication
  15.         oCivilApp = oAcadApp.GetInterfaceObject(sCivilAppName)
  16.         ' Now we can use the AeccApplication object.
  17.         ' Get the AeccDocument representing the currently
  18.         ' active drawing.
  19.         Dim oDocument As AeccDocument
  20.         oDocument = oCivilApp.ActiveDocument

Delegate

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #9 on: June 01, 2012, 01:46:15 PM »
How about this method in c#: (Maybe does not work for getting at Civil3D stuff?)

AcadApplication app = (AcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application");

AcadDocument drawing = app.ActiveDocument;

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #10 on: June 01, 2012, 01:57:54 PM »
Or this:
AcadApplication acadApp = (AcadApplication)Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication;
AcadDocumant acadDoc = acadApp.ActiveDocument;

The AeccApplication for 2011 is 8.0, not 7.0

You can also make it versionless by doing this instead of what the 'help' docs say (sorry for the c#, hopefully you can figure out the VB equivalent):
AeccApplication aeccapp = new AeccApplicationClass();
aeccapp.init(acadApp);

stevenh0616

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #11 on: June 01, 2012, 02:20:16 PM »
Thanks.

I converted both of those over to VB.net and still won't work. I did catch the 8.0 vs 7.0 and that still didn't work. I wish Autodesk would be a bit more clear on what needs to happen from a COM standpoint in VB.net since half the program is in VB.net and the rest in COM.

The command is almost there (See attached PNG)... just have to get it to work... lol.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #12 on: June 01, 2012, 02:54:32 PM »
This seems to be a fairly simple way around this issue, mixing .NET managed code with COM. Note that I did not need to cast anything as the AeccApplication.
Code: [Select]
Imports System
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.Civil.ApplicationServices
Imports Autodesk.Civil.DatabaseServices
Imports Autodesk.Civil.Land.DatabaseServices
Imports Autodesk.Civil.Land.DatabaseServices.Styles
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AECC.Interop.Land


    <CommandMethod("TestSurfStyle")> _
    Public Sub TestSurfStyle()

        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim CivilDoc As CivilDocument = CivilApplication.ActiveDocument
        Using tr As Transaction = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction()
            Dim surf As TinSurface = TryCast(CivilDoc.GetSurfaceIds(0).GetObject(OpenMode.ForRead), TinSurface)
            Dim style As SurfaceStyle = TryCast(CivilDoc.Styles.SurfaceStyles(1).GetObject(OpenMode.ForRead), SurfaceStyle)
            Dim comSurf As AeccTinSurface = TryCast(surf.AcadObject, AeccTinSurface)
            Dim comStyle As AeccSurfaceStyle = TryCast(style.AcadObject, AeccSurfaceStyle)
            comSurf.Style = comStyle
            tr.Commit()
        End Using

    End Sub

stevenh0616

  • Guest
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #13 on: June 01, 2012, 03:29:56 PM »
Thanks Jeff. I was really excited for this because it was something completely different than what I've tried. I used your code almost exact and got the Object not set to an instance of an object.

Only thing I added was my code to pick the surface and plugged the surfaceID into the Surface tryCast.

I get the error on the line: comSurf.Style = comStyle

I suppose the objectID isn't getting passed in the trycast??

Code - vb.net: [Select]
  1. Dim SelSurfID As ObjectId = promptForSurface()
  2.         If ObjectId.Null = SelSurfID Then
  3.             'MsgBox appears under prompt for surface
  4.             ' We don't have a surface; we can't continue.
  5.             Return
  6.         End If
  7.         Dim CivilDoc As CivilDocument = CivilApplication.ActiveDocument
  8.         Using tr As Transaction = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction()
  9.             Dim surf As ACLB.TinSurface = TryCast(SelSurfID.GetObject(OpenMode.ForWrite), ACLB.TinSurface)
  10.             Dim style As SurfaceStyle = TryCast(CivilDoc.Styles.SurfaceStyles(1).GetObject(OpenMode.ForRead), SurfaceStyle)
  11.             Dim comSurf As AeccLandLib.AeccTinSurface = TryCast(surf.AcadObject, AeccLandLib.AeccTinSurface)
  12.             Dim comStyle As AeccLandLib.AeccSurfaceStyle = TryCast(style.AcadObject, AeccLandLib.AeccSurfaceStyle)
  13.             comSurf.Style = comStyle
  14.             tr.Commit()
  15.         End Using

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Programmatically Apply Style to Existing Civil 3D Surface
« Reply #14 on: June 01, 2012, 03:56:12 PM »
Have you stepped through the code when it's running to see what is getting set or not? Also, don't open the surface for write, the COM wrapper does that internally so all you need is to read the .NET object. Maybe try a different number when getting the surface styles, although the 1 I used would get the second one in the collection, so you'd need at least 2 styles for it to work.

Other than that, I really can't say without having your full code to test with.