Jump to content

How to utilize built-in Rotate command with SelectionSet?


Alex_AMF

Recommended Posts

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 by Alex_AMF
Link to comment
Share on other sites

 

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

Link to comment
Share on other sites

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.

0EcIYw5.png

 

Finally, I tested it in AutoCad Mechanical edition.

pLnU9Xy.png

 

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

Link to comment
Share on other sites

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). :thumbsup:

 

Cheers

Link to comment
Share on other sites

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! :D

Link to comment
Share on other sites

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! :D

 

You're welcome, Alex_AMF; I'm happy to help. :beer:

 

Cheers

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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. :thumbsup:

 

You might want to consider SendStringToExecute() instead.

 

Cheers

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...