4

私は、AutoCAD プラグインを VBA から VB.NET に変換する任務を負っていますが、現在少し行き詰っています。

私が取り組んでいるコマンドは、新しいレイヤーを作成し(または、既に存在する場合はアクティブなレイヤーとして選択します)、ユーザーが選択したポイントとdwgファイルを指定する2つの「-INSERT」コマンドを実行します。次に、前のアクティブ レイヤがアクティブ レイヤとしてリセットされます。

挿入コマンドは次のようになります。

-INSERT
C:\path\to\file.dwg
<point.x>,<point.y>,<point.z>
<documentScale>

注: コマンド内のすべての改行はvbCR(not vbCrLf) として追加されます。

私の質問は、ObjectARX に対して .NET で同じ結果を得るにはどうすればよいですか? 非同期 (コールバックなし) であるため使用できませSendStringToExecuteん。つまり、実行が完了すると、現在のレイヤーをリセットできません。おそらく を使用して、純粋な .NET コードでこの機能を複製する何らかの方法が必要BlockTableですが、その方法はわかりません。

http://through-the-interface.typepad.com/through_the_interface/2006/08/import_blocks_f.htmlにある記事に従ってみましたが、ドキュメントに目に見える影響はまったくありませんでした。私も使用しようとしましmyDatabase.Insert(transform, otherDatabase, False)たが、コマンドプロンプトはブロックが既に存在しているためスキップされたことについて何かを言いましたが、それでも変更は見られませんでした。「-INSERT」コマンドが実際に舞台裏でどれほど魔法をかけているかはわかりませんが、それを .NET で複製することは可能でしょうか? それとも、(AutoCAD によって処理されるように送信されたテキスト コマンドとしてではなく) 通常の方法として呼び出すことができるのでしょうか?

4

1 に答える 1

6

Through the Interface 投稿のコード例では、ブロックをインポートしますが、図面には挿入しません。を作成BlockReferenceしてモデル空間に追加する必要があります。また、ファイルを単一のブロックとして挿入するのではなく、ファイルからすべてのブロックを挿入します。

ファイルをブロック全体としてインポートするために使用するコードを次に示します。この関数は、図面に挿入できるブロック参照を返します。

    Private Shared Function InsertFile(ByVal FileName as String, ByVal dwgdb As Database, ByVal tr As Transaction) As BlockReference

        Dim br As BlockReference
        Dim id As ObjectId

        'use a temporary database 
        Using TempDB As New Database(False, True)

            'Get block table
            Dim bt As BlockTable = tr.GetObject(dwgdb.BlockTableId, OpenMode.ForWrite, False)

            'Create unique block name
            Dim BlockName As String = FileName.Replace("\", "").Replace(":", "").Replace(".", "")

            'check if block already exists
            If Not bt.Has(BlockName) Then
                'check if file exists
                If IO.File.Exists(FileName) Then
                    'read in the file into the temp database
                    TempDB.ReadDwgFile(FileName, IO.FileShare.Read, True, Nothing)
                    'insert the tempdb into the current drawing db, id is the new block id
                    id = dwgdb.Insert(BlockName, TempDB, True)
                Else
                    'Throw exception for missing file 
                    Throw New System.Exception(String.Format("File {0} is not found for library item {1}", FileName, item.PartNo))
                End If

            Else
                id = bt.Item(BlockName)
            End If

            'create a new block reference
            br = New BlockReference(New Point3d(0, 0, 0), id)
        End Using

        Return br


    End Function

その関数を使用してブロックをファイルに挿入する例を次に示します。この例では、ジグを使用して、ユーザーがオブジェクトを好きな場所にドロップできるようにします。それ以外の場合は、位置を設定するだけです。

      ' Get Editor
        Dim ed As Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor
        ' Get Database
        Dim dwg As Database = ed.Document.Database

        'Lock document
        Using dl As DocumentLock = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument()

            '### Changed Try Finally to using, try was hiding errors
            'Begin Transaction
            Using trans As Transaction = dwg.TransactionManager.StartTransaction()

                Dim blockRef As BlockReference = InsertFile(FileName, dwg, trans)

                'check if layer exists/create
                AcadUtil.AcadFunctions.CheckLayer(LayerName, trans, dwg)
                blockRef.Layer = LayerName

                'set focus to the editor
                Autodesk.AutoCAD.Internal.Utils.SetFocusToDwgView()

                'have the user pick insert point
                Dim BlockMove As New AcadJigs.JigBlockMove(blockRef, False, 0)
                ed.Drag(BlockMove)
                'optionally you could just set the .Position of the block reference


                ' add it to the current space, first open the current space for write
                Dim btr As BlockTableRecord = trans.GetObject(dwg.CurrentSpaceId, OpenMode.ForWrite, True, True)

                ' Add block reference to current space
                btr.AppendEntity(blockRef)

                'Capture the handle
                handle = blockRef.Handle.Value.ToString

                ' remember to tell the transaction about the new block reference so that the transaction can autoclose it
                trans.AddNewlyCreatedDBObject(blockRef, True)

                'commit the transaction
                trans.Commit()

            End Using

        End Using

そして、ここにもCheckLayer私が呼び出した関数があります。

    Public Shared Sub CheckLayer(ByVal Name As String, ByVal tr As Transaction, ByVal dwg As Database)


        Dim lt As LayerTable = CType(tr.GetObject(dwg.LayerTableId, OpenMode.ForWrite), LayerTable)

        If lt.Has(Name) Then
            Return
        Else
            Dim ly As New LayerTableRecord
            ly.Name = Name
            lt.Add(ly)
            tr.AddNewlyCreatedDBObject(ly, True)
        End If

    End Sub

念のために言っておきますが、Kean のブログは素晴らしいリソースです。私はそこから上記のすべてのコードをほとんど学びました。

完全を期すために、挿入コードでの Jig クラス i の参照を次に示します。

 Class JigBlockMove
        Inherits EntityJig

        Private _CenterPt As Point3d
        Private _ActualPoint As Point3d
        Private _LockZ As Boolean
        Private _Z As Double

        Public ReadOnly Property SelectedPoint() As Point3d
            Get
                Return _ActualPoint
            End Get
        End Property

        Public Sub New(ByVal BlockRef As BlockReference, ByVal LockZ As Boolean, ByVal Z As Double)
            MyBase.New(BlockRef)
            _CenterPt = BlockRef.Position
            _LockZ = LockZ
            _Z = Z
        End Sub

        Protected Overloads Overrides Function Sampler(ByVal prompts As JigPrompts) As SamplerStatus
            Dim jigOpts As New JigPromptPointOptions()
            jigOpts.UserInputControls = (UserInputControls.Accept3dCoordinates Or UserInputControls.NoZeroResponseAccepted Or UserInputControls.NoNegativeResponseAccepted)
            jigOpts.Message = vbLf & "Enter insert point: "
            Dim dres As PromptPointResult = prompts.AcquirePoint(jigOpts)
            If _ActualPoint = dres.Value Then
                Return SamplerStatus.NoChange
            Else
                _ActualPoint = dres.Value
            End If

            Return SamplerStatus.OK
        End Function

        Protected Overloads Overrides Function Update() As Boolean
            If _LockZ Then
                _CenterPt = New Point3d(_ActualPoint.X, _ActualPoint.Y, _Z)
            Else
                _CenterPt = _ActualPoint
            End If

            Try
                DirectCast(Entity, BlockReference).Position = _CenterPt
            Catch generatedExceptionName As System.Exception
                Return False
            End Try

            Return True
        End Function

        Public Function GetEntity() As Entity
            Return Entity
        End Function

    End Class

.NET ObjectARX での作業に関する 1 つの注意点として、AutoCAD のシングル スレッドの性質と、.NET ガベージ コレクターが別のスレッドで実行されるという事実に問題があります。データベースに追加されない一時的な AutoCAD オブジェクトを作成する場合は.Dispose()、それらを明示的に呼び出す必要があります。そうしないと、AutoCAD がクラッシュする可能性があります。ガベージ コレクター スレッドによってトリガーされるため、クラッシュもランダムに見えます。この投稿、http://through-the-interface.typepad.com/through_the_interface/2008/06/cleaning-up-aft.htmlを参照してください。

于 2013-06-27T14:02:36.257 に答える