thereisnotime Posted January 4, 2017 Share Posted January 4, 2017 I'm literally just getting into .NET programming and I'm having trouble figuring out how to request pipe information. I've got something simple here where I've counted pipes in the drawing. Now I'm ultimately trying to loop through the pipes and list their slopes but I'm not quite sure how to do that. As you can see, I tried to first start with listing the different pipe IDs and I'm getting the following error...any help or explanation would be greatly appreciated as the API reference isn't doing a very good job with giving examples. Value of type 'ObjectId' cannot be converted to 'string' Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.Civil.DatabaseServices Public Class PipeSlope <CommandMethod("GetPipeSlope")> Public Sub cmdGetPipeSlope() Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor Dim civDoc As Autodesk.Civil.ApplicationServices.CivilDocument civDoc = Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument Dim pipeIds As ObjectIdCollection = civDoc.GetPipeNetworkIds ed.WriteMessage("There are " & pipeIds.Count & " pipes in the drawing.") Dim oCurrentPipe = civDoc.NetworkState.CurrentPipeId For i = 0 To pipeIds.Count ed.WriteMessage(oCurrentPipe) Next End Sub End Class Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 4, 2017 Share Posted January 4, 2017 I hope that this helps steer you in the right direction. Feel free to ask specifics about what is happening in the code if you are having questions. [color="red"]Imports Autodesk.Civil.ApplicationServices[/color] <CommandMethod("GetPipeSlope")> Public Sub cmdGetPipeSlope() Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor Dim civDoc As civilDocument = Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument Dim aDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim db As Database = aDoc.Database Dim NetworkIds As ObjectIdCollection = civDoc.GetPipeNetworkIds Using trans As Transaction = db.TransactionManager.StartTransaction For Each NetId As ObjectId In NetworkIds Dim net As Network = trans.GetObject(NetId, OpenMode.ForRead) ed.WriteMessage(vbCrLf + net.Name) Dim PipeIds As ObjectIdCollection = net.GetPipeIds Using trans2 As Transaction = db.TransactionManager.StartTransaction Dim cnt As Integer = 1 For Each PipeId As ObjectId In PipeIds Dim pipe As Pipe = trans2.GetObject(PipeId, OpenMode.ForRead) ed.WriteMessage(vbCrLf + cnt.ToString + " : " + pipe.Name + " - " + (pipe.Slope * 100.0).ToString("N2") + "%") cnt = cnt + 1 Next trans2.Commit() End Using Next trans.Commit() End Using End Sub Quote Link to comment Share on other sites More sharing options...
thereisnotime Posted January 4, 2017 Author Share Posted January 4, 2017 That's awesome, thanks so much. I'm coming primarily from VBS and connecting/reading from a database is a little different; in VBS, you would use an ADO connection to connect to an MS Access database, but it's like any file...you have to open for reading, then close the connection once you're done. Do you have to close or disconnect from the DB here as well? Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 4, 2017 Share Posted January 4, 2017 Access to database objects are done through transactions. Since I am using the "Using" statement I do not need to dispose of the transaction as this is automatically completed for me at the "end using". If I wasn't using the "using" statement then I would have to call trans.dispose to dispose of the transaction object. Quote Link to comment Share on other sites More sharing options...
thereisnotime Posted January 6, 2017 Author Share Posted January 6, 2017 Oh nice! So Using is akin to accessing the DB as read-only...that's really handy. Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 6, 2017 Share Posted January 6, 2017 Oh nice! So Using is akin to accessing the DB as read-only...that's really handy. I guess I wouldn't look at "using" in that manner. "Using" is a way to easily work with disposable items, more or less. An instance of a transaction needs to be properly disposed of when you are done using it. I can use "using" in a transaction and write to the database as when. Transactions are simply the proper way to interact with the AutoCAD Database. "Using" is an easy way to dispose of an item when done using it. Quote Link to comment Share on other sites More sharing options...
thereisnotime Posted January 6, 2017 Author Share Posted January 6, 2017 Okay, I took this one step further...not sure if I should create a new thread for this or not...wouldn't be a big deal if I need to...Anyway... This code allows the user to select objects with a crossing window. Then it will take all the object IDs and compare them to the object IDs in the pipe network object collection. If they match, it's a pipe. It will then display the flow method on the screen for each pipe. What I would like to do is make a variable as "ForWrite" to change the method to 3. I tried doing something like this but it gave me an error about how Entity is too broad of a name and I'm not sure how to fix it: Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.Civil.ApplicationServices Imports Autodesk.Civil.DatabaseServices Public Class DisplayPipeInfoSingleSelection <CommandMethod("DisplayPipeInfo")> Public Sub cmdDisplayPipeInfo() Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor Dim civilDOC As CivilDocument = Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument Dim cadDOC As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim cadDB As Database = cadDOC.Database Dim pipeNetIDs As ObjectIdCollection = civilDOC.GetPipeNetworkIds '// Open the DB query Using cadTrans As Transaction = cadDB.TransactionManager.StartTransaction() Dim cadSSPrompt As PromptSelectionResult = cadDOC.Editor.GetSelection() '// If user pressed enter after prompt If cadSSPrompt.Status = PromptStatus.OK Then Dim cadSSet As SelectionSet = cadSSPrompt.Value For Each item As SelectedObject In cadSSet ed.WriteMessage(vbCrLf & "Object in CAD DB: " & item.ObjectId.ToString) '// Check if the item is in the DB If Not IsDBNull(item) Then '// Loop through the networks and see if the object ID is a pipe For Each netID As ObjectId In pipeNetIDs Dim net As Network = cadTrans.GetObject(netID, OpenMode.ForRead) Dim pipeIDs As ObjectIdCollection = net.GetPipeIds Using cadTrans2 As Transaction = cadDB.TransactionManager.StartTransaction For Each pipeID As ObjectId In pipeIDs Dim pipeOBJ As Pipe = cadTrans2.GetObject(pipeID, OpenMode.ForRead) If pipeID = item.ObjectId Then Select Case pipeOBJ.FlowDirectionMethod Case 0 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: Bi-Directional") Case 1 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: Start to End") Case 2 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: End to Start") Case 3 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: By Slope") End Select '// This is where the "Entity" error is Dim pipeOBJwrite As Entity = cadTrans2.GetObject(pipeID, OpenMode.ForWrite) End If Next End Using Next End If Next End If End Using End Sub End Class Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 6, 2017 Share Posted January 6, 2017 If you know that you are only going to be working with pipes. Then only allow the user to select pipes. Dim acTypValAr(0) As TypedValue acTypValAr.SetValue(New TypedValue(DxfCode.Start, "AECC_PIPE"), 0) Dim pSelFil As SelectionFilter = New SelectionFilter(acTypValAr) Dim cadSSPrompt As PromptSelectionResult = cadDOC.Editor.GetSelection(pSelFil) Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 6, 2017 Share Posted January 6, 2017 You can read from an object that you have open for write. There is also an upgrade open method. If you had previously opened for read to can upgrade open to write. If you know that you are working with a pipe you should Dim dbobj as Pipe = trans.GetObject(ObjID,openmode.forwrite) Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 6, 2017 Share Posted January 6, 2017 ***NOTE*** Do not forget to: trans.commit() Otherwise your transaction will rollback as if nothing ever happened. This can be frustrating as all seems correct with the code but nothing is working. Quote Link to comment Share on other sites More sharing options...
thereisnotime Posted January 9, 2017 Author Share Posted January 9, 2017 (edited) Alright, as a test, I clicked a single pipe only that I knew was "By slope" and I'm getting an "InvalidOperationException" error on the line: Dim pipeOBJ As Pipe = cadTrans.GetObject(pipeID, OpenMode.ForWrite) System.InvalidOperationException was unhandled by user code HResult=-2146233079 Message=Operation is not valid due to the current state of the object. Source=Acdbmgd StackTrace: at Autodesk.AutoCAD.DatabaseServices.Transaction.CheckTopTransaction() at Autodesk.AutoCAD.DatabaseServices.Transaction.GetObject(ObjectId id, OpenMode mode) at DisplayPipeInfo.DisplayPipeInfoSingleSelection.cmdDisplayPipeInfo() in H:\Civil3D\VBA .NET\Test Project\DisplayPipeInfo\DisplayPipeInfo\DisplayPipeInfo\DisplayPipeInfoSingleSelection.vb:line 40 at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorker(MethodInfo mi, Object commandObject, Boolean bLispFunction) at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorkerWithExceptionFilter(MethodInfo mi, Object commandObject, Boolean bLispFunction) at Autodesk.AutoCAD.Runtime.PerDocumentCommandClass.Invoke(MethodInfo mi, Boolean bLispFunction) at Autodesk.AutoCAD.Runtime.CommandClass.CommandThunk.Invoke() InnerException: **Edit: hang on, trying something... Edited January 9, 2017 by thereisnotime Quote Link to comment Share on other sites More sharing options...
thereisnotime Posted January 9, 2017 Author Share Posted January 9, 2017 Okay, no more error, but CAD crashes everytime I run the command lol Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.Civil.ApplicationServices Imports Autodesk.Civil.DatabaseServices Public Class DisplayPipeInfoSingleSelection <CommandMethod("DisplayPipeInfo")> Public Sub cmdDisplayPipeInfo() Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor Dim civilDOC As CivilDocument = Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument Dim cadDOC As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim cadDB As Database = cadDOC.Database Dim pipeNetIDs As ObjectIdCollection = civilDOC.GetPipeNetworkIds '// Open the DB query Using cadTrans As Transaction = cadDB.TransactionManager.StartTransaction() '// Use this to filter out ONLY pipes Dim acTypValAr(0) As TypedValue acTypValAr.SetValue(New TypedValue(DxfCode.Start, "AECC_PIPE"), 0) Dim pSelFil As SelectionFilter = New SelectionFilter(acTypValAr) Dim pSelFilOpt As New PromptSelectionOptions With pSelFilOpt .AllowDuplicates = False .AllowSubSelections = False .RejectObjectsFromNonCurrentSpace = True .RejectObjectsOnLockedLayers = False End With Dim cadSSPrompt As PromptSelectionResult = cadDOC.Editor.GetSelection(pSelFilOpt, pSelFil) Dim cadSSet As SelectionSet = cadSSPrompt.Value For Each item As SelectedObject In CadSSet If cadSSPrompt.Status = PromptStatus.OK Then For Each netID As ObjectId In pipeNetIDs Dim net As Network = cadTrans.GetObject(netID, OpenMode.ForWrite) Dim pipeIDs As ObjectIdCollection = net.GetPipeIds For Each pipeID As ObjectId In pipeIDs Dim pipeOBJ As Pipe = cadTrans.GetObject(pipeID, OpenMode.ForWrite) If pipeID = item.ObjectId Then Select Case pipeOBJ.FlowDirectionMethod Case 0 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: Bi-Directional") pipeOBJ.FlowDirectionMethod = 3 cadTrans.Commit() Case 1 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: Start to End") pipeOBJ.FlowDirectionMethod = 3 cadTrans.Commit() Case 2 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: End to Start") pipeOBJ.FlowDirectionMethod = 3 cadTrans.Commit() Case 3 ed.WriteMessage(vbCrLf & pipeOBJ.Name & " flow method: By Slope") End Select End If Next Next End If Next End Using End Sub End Class Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 9, 2017 Share Posted January 9, 2017 There were a few quirky things that you were doing that didn't seem to quite make sense. I have rewritten your code according to what I thought that you were trying to do. <CommandMethod("SetPipeFlowMethodToSlope")> Public Sub setPipeFlowMethodToSlope() 'Get Documents and Database Dim aDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim ed As Editor = aDoc.Editor Dim db As Database = aDoc.Database 'Build SelectionSet Options and Filter Dim acTypValAr(0) As TypedValue acTypValAr.SetValue(New TypedValue(DxfCode.Start, "AECC_PIPE"), 0) Dim pSelFil As SelectionFilter = New SelectionFilter(acTypValAr) Dim pSelFilOpt As New PromptSelectionOptions With pSelFilOpt .AllowDuplicates = False .AllowSubSelections = False .RejectObjectsFromNonCurrentSpace = True .RejectObjectsOnLockedLayers = False End With 'Prompt for Selection Dim PrmptSelRes As PromptSelectionResult = aDoc.Editor.GetSelection(pSelFilOpt, pSelFil) 'Test for a Good Selection If PrmptSelRes.Status = PromptStatus.OK Then 'Get the SelectionSet Dim ss As SelectionSet = PrmptSelRes.Value 'Begin a database transaction Using trans As Transaction = db.TransactionManager.StartTransaction For Each item As SelectedObject In ss 'Open each pipe in the selectionset for write Dim pipeObj As Pipe = trans.GetObject(item.ObjectId, OpenMode.ForWrite) 'Print the Network Name, Pipe Name & Current Flow Method. ed.WriteMessage(vbCrLf + "Network: " + pipeObj.NetworkName + " Name: " + pipeObj.Name + " - " + pipeObj.FlowDirectionMethod.ToString) 'Set the Flow Direction to BySlope pipeObj.FlowDirectionMethod = FlowDirectionMethodType.BySlope 'Print what we just did. ed.WriteMessage(vbCrLf + "Name: " + pipeObj.Name + " FlowDirectionMethod has been set to BySlope.") Next 'Commit the transaction. trans.Commit() End Using End If ed.WriteMessage(vbCrLf + "Command has completed sucessfully.") End Sub Quote Link to comment Share on other sites More sharing options...
thereisnotime Posted January 9, 2017 Author Share Posted January 9, 2017 (edited) Ah yes, I see where I was going wrong. Too much "patchwork" on my part. Thanks so much. This is a great starting point for me That's so interesting how you can't just say the integer of the flow direction method...you have to say "BySlope", but I guess that makes sense since you have to assign it to the property. I think I understand how this all works now; the program will give you the numerical value of a property, but you can't just say "this property, instead of 2, make it 3", you have to physically make it equal to a raw property of that object. Much different than Visual Basic Script lol but it makes sense now. Edited January 9, 2017 by thereisnotime Quote Link to comment Share on other sites More sharing options...
Hippe013 Posted January 9, 2017 Share Posted January 9, 2017 (edited) Actually you can use the enum value (in this case 3) instead of the enum. I prefer to use the enum when ever possible for better readability of the code. <CommandMethod("SetPipeFlowMethodToSlope")> Public Sub setPipeFlowMethodToSlope() 'Get Documents and Database Dim aDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim ed As Editor = aDoc.Editor Dim db As Database = aDoc.Database 'Build SelectionSet Options and Filter Dim acTypValAr(0) As TypedValue acTypValAr.SetValue(New TypedValue(DxfCode.Start, "AECC_PIPE"), 0) Dim pSelFil As SelectionFilter = New SelectionFilter(acTypValAr) Dim pSelFilOpt As New PromptSelectionOptions With pSelFilOpt .AllowDuplicates = False .AllowSubSelections = False .RejectObjectsFromNonCurrentSpace = True .RejectObjectsOnLockedLayers = False End With 'Prompt for Selection Dim PrmptSelRes As PromptSelectionResult = aDoc.Editor.GetSelection(pSelFilOpt, pSelFil) 'Test for a Good Selection If PrmptSelRes.Status = PromptStatus.OK Then 'Get the SelectionSet Dim ss As SelectionSet = PrmptSelRes.Value 'Begin a database transaction Using trans As Transaction = db.TransactionManager.StartTransaction For Each item As SelectedObject In ss 'Open each pipe in the selectionset for write Dim pipeObj As Pipe = trans.GetObject(item.ObjectId, OpenMode.ForWrite) 'Print the Network Name, Pipe Name & Current Flow Method. ed.WriteMessage(vbCrLf + "Network: " + pipeObj.NetworkName + " Name: " + pipeObj.Name + " - " + pipeObj.FlowDirectionMethod.ToString) 'Set the Flow Direction to BySlope [color="red"]pipeObj.FlowDirectionMethod = 3[/color] 'Print what we just did. ed.WriteMessage(vbCrLf + "Name: " + pipeObj.Name + " FlowDirectionMethod has been set to BySlope.") Next 'Commit the transaction. trans.Commit() End Using End If ed.WriteMessage(vbCrLf + "Command has completed successfully.") End Sub https://msdn.microsoft.com/en-us/library/3sd4y2w7.aspx Edited January 9, 2017 by Hippe013 Typo Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.