Alex_AMF Posted December 1, 2014 Posted December 1, 2014 (edited) Hello, Our users must be able to rotate a bunch of lines, circles, blocks etc (which result in looking like a conveyor). I am trying to pass a SelectionSet using the built-in rotate command of AutoCAD. I got a lot of help on the AutoDesk forums: http://forums.autodesk.com/t5/net/how-to-pass-objectidcollection-into-built-in-rotate-command/m-p/5429159#M42620 I seem to be in a stalemate right now. I don't have AutoCAD 2015 so I use a RunCommand wrapper to enable me to use the editor.Command(). Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Linq.Expressions Imports System.Reflection Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.EditorInput Module EditorInputExtensionMethods <System.Runtime.CompilerServices.Extension()> _ Public Function Command(editor As Editor, ParamArray args As Object()) As PromptStatus If editor Is Nothing Then Throw New ArgumentNullException("editor") End If Return runCommand(editor, args) End Function Dim runCommand As Func(Of Editor, Object(), PromptStatus) = GenerateRunCommand() Private Function GenerateRunCommand() As Func(Of Editor, Object(), PromptStatus) Dim method As MethodInfo = GetType(Editor).GetMethod("RunCommand", BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.[Public]) Dim instance As ParameterExpression = Expression.Parameter(GetType(Editor), "editor") Dim args As ParameterExpression = Expression.Parameter(GetType(Object()), "args") Return Expression.Lambda(Of Func(Of Editor, Object(), PromptStatus))(Expression.Call(instance, method, args), instance, args).Compile() End Function End Module I then populate my SelectionSet using an object ID collection that was built. Here is my code that I use to try and use the already built-in rotate command that AutoCAD has to offer: <CommandMethod("My-Rotate")> _ Public Sub MyRotate() 'Get the current document and database Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim acCurDb As Database = acDoc.Database Dim acObj As Object Dim entRes As PromptEntityResult Dim entOpts As PromptEntityOptions Dim rb As ResultBuffer Dim FoundHunter As Boolean Dim acBlkTbl As BlockTable Dim acBlkTblRec As BlockTableRecord Dim pickedPolyline As Polyline = Nothing Dim SelSet As SelectionSet Dim Lst_ObjId As New List(Of ObjectId) 'Prompt user to select the conveyor he wants to rotate Autodesk.AutoCAD.Internal.Utils.SetFocusToDwgView() entOpts = New PromptEntityOptions(vbLf & "Choose the object you wish to rotate") entRes = acDoc.Editor.GetEntity(entOpts) If (entRes.Status = PromptStatus.OK) Then 'Start a transaction Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction() acObj = entRes.ObjectId.GetObject(OpenMode.ForRead) 'Make sure the selected object was a polyline If Not TypeOf acObj Is Polyline Then MsgBox("You must choose a line or polyline") : Exit Sub rb = New ResultBuffer rb = entRes.ObjectId.GetObject(OpenMode.ForRead).XData() 'Sets the correct Project Conveyor ProjectConveyor.SetByDataTable(GetPKFromResultBuffer(rb), Project.PK_Project) 'Open the Block table for read acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) 'Open the Block table record Model space for write acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite) 'Go through the Block Table Record and build the collection ID For Each acObjId As ObjectId In acBlkTblRec rb = New ResultBuffer rb = acObjId.GetObject(OpenMode.ForRead).XData() FoundHunter = False If Not rb Is Nothing Then For Each tv As TypedValue In rb If tv.TypeCode = DxfCode.ExtendedDataRegAppName Then If tv.Value = "MY_PROGRAM_NAME" Then FoundHunter = True End If If FoundHunter And tv.TypeCode = DxfCode.ExtendedDataInteger32 Then If tv.Value = ProjectConveyor.PK_ProjectConveyor Then Lst_ObjId.Add(acObjId) 'Sets up all object IDs correctly here Exit For End If End If Next rb.Dispose() End If Next 'Create a selection set from object IDs SelSet = SelectionSet.FromObjectIds(Lst_ObjId.ToArray) 'Use AUTOCAD's Rotate function knowing we have all selections in selection set acDoc.Editor.Command("_.rotate", SelSet, "") 'Save the new objects to the database ProjectConveyor.Update() acTrans.Commit() End Using End If End Sub My issue is, whenever I get to the acDoc.Editor.Command() portion, it does not prompt the user to rotate anything. It returns Error(-5001) ... Any ideas? Edited December 1, 2014 by Alex_AMF Quote
BlackBox Posted December 1, 2014 Posted December 1, 2014 My issue is, whenever I get to the acDoc.Editor.Command() portion, it does not prompt the user to rotate anything. Any ideas? Try moving your Editor.Command() call from within your Transaction's using statement, to after it with something like (C# shown): // ... //Create a selection set from object IDs SelSet = SelectionSet.FromObjectIds(Lst_ObjId.ToArray()); //Use AUTOCAD's Rotate function knowing we have all selections in selection set //acDoc.Editor.Command("_.rotate", SelSet, ""); //Save the new objects to the database ProjectConveyor.Update(); acTrans.Commit(); } [color="red"]if (SelSet.Count > 0) acDoc.Editor.Command("_.rotate", SelSet, "");[/color] } } ^^ Tested in 2015, FWIW Quote
Alex_AMF Posted December 2, 2014 Author Posted December 2, 2014 Thanks for the reply BlackBox. I figured out the source of my troubles but have not fixed them yet. I was testing all this in AutoCad Standard edition which is what all users use normally. Finally, I tested it in AutoCad Mechanical edition. It worked in Mechanical only. In Mechanical, it would even work with the editor command being in the transaction. For good measure, I'll leave it out of the transaction as you suggested. Any idea why it's so glitchy in Standard Edition though? Try moving your Editor.Command() call from within your Transaction's using statement, to after it with something like (C# shown): // ... //Create a selection set from object IDs SelSet = SelectionSet.FromObjectIds(Lst_ObjId.ToArray()); //Use AUTOCAD's Rotate function knowing we have all selections in selection set //acDoc.Editor.Command("_.rotate", SelSet, ""); //Save the new objects to the database ProjectConveyor.Update(); acTrans.Commit(); } [color="red"]if (SelSet.Count > 0) acDoc.Editor.Command("_.rotate", SelSet, "");[/color] } } ^^ Tested in 2015, FWIW Quote
BlackBox Posted December 2, 2014 Posted December 2, 2014 Any idea why it's so glitchy in Standard Edition though? Without more information, or complete code to go on... No. I too work with AutoCAD verticals such as Map 3D, and Civil 3D (our primary production tool)... Verticals such as Map 3D, Civil 3D, Mechanical, MEP, etc. are built on top of what we refer to as vanilla AutoCAD (you call it standard), so what works in AutoCAD will work in verticals (OOTB)... Whereas what works in a vertical may not necessarily work in vanilla. If you find the need to have two separate interactions, then you might consider either conditionally testing that in your code with and IF, or SWITCH case statement, or simply compiling two separate assemblies, and using the Autoloader Mechanism to load the correct assembly into the correct application automagically. See links in my signature for more information, if not already familiar. Separately, if you're not already an ADN member, and you're going to continue developing internal customizations for your employer... You might consider becoming an AUGI Professional Member, which comes with a FREE Autodesk Developer Network (ADN) Standard Membership (saving you $1400). Cheers Quote
Alex_AMF Posted December 2, 2014 Author Posted December 2, 2014 You're right, I have on the "Standard" AutoCAD which has the Vanilla profile while the Mechanical one starts on the ACADMPP. I'll look through your Autoloader link in your signature. Also I'll check in to being an AUGI Professional Member. Seems interesting. Thanks! Quote
BlackBox Posted December 2, 2014 Posted December 2, 2014 You're right, I have on the "Standard" AutoCAD which has the Vanilla profile while the Mechanical one starts on the ACADMPP. I'll look through your Autoloader link in your signature. Also I'll check in to being an AUGI Professional Member. Seems interesting. Thanks! You're welcome, Alex_AMF; I'm happy to help. Cheers Quote
Alex_AMF Posted December 2, 2014 Author Posted December 2, 2014 One last question ... I have an issue with the code that utilizes the built-in rotate command. Once the item is rotated, I'd like to save the new Point3d in the database and then save the drawing. Although, my problem is that the compiler goes through the editor.Command(), continues all the way to the End Sub and then prompts the user to rotate the object. Why does it not wait for the user to complete the command before continueing? It just goes straight through. Is there a way to fix this? Quote
BlackBox Posted December 3, 2014 Posted December 3, 2014 One last question ... I have an issue with the code that utilizes the built-in rotate command. Once the item is rotated, I'd like to save the new Point3d in the database and then save the drawing. Although, my problem is that the compiler goes through the editor.Command(), continues all the way to the End Sub and then prompts the user to rotate the object. Why does it not wait for the user to complete the command before continueing? It just goes straight through. Is there a way to fix this? You should read up on the difference between Synchronous, and Asynchronous execution. You might want to consider SendStringToExecute() instead. Cheers Quote
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.