Rotate block on insert (while being able to see what rotated block would look like)
Hi, I want to be able to insert a block using vb.net and rotate that block during insertion, while being able to see what the rotation would look like.
The old Macro we used to do this was this *^C^C(command "layer" "m" "CSVGSYM" "ltype" "continuous" "" "color" "150" "" "")(command "insert" "221" "S" msf (getpoint))
This would insert the block on the layer and allow the user to rotate it after picking the insertion point, showing the user what the rotation would look like.
If I use this:
acedPostCommand("(command ""layer"" ""m"" ""CSVGSYM"" ""ltype"" ""continuous"" """" ""color"" ""150"" """" """") ")
acedPostCommand("(command ""insert"" ""221"" ""S"" msf (getpoint))")
It works properly but I cannot put it in a loop as it does not wait for a user response before looping again.
If I put it in a loop like this the problem is that I don't get to see what the rotated image would look while selecting the rotation angle.
Code:
insertRotatedBlock("X:\\Blocks\\221.dwg", "CSVGSYM", 150, "continuous")
Private Sub insertRotatedBlock(location As String, layer As String, color As String, linetype As String)
ThisDrawing = CType(Autodesk.AutoCAD.ApplicationServices.DocumentExtension.GetAcadDocument(Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument), Autodesk.AutoCAD.Interop.AcadDocument)
Dim tempBlock As AcadBlockReference
Dim userPoint As Object
Do
Try
userPoint = ThisDrawing.Utility.GetPoint(, "Specify insertion point:")
checkNewLayer(layer, color)
tempBlock = ThisDrawing.ModelSpace.InsertBlock(userPoint, location, (drawingSetting.getScale() / 1000), (drawingSetting.getScale() / 1000), (drawingSetting.getScale() / 1000), ThisDrawing.Utility.GetAngle(userPoint, "Select Rotation Angle: "))
tempBlock.Layer = layer
tempBlock.Linetype = linetype
Catch ex As System.Runtime.InteropServices.ExternalException
Exit Do
Catch exs As Exception
Exit Do
End Try
Loop
End Sub
Any help would be appreciated, thanks
Re: Rotate block on insert (while being able to see what rotated block would look like)
I'm confused... I do not understand why such a simple macro is being redone in VB.NET when a far simpler LISP would suffice, and still be callable via your existing Toolbar/Menu macro?
Code:
(vl-load-com)
(defun c:FOO (/ *error* layerName oldClayer)
(defun *error* (msg)
(and oldClayer (setvar 'clayer oldClayer))
(cond ((not msg)) ; Normal exit
((member msg '("Function cancelled" "quit / exit abort"))) ; <esc> or (quit)
((princ msg)) ; Fatal error, display it
)
(princ)
)
;; layer check
(if (not (tblsearch "layer" (setq layerName "CSVGSYM")))
(vla-put-color
(vla-add (vla-get-layers
(vla-get-activedocument (vlax-get-acad-object))
)
layerName
)
150
)
)
;; set the desired layer
(setq oldClayer (getvar 'clayer))
(setvar 'clayer layerName)
;; loop block insertion
(while (vl-cmdf "._-insert" "221" pause 1.0 1.0 pause))
;; exit
(*error* nil)
)
** Edit - You might also consider the acet-ss-drag-rotate function, if you do not care for my implementation above.
Further perplexing, and please forgive my saying so as I know nothing of your proficiency at .NET development, but I really do not understand why if you're going to step up into the .NET API, you'd still be performing simple tasks such as adding a Layer via acedPostCommand, SendStringToExecute, or the like... Instead, just Create and Name Layers.
Cheers
Re: Rotate block on insert (while being able to see what rotated block would look like)
Another way is to use acedCmd instead as this is
well explained in this article:
http://adndevblog.typepad.com/autoca...ing-c-net.html
Re: Rotate block on insert (while being able to see what rotated block would look like)
Hi,
If you want/need to do it in plain .NET you'll have to use Jigs (if you don't, you'd rather keep on using command macros and/or AutoLISP instead of trying to script with .NET and the COM interop).
Here's a little example using to classes derived from EntityJig. The first one is used to insert the block, the second to rotate it.
VB
Code:
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.Runtime
<Assembly: CommandClass(GetType(InsertRotateJigSample.CommandMethods))>
Namespace InsertRotateJigSample
Public Class CommandMethods
<CommandMethod("Test", CommandFlags.Modal)> _
Public Sub Test()
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Dim pr As PromptResult = ed.GetString(vbLf & "Enter the block name: ")
If pr.Status <> PromptStatus.OK Then
Return
End If
Dim blkName As String = pr.StringResult
Using tr As Transaction = db.TransactionManager.StartTransaction()
Dim bt As BlockTable = _
DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
If Not bt.Has(blkName) Then
ed.WriteMessage(vbLf & "Block '{0}' not found.", blkName)
Return
End If
Using br As New BlockReference(Point3d.Origin, bt(blkName))
br.TransformBy(ed.CurrentUserCoordinateSystem)
' Using InsertBlockJig class to insert the block
Dim insertJig As New InsertBlockJig(br)
pr = ed.Drag(insertJig)
If pr.Status <> PromptStatus.OK Then
Return
End If
' Using RotateBlockJig class to rotate the block
Dim rotateJig As New RotateBlockJig(br)
pr = ed.Drag(rotateJig)
If pr.Status <> PromptStatus.OK Then
Return
End If
rotateJig.UpdateRotation()
Dim btr As BlockTableRecord = _
DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
btr.AppendEntity(br)
tr.AddNewlyCreatedDBObject(br, True)
End Using
tr.Commit()
End Using
End Sub
End Class
Class InsertBlockJig
Inherits EntityJig
' Protected fields
Protected position As Point3d
Protected br As BlockReference
' Constructor (fields initialization)
Public Sub New(br As BlockReference)
MyBase.New(br)
Me.br = br
Me.position = br.Position
End Sub
' Prompts the user to specify the insertion point (EntityJig implementation)
Protected Overrides Function Sampler(prompts As JigPrompts) As SamplerStatus
Dim msg As String = vbLf & "Specify the insertion point: "
Dim jppo As New JigPromptPointOptions(msg)
jppo.UserInputControls = (UserInputControls.Accept3dCoordinates Or _
UserInputControls.NullResponseAccepted)
Dim ppr As PromptPointResult = prompts.AcquirePoint(jppo)
If Me.position.DistanceTo(ppr.Value) < Tolerance.[Global].EqualPoint Then
Return SamplerStatus.NoChange
Else
Me.position = ppr.Value
End If
Return SamplerStatus.OK
End Function
' Updates the bloc position (EntityJig implementation)
Protected Overrides Function Update() As Boolean
Me.br.Position = Me.position
Return True
End Function
End Class
Class RotateBlockJig
Inherits EntityJig
' Private fields
Protected br As BlockReference
Protected rot As Double, ucsRot As Double
' Constructor
Public Sub New(br As BlockReference)
MyBase.New(br)
Me.br = br
Me.ucsRot = br.Rotation
End Sub
' Prompts the user to specify the rotation (EntityJig implementation)
Protected Overrides Function Sampler(prompts As JigPrompts) As SamplerStatus
Dim jpao As New JigPromptAngleOptions(vbLf & "Specify the rotation: ")
jpao.DefaultValue = 0.0
jpao.UseBasePoint = True
jpao.BasePoint = Me.br.Position
jpao.Cursor = CursorType.RubberBand
jpao.UserInputControls = (UserInputControls.Accept3dCoordinates Or _
UserInputControls.UseBasePointElevation Or _
UserInputControls.NullResponseAccepted)
Dim pdr As PromptDoubleResult = prompts.AcquireAngle(jpao)
If Me.rot = pdr.Value Then
Return SamplerStatus.NoChange
Else
Me.rot = pdr.Value
Return SamplerStatus.OK
End If
End Function
' Updates the bloc rotation (EntityJig implementation)
Protected Overrides Function Update() As Boolean
UpdateRotation()
Return True
End Function
' Updates the bloc rotation (mandatory for the 'default' option)
' This method is called from the method where the jig is created
Friend Sub UpdateRotation()
Me.br.Rotation = Me.rot + Me.ucsRot
End Sub
End Class
End Namespace
Re: Rotate block on insert (while being able to see what rotated block would look like)
If you realy want/need scripting with .NET, you can use the following Editor extension method shared by Tony Tanzillo.
This method wraps the undocumented RunCommand() method which works the same as the AutoLISP 'command' function and accepts managed types as arguments.
C#
Code:
using System;
using System.Reflection;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
namespace InsertRotateJigSample
{
// From Tony Tanzillo (using reflection)
// http://www.theswamp.org/index.php?topic=43113.msg483306#msg483306
public static class EditorExtensions
{
public static PromptStatus Command(this Editor ed, params object[] args)
{
if (Application.DocumentManager.IsApplicationContext)
throw new InvalidOperationException("Invalid execution context for Command()");
if (ed.Document != Application.DocumentManager.MdiActiveDocument)
throw new InvalidOperationException("Document is not active");
return (PromptStatus)runCommand.Invoke(ed, new object[] { args });
}
static MethodInfo runCommand = typeof(Editor).GetMethod(
"RunCommand", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
}
}
VB
Code:
Imports System.Reflection
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Namespace InsertRotateJigSample
' From Tony Tanzillo (using reflection)
' http://www.theswamp.org/index.php?topic=43113.msg483306#msg483306
Module EditorExtensions
<System.Runtime.CompilerServices.Extension> _
Public Function Command(ed As Editor, ParamArray args As Object()) As PromptStatus
If Application.DocumentManager.IsApplicationContext Then
Throw New InvalidOperationException("Invalid execution context for Command()")
End If
If ed.Document <> Application.DocumentManager.MdiActiveDocument Then
Throw New InvalidOperationException("Document is not active")
End If
Return DirectCast(runCommand.Invoke(ed, New Object() {args}), PromptStatus)
End Function
Dim runCommand As MethodInfo = GetType(Editor).GetMethod( _
"RunCommand", BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.[Public])
End Module
End Namespace
Adding this module to your project, you'd be able to use the Editor.Command() method as the AutoLISP 'command' function:
Code:
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
ed.Command("_insert", "221", "\", 1.0, 1.0, "\")
Re: Rotate block on insert (while being able to see what rotated block would look like)
Gile -
You and Tony never fail to amaze, and are both incredibly kind to continue to offer this community all that you do.
Cheers
Re: Rotate block on insert (while being able to see what rotated block would look like)
Quote:
Originally Posted by
BlackBox
Gile -
You and Tony never fail to amaze, and are both incredibly kind to continue to offer this community all that you do.
Cheers
Subscribe to your opinion,
Regards
Re: Rotate block on insert (while being able to see what rotated block would look like)
Blackbox - you vla code works well - that block insert is very useful for me :)
Thank you for sharing it.
Re: Rotate block on insert (while being able to see what rotated block would look like)
Quote:
Originally Posted by
Brian C
Blackbox - you vla code works well - that block insert is very useful for me :)
Thank you for sharing it.
You're welcome, Brian - I'm always happy to help. :beer:
Re: Rotate block on insert (while being able to see what rotated block would look like)
Quote:
Originally Posted by
fixo
Subscribe to your opinion,
Regards
I too second the motion.
much appreciated.
I hope to contribute to the community as well.
how? i have no idea. but i'll find a way :)