.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Rotate Prior to Insertion of Block

12 REPLIES 12
SOLVED
Reply
Message 1 of 13
Ron_M
1939 Views, 12 Replies

Rotate Prior to Insertion of Block

ACA 2014, WIndows 7 64, VS 2013 Express, VB.Net

 

The block library is coming along well and I'm at a point where one further push or assist should allow me to complete it.

 

At this time blocks are pulled from external drawings, shown on the cursor as it moves on the screen, rotate on the cursor prior to input, BUT insert at the original orientation.  I am confused on how to pass back to InsertBlock the rotation angle of the block as shown on the cursor and have the block inserted at that orienation rather than at the original.  Below are the code for my library and the jig. 

 

Library.vb

Imports System
Imports System.IO
Imports System.Windows.Controls
Imports Autodesk.AutoCAD
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime

Public Class Library
    Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
    Dim itemstr As String
    Dim ed As Editor

    Private Sub Library_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each i As String In Directory.GetDirectories("R:\2014\Library\")
            ListView1.Items.Add(Path.GetFileName(i))
        Next
        ListView1.Items.Remove(ListView1.Items(0))
        If ListView1.Items.Count > 0 Then
            ListView1.Items(0).Focused = True
            ListView1.Items(0).Selected = True
            itemstr = (Me.ListView1.FocusedItem.Text)
            PictureBox1.ImageLocation = ("R:\2014\Library\" & itemstr & "\template.wmf")
        End If
    End Sub

    Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
        If Me.ListView1.SelectedItems.Count > 0 Then
            itemstr = (Me.ListView1.FocusedItem.Text)
            PictureBox1.ImageLocation = ("R:\2014\Library\" & itemstr & "\template.wmf")
        End If
    End Sub

    Private Sub PictureBox1_MouseClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseClick
        Dim xPos As Integer
        Dim yPos As Integer
        If e.Button = System.Windows.Forms.MouseButtons.Left Then
            xPos = e.X
            yPos = e.Y
        End If
        doit(xPos, yPos, itemstr)
    End Sub

    Private Sub doit(ByVal xPos As Single, ByVal yPos As Single, itemstr As String)
        Dim box As String
        Dim x As Integer
        Dim y As Integer
        Dim layer As String
        x = (Int(xPos / 100))
        y = (Int(yPos / 100))
        If y > 0 Then
            box = (Int((x) + (Int(y) * 8)))
        Else : box = x
        End If

        'Layers
        Using Myreader As New Microsoft.VisualBasic.FileIO.TextFieldParser("R:\2014\Library\" & itemstr & "\layers.lst")
            Myreader.TextFieldType = FileIO.FieldType.Delimited
            Myreader.SetDelimiters(",")
            While Not Myreader.EndOfData
                Try
                    Dim fields() As String = Myreader.ReadFields
                    layer = (fields(box))
                Finally
                End Try
            End While
            AddLayer(layer)
        End Using

        'Blocks
        Using Myreaderblocks As New Microsoft.VisualBasic.FileIO.TextFieldParser("R:\2014\Library\" & itemstr & "\library.lst")
            Myreaderblocks.TextFieldType = FileIO.FieldType.Delimited
            Myreaderblocks.SetDelimiters(",")
            While Not Myreaderblocks.EndOfData
                Try
                    Dim fields() As String = Myreaderblocks.ReadFields
                    Dim currentField As String = (fields(box))
                    If currentField.Length > 5 Then
                        result = currentField.Substring(currentField.Length - 3)
                    End If
                    Dim BlockName As String = currentField.Substring(0, currentField.Length - 6)
                    If Not result = "" Then
                        Select Case result
                            Case "dwg"
                                addblock(BlockName, currentField, itemstr)
                        End Select
                    End If
                Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
                End Try
            End While
        End Using
    End Sub

    Public Sub AddLayer(layer)
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        acDoc.LockDocument()
        Using tr As Transaction = db.TransactionManager.StartTransaction()
            Dim ltb As LayerTable = DirectCast(tr.GetObject(db.LayerTableId, OpenMode.ForRead), LayerTable)
            'create a new layer
            If Not ltb.Has(layer) Then
                ltb.UpgradeOpen()
                Dim newLayer As New LayerTableRecord()
                newLayer.Name = layer
                newLayer.LineWeight = LineWeight.LineWeight005
                newLayer.Description = "This is new layer"
                'red color
                newLayer.Color = Autodesk.AutoCAD.Colors.Color.FromRgb(255, 0, 0)
                ltb.Add(newLayer)
                tr.AddNewlyCreatedDBObject(newLayer, True)
            End If
            tr.Commit()
            'make it as current
            db.Clayer = ltb(layer)
        End Using
    End Sub

    Public Sub addblock(ByVal blockname As String, ByVal currentfield As String, ByVal itemstr As String)
        Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
        Using OpenDb As New Database(False, True)
            OpenDb.ReadDwgFile("R:\2014\Library\" & itemstr & "\" & currentfield, System.IO.FileShare.ReadWrite, True, "")
            acDoc.LockDocument()
            Dim ids As New ObjectIdCollection()
            Using tr As Transaction = OpenDb.TransactionManager.StartTransaction()
                'For example, Get the block by name "BlkName"
                Dim bt As BlockTable
                bt = DirectCast(tr.GetObject(OpenDb.BlockTableId, OpenMode.ForRead), BlockTable)
                If bt.Has(blockname) Then
                    ids.Add(bt(blockname))
                End If
                tr.Commit()
            End Using
            'if not found, add the block
            If ids.Count <> 0 Then
                'get the current drawing database
                Dim destdb As Database = acDoc.Database
                Dim iMap As New IdMapping()
                acDoc.LockDocument()
                destdb.WblockCloneObjects(ids, destdb.BlockTableId, iMap, DuplicateRecordCloning.Ignore, False)
            End If
        End Using
        Dispose()
        InsertBlockWithJig(blockname, layer)
    End Sub

    Public Sub InsertBlockWithJig(ByVal blockname As String, layer As String)
        Dim myDB As Database
        myDB = HostApplicationServices.WorkingDatabase
        Dim myJig As BlockJig

        Using myTrans As Transaction = myDB.TransactionManager.StartTransaction
            Dim myBT As BlockTable = myDB.BlockTableId.GetObject(OpenMode.ForRead)
            If myBT.Has(blockname) Then
                Dim myBTR As BlockTableRecord = myBT(blockname).GetObject(OpenMode.ForRead)
                myJig = New BlockJig(myBTR.ObjectId)
            Else
                Exit Sub
            End If
        End Using
        Dim myBlkID As ObjectId
        Dim SelPt As EditorInput.PromptPointResult
        Dim pdr As EditorInput.PromptPointResult
        Do
            SelPt = myJig.BeginJig
            If Not SelPt Is Nothing Then
                Select Case SelPt.Status
                    Case EditorInput.PromptStatus.OK
                        myBlkID = insertblock(SelPt.Value, blockname)
                    Case EditorInput.PromptStatus.Other
                        Exit Sub
                End Select
            End If
            If SelPt Is Nothing Then Exit Do
        Loop While SelPt.Status = EditorInput.PromptStatus.OK
    End Sub

    Public Function insertblock(BasePt As Point3d, blockname As String)
        Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
        Using myT As Transaction = db.TransactionManager.StartTransaction()
            'Get the block definition "Check".
            Dim bt As BlockTable = TryCast(db.BlockTableId.GetObject(OpenMode.ForRead), BlockTable)
            Dim blockDef As BlockTableRecord = TryCast(bt(blockname).GetObject(OpenMode.ForRead), BlockTableRecord)
            'Also open modelspace - we'll be adding our BlockReference to it
            Dim ms As BlockTableRecord = TryCast(bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite), BlockTableRecord)

            'Create new BlockReference, and link it to our block definition
            Using blockRef As New BlockReference(BasePt, blockDef.ObjectId)
                'Add the block reference to modelspace
                ms.AppendEntity(blockRef)
                myT.AddNewlyCreatedDBObject(blockRef, True)

                'Iterate block definition to find all non-constant AttributeDefinitions
                For Each id As ObjectId In blockDef
                    Dim obj As DBObject = id.GetObject(OpenMode.ForRead)
                    Dim attDef As AttributeDefinition = TryCast(obj, AttributeDefinition)
                    If (attDef IsNot Nothing) AndAlso (Not attDef.Constant) Then
                        'This is a non-constant AttributeDefinition
                        'Create a new AttributeReference
                        Using attRef As New AttributeReference()
                            attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform)
                            'Add the AttributeReference to the BlockReference
                            blockRef.AttributeCollection.AppendAttribute(attRef)
                            myT.AddNewlyCreatedDBObject(attRef, True)
                        End Using
                    End If
                Next
            End Using
            acDoc.TransactionManager.QueueForGraphicsFlush()
            myT.Commit()
        End Using
    End Function

End Class

 BlockJig.vb

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD

Public Class BlockJig
    Inherits Autodesk.AutoCAD.EditorInput.EntityJig
    Dim BasePt As Point3d = New Point3d(0, 0, 0)
    Dim myMatrix As Matrix3d
    Dim myBRef As DatabaseServices.BlockReference
    Dim myOpts As EditorInput.JigPromptPointOptions
    Dim CurrentKeyword As String
    Protected _pos As Point3d
    Protected _rot As Double, _ucsRot As Double

    Sub New(ByVal BlockID As ObjectId)
        MyBase.New(New DatabaseServices.BlockReference(BlockIns, BlockID))
        myBRef = Me.Entity
        _pos = myBRef.Position
        _rot = myBRef.Rotation
    End Sub

    Function BeginJig() As PromptPointResult
        If myOpts Is Nothing Then
            myOpts = New EditorInput.JigPromptPointOptions()
            myOpts.Message = vbCrLf & "Select a point:"
            myOpts.Cursor = EditorInput.CursorType.Invisible
            myOpts.UseBasePoint = False
        End If
        Dim ed As EditorInput.Editor = Application.DocumentManager.MdiActiveDocument.Editor
        Dim myPR As PromptResult
        Dim ucs As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d
        Dim ocsMat As Matrix3d = Matrix3d.WorldToPlane(New Plane(Point3d.Origin, ucs.Zaxis))
        _ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(ocsMat), ucs.Zaxis)
        _rot = myBRef.Rotation - _ucsRot
        myPR = ed.Drag(Me)
        Do
            Select Case myPR.Status
                Case EditorInput.PromptStatus.OK
                    Return myPR
                    Exit Do
                Case EditorInput.PromptStatus.None
                    Return myPR
                    Exit Do
                Case EditorInput.PromptStatus.Other
                    Return myPR
                    Exit Do
            End Select
        Loop While myPR.Status <> EditorInput.PromptStatus.Cancel
        Return Nothing
    End Function

    Protected Overrides Function Sampler(prompts As JigPrompts) As SamplerStatus
        Dim mods As System.Windows.Forms.Keys = System.Windows.Forms.Control.ModifierKeys
        If (mods And System.Windows.Forms.Keys.Control) > 0 Then
            Dim jpao As New JigPromptAngleOptions(vbLf & "Specify the rotation: ")
            jpao.UseBasePoint = True
            jpao.BasePoint = myBRef.Position
            jpao.Cursor = CursorType.Invisible
            jpao.UserInputControls = (UserInputControls.Accept3dCoordinates Or UserInputControls.UseBasePointElevation)
            Dim pdr As PromptDoubleResult = prompts.AcquireAngle(jpao)

            If _rot = pdr.Value Then
                Return SamplerStatus.NoChange
            Else
                _rot = pdr.Value
                Return SamplerStatus.OK
            End If
        Else
            Dim jppo As New JigPromptPointOptions(vbLf & "Specify insertion point (or press Ctrl for rotation): ")
            jppo.UserInputControls = (UserInputControls.Accept3dCoordinates Or UserInputControls.NullResponseAccepted)
            Dim ppr As PromptPointResult = prompts.AcquirePoint(jppo)
            If _pos.DistanceTo(ppr.Value) < Tolerance.[Global].EqualPoint Then
                Return SamplerStatus.NoChange
            Else
                _pos = ppr.Value
            End If
            Return SamplerStatus.OK
        End If
    End Function

    Protected Overrides Function Update() As Boolean
        myBRef.Position = _pos
        myBRef.Rotation = _rot + _ucsRot
        Return True
    End Function

End Class

 

12 REPLIES 12
Message 2 of 13
_gile
in reply to: Ron_M

Hi,

 

You can add a Rotation property in the BlockJig class so that you can get the specified rotation from the calling method and set this rotation to the inserted BlockReference.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 13
Ron_M
in reply to: _gile

I had thought I had done that as I can rotate the block on the cursor prior to selecting the insertion point. I can't seem to get the rotation returned to the inserted block.
Message 4 of 13
_gile
in reply to: Ron_M

Hi,

 

I didn't read your code enough attentively.

 

Here's a little sample closer to my understanding of your request (the code don't care about loading the block if not existing in the block table to focus to the  BlockJig).

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace InsertBlockSample
{
    public class CommandMethods
    {
        [CommandMethod("Test")]
        public void Test()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptResult psr = ed.GetString("\nEnter the block name: ");
            if (psr.Status != PromptStatus.OK) return;
            string blockName = psr.StringResult;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(blockName))
                {
                    using (BlockReference br = new BlockReference(Point3d.Origin, bt[blockName]))
                    {
                        br.TransformBy(ed.CurrentUserCoordinateSystem);
                        BlockJig jig = new BlockJig(br);
                        PromptResult pr = ed.Drag(jig);
                        if (pr.Status == PromptStatus.OK)
                        {
                            BlockTableRecord curspace =
                                (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                            curspace.AppendEntity(br);
                            tr.AddNewlyCreatedDBObject(br, true);
                        }
                    }
                }
                else
                {
                    Application.ShowAlertDialog(string.Format("Block '{0}' not found.", blockName));
                }
                tr.Commit();
            }
        }
    }

    class BlockJig : EntityJig
    {
        protected BlockReference _br;
        protected Point3d _pos;
        protected double _rot, _ucsRot;

        public BlockJig(BlockReference br)
            : base(br)
        {
           _br = br;
            _pos = br.Position;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            Matrix3d ucsMat = ed.CurrentUserCoordinateSystem;
            CoordinateSystem3d ucs = ucsMat.CoordinateSystem3d;
            Matrix3d ocsMat = Matrix3d.WorldToPlane(new Plane(Point3d.Origin, ucs.Zaxis));
            _ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(ocsMat), ucs.Zaxis);
            _rot = br.Rotation - _ucsRot;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            System.Windows.Forms.Keys mods = System.Windows.Forms.Control.ModifierKeys;
            if ((mods & System.Windows.Forms.Keys.Control) > 0)
            {
                JigPromptAngleOptions jpao = new JigPromptAngleOptions(
                    "\nSpecify the rotation (release Ctrl to validate): ");
                jpao.UseBasePoint = true;
                jpao.BasePoint = _br.Position;
                jpao.Cursor = CursorType.RubberBand;
                jpao.UserInputControls = (
                    UserInputControls.Accept3dCoordinates |
                    UserInputControls.UseBasePointElevation);
                PromptDoubleResult pdr = prompts.AcquireAngle(jpao);

                if (_rot == pdr.Value)
                {
                    return SamplerStatus.NoChange;
                }
                else
                {
                    _rot = pdr.Value;
                    return SamplerStatus.OK;
                }
            }
            else
            {
                JigPromptPointOptions jppo = new JigPromptPointOptions(
                    "\nSpecify the insertion point (or press Ctrl for rotation): ");
                jppo.UserInputControls =
                  (UserInputControls.Accept3dCoordinates |
                  UserInputControls.NullResponseAccepted);
                PromptPointResult ppr = prompts.AcquirePoint(jppo);
                if (_pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint)
                {
                    return SamplerStatus.NoChange;
                }
                else
                {
                    _pos = ppr.Value;
                }
                return SamplerStatus.OK;
            }
        }

        protected override bool Update()
        {
            _br.Position = _pos;
            _br.Rotation = _rot + _ucsRot;
            return true;
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 13
_gile
in reply to: _gile

One step further.

 

If the block have attributes and you want to diplay them during the jig dragging, you may add the block reference and the attribute references before dragging and erase it if ed.Drag(jig) does not return PromptStatus.OK

I use another class (BlockAttribJig) which inherits from BlockJig and only cares of updating the attributes geometry.

I also use a little structure (AttInfo) to store the text informations of the attribute definitions.

 

using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace InsertBlockSample
{
    public class CommandMethods
    {
        [CommandMethod("Test")]
        public void Test()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;  

            PromptResult psr = ed.GetString("\nEnter the block name: ");
            if (psr.Status != PromptStatus.OK) return;
            string blockName = psr.StringResult;

            InsertBlock(blockName);
        }

        private void InsertBlock(string blockName)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(blockName))
                {
                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead);
                    using (BlockReference br = new BlockReference(Point3d.Origin, bt[blockName]))
                    {
                        br.TransformBy(ed.CurrentUserCoordinateSystem);
                        BlockTableRecord curspace =
                            (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        curspace.AppendEntity(br);
                        tr.AddNewlyCreatedDBObject(br, true);

                        BlockJig jig;
                        if (btr.HasAttributeDefinitions)
                        {
                            Dictionary<string, TextInfo> attInfos = new Dictionary<string, TextInfo>();
                            RXClass attribClass = RXClass.GetClass(typeof(AttributeDefinition));
                            foreach (ObjectId id in btr)
                            {
                                if (id.ObjectClass == attribClass)
                                {
                                    AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                                    AttributeReference attRef = new AttributeReference();
                                    attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
                                    br.AttributeCollection.AppendAttribute(attRef);
                                    tr.AddNewlyCreatedDBObject(attRef, true);
                                    attInfos.Add(attDef.Tag, new TextInfo(attDef));
                                }
                            }
                            jig = new BlockAttribJig(br, attInfos);
                        }
                        else
                        {
                            jig = new BlockJig(br);
                        }

                        PromptResult pr = ed.Drag(jig);
                        if (pr.Status != PromptStatus.OK)
                        {
                            br.Erase();
                        }
                    }
                }
                else
                {
                    Application.ShowAlertDialog(string.Format("Block '{0}' not found.", blockName));
                }
                tr.Commit();
            }
        }
    }

    class BlockJig : EntityJig
    {
        protected BlockReference br;
        protected Point3d pos;
        protected double ucsRot, rot;

        public BlockJig(BlockReference br)
            : base(br)
        {
            this.br = br;
            pos = br.Position;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            Matrix3d ucsMat = ed.CurrentUserCoordinateSystem;
            CoordinateSystem3d ucs = ucsMat.CoordinateSystem3d;
            Matrix3d ocsMat = Matrix3d.WorldToPlane(new Plane(Point3d.Origin, ucs.Zaxis));
            ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(ocsMat), ucs.Zaxis);
            rot = br.Rotation - ucsRot;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            System.Windows.Forms.Keys mods = System.Windows.Forms.Control.ModifierKeys;
            if ((mods & System.Windows.Forms.Keys.Control) > 0)
            {
                JigPromptAngleOptions jpao = new JigPromptAngleOptions(
                    "\nSpecify the rotation (release Ctrl to validate): ");
                jpao.UseBasePoint = true;
                jpao.BasePoint = br.Position;
                jpao.Cursor = CursorType.RubberBand;
                jpao.UserInputControls = (
                    UserInputControls.Accept3dCoordinates |
                    UserInputControls.UseBasePointElevation);
                PromptDoubleResult pdr = prompts.AcquireAngle(jpao);

                if (rot == pdr.Value)
                {
                    return SamplerStatus.NoChange;
                }
                else
                {
                    rot = pdr.Value;
                    return SamplerStatus.OK;
                }
            }
            else
            {
                JigPromptPointOptions jppo = new JigPromptPointOptions(
                    "\nSpecify the insertion point (or press Ctrl for rotation): ");
                jppo.UserInputControls =
                  (UserInputControls.Accept3dCoordinates |
                  UserInputControls.NullResponseAccepted);
                PromptPointResult ppr = prompts.AcquirePoint(jppo);
                if (pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint)
                {
                    return SamplerStatus.NoChange;
                }
                else
                {
                    pos = ppr.Value;
                }
                return SamplerStatus.OK;
            }
        }

        protected override bool Update()
        {
            br.Position = pos;
            br.Rotation = rot + ucsRot;
            return true;
        }
    }

    class BlockAttribJig : BlockJig
    {
        private Dictionary<string, TextInfo> attRefInfos;
        private Transaction tr;

        public BlockAttribJig(BlockReference br, Dictionary<string, TextInfo> attInfos)
            : base(br)
        {
            attRefInfos = attInfos;
            tr = br.Database.TransactionManager.TopTransaction;
        }

        protected override bool Update()
        {
            base.Update();
            foreach (ObjectId id in br.AttributeCollection)
            {
                AttributeReference att = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                string tag = att.Tag.ToUpper();
                if (attRefInfos.ContainsKey(tag))
                {
                    TextInfo ti = attRefInfos[tag];
                    att.Position = ti.Position.TransformBy(br.BlockTransform);
                    att.Rotation = ti.Rotation + br.Rotation;
                    if (ti.IsAligned)
                    {
                        att.AlignmentPoint =
                            ti.Alignment.TransformBy(br.BlockTransform);
                        att.AdjustAlignment(br.Database);
                    }
                    if (att.IsMTextAttribute)
                    {
                        att.UpdateMTextAttribute();
                    }
                }
            }
            return true;
        }
    }

    struct TextInfo
    {
        public readonly Point3d Position, Alignment;
        public readonly bool IsAligned;
        public readonly double Rotation;

        public TextInfo(DBText text)
        {
            this.Position = text.Position;
            this.Alignment = text.AlignmentPoint;
            this.IsAligned = text.Justify != AttachmentPoint.BaseLeft;
            this.Rotation = text.Rotation;
        }
    }
}

 

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 13
_gile
in reply to: _gile

One more step further.

Using a class which implements the System.Windows.Forms.IMessageFilter interface allows to catch some key down during the jig drag and perform some changes to the block rotation.
In the following sample, it's used to add 90° to the block current rotation each time the user hits the Tab key.

 

using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace InsertBlockSample
{
    public class CommandMethods
    {
        [CommandMethod("Test")]
        public void Test()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;  

            PromptResult psr = ed.GetString("\nEnter the block name: ");
            if (psr.Status != PromptStatus.OK) return;
            string blockName = psr.StringResult;

            InsertBlock(blockName);
        }

        private void InsertBlock(string blockName)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(blockName))
                {
                    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead);
                    using (BlockReference br = new BlockReference(Point3d.Origin, bt[blockName]))
                    {
                        br.TransformBy(ed.CurrentUserCoordinateSystem);
                        BlockTableRecord curspace =
                            (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        curspace.AppendEntity(br);
                        tr.AddNewlyCreatedDBObject(br, true);

                        BlockJig jig;
                        if (btr.HasAttributeDefinitions)
                        {
                            Dictionary<string, TextInfo> attInfos = new Dictionary<string, TextInfo>();
                            RXClass attribClass = RXClass.GetClass(typeof(AttributeDefinition));
                            foreach (ObjectId id in btr)
                            {
                                if (id.ObjectClass == attribClass)
                                {
                                    AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                                    AttributeReference attRef = new AttributeReference();
                                    attRef.SetAttributeFromBlock(attDef, br.BlockTransform);
                                    br.AttributeCollection.AppendAttribute(attRef);
                                    tr.AddNewlyCreatedDBObject(attRef, true);
                                    attInfos.Add(attDef.Tag, new TextInfo(attDef));
                                }
                            }
                            jig = new BlockAttribJig(br, attInfos);
                        }
                        else
                        {
                            jig = new BlockJig(br);
                        }

                        TabKeyDownFilter tabFilter = new TabKeyDownFilter(jig);
                        System.Windows.Forms.Application.AddMessageFilter(tabFilter);
                        PromptResult pr = ed.Drag(jig);
                        if (pr.Status != PromptStatus.OK)
                        {
                            br.Erase();
                        }
                        System.Windows.Forms.Application.RemoveMessageFilter(tabFilter);
                    }
                }
                else
                {
                    Application.ShowAlertDialog(string.Format("Block '{0}' not found.", blockName));
                }
                tr.Commit();
            }
        }
    }

    class BlockJig : EntityJig
    {
        protected BlockReference br;
        protected Point3d pos;
        protected double ucsRot;

        protected internal double Rotation { get; set; }

        public BlockJig(BlockReference br)
            : base(br)
        {
            this.br = br;
            pos = br.Position;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            Matrix3d ucsMat = ed.CurrentUserCoordinateSystem;
            CoordinateSystem3d ucs = ucsMat.CoordinateSystem3d;
            Matrix3d ocsMat = Matrix3d.WorldToPlane(new Plane(Point3d.Origin, ucs.Zaxis));
            ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(ocsMat), ucs.Zaxis);
            this.Rotation = br.Rotation - ucsRot;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            System.Windows.Forms.Keys mods = System.Windows.Forms.Control.ModifierKeys;
            if ((mods & System.Windows.Forms.Keys.Control) > 0)
            {
                JigPromptAngleOptions jpao = new JigPromptAngleOptions(
                    "\nSpecify the rotation (release Ctrl to validate): ");
                jpao.UseBasePoint = true;
                jpao.BasePoint = br.Position;
                jpao.Cursor = CursorType.RubberBand;
                jpao.UserInputControls = (
                    UserInputControls.Accept3dCoordinates |
                    UserInputControls.UseBasePointElevation);
                PromptDoubleResult pdr = prompts.AcquireAngle(jpao);

                if (this.Rotation == pdr.Value)
                {
                    return SamplerStatus.NoChange;
                }
                else
                {
                    this.Rotation = pdr.Value;
                    return SamplerStatus.OK;
                }
            }
            else
            {
                JigPromptPointOptions jppo = new JigPromptPointOptions(
                    "\nSpecify the insertion point (or press Ctrl for rotation): ");
                jppo.UserInputControls =
                  (UserInputControls.Accept3dCoordinates |
                  UserInputControls.NullResponseAccepted);
                PromptPointResult ppr = prompts.AcquirePoint(jppo);
                if (pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint)
                {
                    return SamplerStatus.NoChange;
                }
                else
                {
                    pos = ppr.Value;
                }
                return SamplerStatus.OK;
            }
        }

        protected override bool Update()
        {
            br.Position = pos;
            UpdateRotation();
            return true;
        }

        internal void UpdateRotation()
        {
            br.Rotation = this.Rotation + ucsRot;
        }
    }

    class BlockAttribJig : BlockJig
    {
        private Dictionary<string, TextInfo> attRefInfos;
        private Transaction tr;

        public BlockAttribJig(BlockReference br, Dictionary<string, TextInfo> attInfos)
            : base(br)
        {
            attRefInfos = attInfos;
            tr = br.Database.TransactionManager.TopTransaction;
        }

        protected override bool Update()
        {
            base.Update();
            foreach (ObjectId id in br.AttributeCollection)
            {
                AttributeReference att = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                string tag = att.Tag.ToUpper();
                if (attRefInfos.ContainsKey(tag))
                {
                    TextInfo ti = attRefInfos[tag];
                    att.Position = ti.Position.TransformBy(br.BlockTransform);
                    att.Rotation = ti.Rotation + br.Rotation;
                    if (ti.IsAligned)
                    {
                        att.AlignmentPoint =
                            ti.Alignment.TransformBy(br.BlockTransform);
                        att.AdjustAlignment(br.Database);
                    }
                    if (att.IsMTextAttribute)
                    {
                        att.UpdateMTextAttribute();
                    }
                }
            }
            return true;
        }
    }

    struct TextInfo
    {
        public readonly Point3d Position, Alignment;
        public readonly bool IsAligned;
        public readonly double Rotation;

        public TextInfo(DBText text)
        {
            this.Position = text.Position;
            this.Alignment = text.AlignmentPoint;
            this.IsAligned = text.Justify != AttachmentPoint.BaseLeft;
            this.Rotation = text.Rotation;
        }
    }

    class TabKeyDownFilter : System.Windows.Forms.IMessageFilter
    {
        private const int WM_KEYDOWN = 0x100;
        private BlockJig jig;

        public TabKeyDownFilter(BlockJig jig)
        {
            this.jig = jig;
        }

        public bool PreFilterMessage(ref System.Windows.Forms.Message m)
        {
            if (m.Msg == WM_KEYDOWN && (int)m.WParam == 9)
            {
                jig.Rotation += Math.PI / 2.0;
                jig.UpdateRotation();
            }
            return false;
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 13
Ron_M
in reply to: _gile

Thanks for all of the input. I'm going to start digesting this morning and will follow up soon.
Message 8 of 13
Ron_M
in reply to: _gile

And now I know why you are an "Expert Elite".  Many thanks for this.  I'm going to try to get back the modeless library window and multiple insertion on my own.  Had it previously so I don't think that will be difficult.  Again, if I could upgrade your rating I would.

Message 9 of 13
Ron_M
in reply to: _gile

At this time I am unable to visually see the attributes in the blocks during or after insertion.  I've gone back to a point where I had that working but am so far I have proven inadequate to integrating it into the block insertion with rotate with attInfos.  The attributes are there in the block, the blocks haven't changed in construction, I can attedit the attributes, but I can't see them.  Any ideas?

Message 10 of 13
_gile
in reply to: Ron_M

Did you add the block reference and its attributes to the current space and the transaction before dragging the block?



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 11 of 13
Ron_M
in reply to: _gile

If I just insert the block in the attributes are fully visible and operate as desired.  Insert through the code you and I have been discussing, even with the block previously inserted and still visible doesn't show attributes even though they are editable through attedit.

Message 12 of 13
_gile
in reply to: Ron_M

what I want to say is that you have to add the new block reference and its attributes to the transaction in the code before dragging it (and erase it if Prompt Status is not OK).

 

Try this VB code, it works for me.

 

Imports System.Collections.Generic
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.Runtime

Namespace InsertBlockSample

    Public Class CommandMethods

        <CommandMethod("Test")> _
        Public Sub Test()
            Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
            Dim psr As PromptResult = ed.GetString(vbLf & "Enter the block name: ")
            If psr.Status <> PromptStatus.OK Then
                Return
            End If
            Dim blockName As String = psr.StringResult
            InsertBlock(blockName)
        End Sub

        Private Sub InsertBlock(blockName As String)
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor
            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
                If bt.Has(blockName) Then
                    ' Insert the block at (0, 0, 0)
                    Dim br As New BlockReference(Point3d.Origin, bt(blockName))
                    br.TransformBy(ed.CurrentUserCoordinateSystem)
                    Dim curspace As BlockTableRecord = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
                    curspace.AppendEntity(br)
                    tr.AddNewlyCreatedDBObject(br, True)

                    Dim btr As BlockTableRecord = DirectCast(tr.GetObject(bt(blockName), OpenMode.ForRead), BlockTableRecord)
                    Dim jig As BlockJig
                    If btr.HasAttributeDefinitions Then
                        ' Add the attributes and get their TextInfo
                        Dim attInfos As New Dictionary(Of String, TextInfo)()
                        Dim attribClass As RXClass = RXClass.GetClass(GetType(AttributeDefinition))
                        For Each id As ObjectId In btr
                            If id.ObjectClass = attribClass Then
                                Dim attDef As AttributeDefinition = DirectCast(tr.GetObject(id, OpenMode.ForRead), AttributeDefinition)
                                Dim attRef As New AttributeReference()
                                attRef.SetAttributeFromBlock(attDef, br.BlockTransform)
                                br.AttributeCollection.AppendAttribute(attRef)
                                tr.AddNewlyCreatedDBObject(attRef, True)
                                attInfos.Add(attDef.Tag, New TextInfo(attDef))
                            End If
                        Next
                        jig = New BlockAttribJig(br, attInfos)
                    Else
                        jig = New BlockJig(br)
                    End If

                    ' start dragging the block
                    Dim pr As PromptResult = jig.Drag()
                    If pr.Status <> PromptStatus.OK Then
                        br.[Erase]()
                    End If
                Else
                    Application.ShowAlertDialog(String.Format("Block '{0}' not found.", blockName))
                End If
                tr.Commit()
            End Using
        End Sub
    End Class

    Class BlockJig
        Inherits EntityJig

        Protected br As BlockReference
        Protected pos As Point3d
        Protected rot As Double, ucsRot As Double
        Private ed As Editor

        Protected Friend Property Rotation() As Double
            Get
                Return rot
            End Get
            Set(value As Double)
                rot = value
                Update()
            End Set
        End Property

        Public Sub New(br As BlockReference)
            MyBase.New(br)
            Me.br = br
            pos = br.Position
            ed = Application.DocumentManager.MdiActiveDocument.Editor
            Dim ucsMat As Matrix3d = ed.CurrentUserCoordinateSystem
            Dim ucs As CoordinateSystem3d = ucsMat.CoordinateSystem3d
            Dim ocsMat As Matrix3d = Matrix3d.WorldToPlane(New Plane(Point3d.Origin, ucs.Zaxis))
            ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(ocsMat), ucs.Zaxis)
            rot = br.Rotation - ucsRot
        End Sub

        Protected Overrides Function Sampler(prompts As JigPrompts) As SamplerStatus
            Dim mods As System.Windows.Forms.Keys = System.Windows.Forms.Control.ModifierKeys
            If (mods And System.Windows.Forms.Keys.Control) > 0 Then
                Dim jpao As New JigPromptAngleOptions(vbLf & "Specify the rotation (release Ctrl to validate): ")
                jpao.UseBasePoint = True
                jpao.BasePoint = br.Position
                jpao.Cursor = CursorType.RubberBand
                jpao.UserInputControls = (UserInputControls.Accept3dCoordinates Or UserInputControls.UseBasePointElevation)
                Dim pdr As PromptDoubleResult = prompts.AcquireAngle(jpao)

                If rot = pdr.Value Then
                    Return SamplerStatus.NoChange
                Else
                    rot = pdr.Value
                    Return SamplerStatus.OK
                End If
            Else
                Dim jppo As New JigPromptPointOptions(vbLf & "Specify the insertion point (or press Ctrl for rotation): ")
                jppo.UserInputControls = (UserInputControls.Accept3dCoordinates Or UserInputControls.NullResponseAccepted)
                Dim ppr As PromptPointResult = prompts.AcquirePoint(jppo)
                If pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint Then
                    Return SamplerStatus.NoChange
                Else
                    pos = ppr.Value
                End If
                Return SamplerStatus.OK
            End If
        End Function

        Protected Overrides Function Update() As Boolean
            br.Position = pos
            br.Rotation = rot + ucsRot
            Return True
        End Function

        Friend Function Drag() As PromptResult
            Dim tabFilter As New TabKeyDownFilter(Me)
            System.Windows.Forms.Application.AddMessageFilter(tabFilter)
            Dim pr As PromptResult = ed.Drag(Me)
            System.Windows.Forms.Application.RemoveMessageFilter(tabFilter)
            Return pr
        End Function
    End Class

    Class BlockAttribJig
        Inherits BlockJig

        Private attRefInfos As Dictionary(Of String, TextInfo)
        Private tr As Transaction

        Public Sub New(br As BlockReference, attInfos As Dictionary(Of String, TextInfo))
            MyBase.New(br)
            attRefInfos = attInfos
            tr = br.Database.TransactionManager.TopTransaction
        End Sub

        Protected Overrides Function Update() As Boolean
            MyBase.Update()
            For Each id As ObjectId In br.AttributeCollection
                Dim att As AttributeReference = DirectCast(tr.GetObject(id, OpenMode.ForWrite), AttributeReference)
                Dim tag As String = att.Tag.ToUpper()
                If attRefInfos.ContainsKey(tag) Then
                    Dim ti As TextInfo = attRefInfos(tag)
                    att.Position = ti.Position.TransformBy(br.BlockTransform)
                    att.Rotation = ti.Rotation + br.Rotation
                    If ti.IsAligned Then
                        att.AlignmentPoint = ti.Alignment.TransformBy(br.BlockTransform)
                        att.AdjustAlignment(br.Database)
                    End If
                    If att.IsMTextAttribute Then
                        att.UpdateMTextAttribute()
                    End If
                End If
            Next
            Return True
        End Function
    End Class

    Structure TextInfo
        Public ReadOnly Position As Point3d, Alignment As Point3d
        Public ReadOnly IsAligned As Boolean
        Public ReadOnly Rotation As Double

        Public Sub New(text As DBText)
            Me.Position = text.Position
            Me.Alignment = text.AlignmentPoint
            Me.IsAligned = text.Justify <> AttachmentPoint.BaseLeft
            Me.Rotation = text.Rotation
        End Sub
    End Structure

    Class TabKeyDownFilter
        Implements System.Windows.Forms.IMessageFilter

        Private Const WM_KEYDOWN As Integer = &H100
        Private Const VK_TAB As Integer = &H9
        Private jig As BlockJig

        Public Sub New(jig As BlockJig)
            Me.jig = jig
        End Sub

        Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean _
            Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
            If m.Msg = WM_KEYDOWN AndAlso CInt(m.WParam) = VK_TAB Then
                jig.Rotation += Math.PI * 0.5
            End If
            Return False
        End Function
    End Class

End Namespace

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 13 of 13
Ron_M
in reply to: _gile

And now we come to the point where I explain that it was my fault that the attributes weren't showing up.  Years ago I had written a module in VBA that allowed me to insert attributes with spaces in the tag and lower case letters where I wanted them.  I've used this to create many blocks in our library with attributes.  Those blocks with attributes made this way are the ones that the attributes don't visibly show when the block is inserted using the code I'm writing now.  Eventually I'm going to try to figure out exactly why but for now I can recreate any attributes that need to be and have that done by tomorrow afternoon (estimate). 

 

For giggles below is the VBA code I use to put the attributes in:

Sub Add_Attribute()
    Dim blockObj As AcadBlock
    Dim insertionPnt(0 To 2) As Double
    insertionPnt(0) = 0
    insertionPnt(1) = 0
    insertionPnt(2) = 0
    Set blockObj = ThisDrawing.Blocks.Add _
                     (insertionPnt, "Attribute")
    Dim attributeObj As AcadAttribute
    Dim height As Double
    Dim mode As Long
    Dim prompt As String
    Dim insertionPoint(0 To 2) As Double
    Dim tag As String
    Dim value As String
    height = 1
    mode = acAttributeModePreset
    prompt = "Head Detail #:"
    insertionPoint(0) = 0
    insertionPoint(1) = 0
    insertionPoint(2) = 0
    tag = "Head Detail #:"
    value = "X"
    Set attributeObj = blockObj.AddAttribute(height, mode, _
                          prompt, insertionPoint, tag, value)
    Dim blockRefObj As AcadBlockReference
    insertionPnt(0) = 2
    insertionPnt(1) = 2
    insertionPnt(2) = 0
    Set blockRefObj = ThisDrawing.ModelSpace.InsertBlock _
               (insertionPnt, "Attribute", 1#, 1#, 1#, 0)
    attributeObj.Backward = False
    attributeObj.LockPosition = True
    attributeObj.Alignment = acAlignmentMiddleCenter
    attributeObj.Update
End Sub

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost