Autodesk Community Tips- ADNオープン
Autodesk Community Tipsではちょっとしたコツ、やり方、ショートカット、アドバイスやヒントを共有しています。
ソート順:
Issue AutoLISP のリスト操作で拡張エンティティ データを付加・参照・削除するには、それぞれ、どのようなコードを作成すればいいでしょうか?   Solution 拡張エンティティ データは、AutoCAD 図面内の任意のオブジェクトに任意のカスタム データの付加、参照する手法です。AutoLISP でも、他の API 同様、拡張エンティティ データの付加・参照・削除を実装することが出来ます。   次のコードは、リスト操作で拡張エンティティ データを付加する AddXData コマンド、参照する GetXData コマンド、削除する RemoveXData コマンドの例です。   ;https://help.autodesk.com/view/OARX/2025/JPN/?guid=GUID-A94BC605-5517-437F-A6FE-D3EB8116A01A ; 拡張エンティティデータの追加例 (defun C:AddXData (/) (setq ename (car (entsel))) (if (= ename nil) (exit) ) (setq appname "Test_App") (if (= (tblsearch "APPID" appname) nil) (if (= (regapp appname) nil) (princ (strcat "\n" appname " アプリケーション名が登録出来ません... ")) ) ) (setq edata (entget ename (list "*"))) (setq exist (cdr (assoc -3 edata))) (if (= exist nil) (progn ; 他の拡張エンティティデータも付加されていない場合 (setq xdata (list (list -3 (list appname (cons 1002 "{") (cons 1000 "あいうえお") ; 文字列データ (cons 1040 999.99) ; 実数データ (cons 1070 1111) ; 整数データ (cons 1002 "}") ) ) ) ) (setq newdata (append edata xdata)) (entmod newdata) ) (progn ; 既になんらかの拡張エンティティデータが付加されている場合 (foreach xdatas exist (progn (if (= appname (car xdatas)) (progn (princ (strcat "\n既に " appname " データが付加されています...")) (exit) ; 処理中断 ) ) (setq xdata (list (list appname (cons 1002 "{") (cons 1000 "あいうえお") ; 文字列データ (cons 1040 999.99) ; 実数データ (cons 1070 1111) ; 整数データ (cons 1002 "}") ) ) ) (setq xdatas (append (list -3) (append exist xdata))) (setq newdata (subst xdatas (append (list -3) exist) edata)) (entmod newdata) (princ (strcat "\n" appname " データが付加しました...")) ) ) ) ) (princ) ) ; 拡張エンティティデータの取得例 (defun C:GetXData (/) (setq ename (car (entsel))) (if (= ename nil) (exit) ) (setq edata (entget ename (list "*"))) (setq exist (cdr (assoc -3 edata))) (if (/= exist nil) (progn (foreach xdatas exist (progn (princ (strcat "\n*** " (car xdatas))) (setq xdata (cdr xdatas)) (foreach element xdata (setq code (car element)) (setq value (cdr element)) (cond ((= code 1000) (princ (strcat "\n文字列値:" value)) ) ((= code 1040) (princ (strcat "\n実数値:" (rtos value))) ) ((= code 1070) (princ (strcat "\n整数値:" (itoa value))) ) ) ) ) ) ) (progn (princ "\n拡張エンティティデータが付加されていません...") ) ) (princ) ) ; 拡張エンティティデータの削除例 (defun C:RemXData (/) (setq ename (car (entsel))) (if (= ename nil) (exit) ) (setq appname "Test_App") (if (= (tblsearch "APPID" appname) nil) (princ (strcat "\n" appname " アプリケーション名が登録されていません... ")) ) (setq edata (entget ename (list "*"))) (setq exist (cdr (assoc -3 edata))) (if (/= exist nil) (progn (foreach xdatas exist (progn (if (= appname (car xdatas)) (progn (setq xdata (list (list appname) ) ) (setq xdatas (append (list -3) (append exist xdata))) (setq newdata (subst xdatas (append (list -3) exist) edata)) (entmod newdata) (princ (strcat "\n付加された " appname " データを削除しました...")) ) ) ) ) ) ) (princ) ) 他の 3rd party アプリケーションや AutoCAD 自身も拡張エンティティデータ利用していますので、既に付加されている拡張エンティティデータに影響を与えずに独自データを付加、削除するようご留意ください。
記事全体を表示
Issue FIELD コマンドで選択したオブジェクトの面積をフィールド文字として作成することは出来ますか?        Solution AutoCAD .NET API では、文字(DBText)または、マルチテキスト(MText)ブロックを作成後、[フィールド] ダイアログ下部に表示される「フィールド式」を SetField メソッドで設定することで、特定のオブジェクトを参照するフィールド文字を作成することが出来ます。     フィールド式中の _ObjId の値は、選択したオブジェクトの ObjectId 値になります。 次の C# コードは、ポリラインの面積をフィールド文字として作図する例です。   [CommandMethod("MyCommand")] public void MyCommand() // This method can have any name { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptEntityOptions options = new PromptEntityOptions("\nポリラインを選択:"); options.SetRejectMessage("\nポリラインを選択"); options.AddAllowedClass(typeof(Autodesk.AutoCAD.DatabaseServices.Polyline), false); PromptEntityResult acSSPrompt = ed.GetEntity(options); if (acSSPrompt.Status != PromptStatus.OK) return; PromptPointOptions ppo = new PromptPointOptions("\n挿入点を指示:"); PromptPointResult ppr = ed.GetPoint(ppo); if (ppr.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { // %<\AcObjProp.16.2 Object(%<\_ObjId 3132455955584>%).Area \f "%lu2%pr1%ps[面積:, ㎡]%ct8[0.001]">% string strId = acSSPrompt.ObjectId.OldIdPtr.ToString(); string str1 = "%<\\AcObjProp.16.2 Object(%<\\_ObjId "; string str2 = ">%).Area \\f \"%lu2%pr1%ps[面積:, ㎡]%ct8[0.001]\">%"; string format = str1 + strId + str2; DBText text = new DBText(); text.Height = 10.0; text.Position = ppr.Value; ObjectId objId = SymbolUtilityServices.GetBlockModelSpaceId(db); BlockTableRecord btr = tr.GetObject(objId, OpenMode.ForWrite) as BlockTableRecord; btr.AppendEntity(text); tr.AddNewlyCreatedDBObject(text, true); Field entField = new Field(format); entField.Evaluate(); text.SetField(entField); tr.AddNewlyCreatedDBObject(entField, true); tr.Commit(); } }   作図したフィールド文字は、参照したポリラインの変化に追従するようになります。  
記事全体を表示
Issue AutoCAD .NET API で SURFEXTEND[延長サーフェス] コマンド と同じような処理は出来ますか?   Solution サーフェス エッジの延長は、Surface.ExtendEdges メソッド で実装することが出来ます。   次の C# コードは、選択した1つのサーフェス エッジを 100 ポイント延長するものです。 SURFEXTEND[延長サーフェス] コマンド と同様に、エッジの延長でサーフェスに自己交差すると延長に失敗する場合があります。   var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; var db = doc.Database; var ed = doc.Editor; try { PromptSelectionOptions pso = new PromptSelectionOptions(); pso.MessageForAdding = "\n延長するサーフェス エッジを選択:"; pso.SingleOnly = true; pso.SinglePickInSpace = true; pso.ForceSubSelections = true; PromptSelectionResult psr = ed.GetSelection(pso); if (psr.Status != PromptStatus.OK) return; SelectionSet ss = psr.Value; SelectedObject surfedge = ss[0]; ObjectId surfId = ss.GetObjectIds()[0]; if (!surfId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(Autodesk.AutoCAD.DatabaseServices.Surface)))) { ed.WriteMessage("\nサーフェス エッジを選択を選択してください ..."); return; } using (var tr = db.TransactionManager.StartTransaction()) { var surf = tr.GetObject(surfId, OpenMode.ForWrite) as Autodesk.AutoCAD.DatabaseServices.Surface; if (surf != null) { if (surfedge.GetSubentities()[0].FullSubentityPath.SubentId.Type != SubentityType.Edge) { ed.WriteMessage("\n{0} が選択されました ...\nサーフェス エッジを選択を選択してください ...", surfedge.GetSubentities()[0].FullSubentityPath.SubentId.Type); tr.Abort(); return; } FullSubentityPath[] edges = { surfedge.GetSubentities()[0].FullSubentityPath }; surf.ExtendEdges(edges, 100.0, Autodesk.AutoCAD.DatabaseServices.Surface.EdgeExtensionType.ExtendEdge, true); } tr.Commit(); } } catch (Autodesk.AutoCAD.BoundaryRepresentation.Exception ex) { ed.WriteMessage("\nエラー: {0}\r\n at {1}", ex.Message, ex.StackTrace); }   なお、SURFEXTEND[延長サーフェス] コマンド によるサーフェス延長とは異なり、Surface.ExtendEdges メソッド  による延長では、延長されたサーフェス部分は、無条件に元のサーフェスに結合された状態になります。 SURFEXTEND[延長サーフェス] コマンド では、延長されたサーフェスを元のサーフェスと結合(合成)するか、別のサーフェスとして追加するか(既定値)をコマンド プションで指定することが出来ます。  
記事全体を表示
Issue VBA では表を TABLE オブジェクトで作成することが出来ますが、データ値にオブジェクトのプロパティをフィールドとして利用、表の内容を最新に保つようなことは出来ますか?   Solution  TABLE オブジェクト のデータセルにフィールド文字を挿入することは可能です。どのようなフィールド文字列を値に設定するべきかは、FIELD[フィールド] コマンド 表示される [フィールド] ダイアログで、特定のオブジェクトと同オブジェクト タイプで利用可能なプロパティを選択すると、ダイアログ下部の「フィールド式」に表示される内容で取得することが出来ます。   このとき、特定のオブジェクトは AutoCAD API の識別子の 1つである ObjectId で関連付けされますので、VBA マクロでフィールド式をセルに指定する際に、適宜変更する必要があります。     次のマクロは、モデル空間に作図されているすべてのオブジェクトのハンドル番号とオブジェクト タイプ、オブジェクトの色を表に書き込むものです。色の情報がフィールド式で指定されているので、作図後に REGEN[再作図] コマンド を実行すると、値が更新されるようになります。   Option Explicit Public Sub FieldTable() ' 新しい表スタイルの作成 On Error Resume Next Dim oTblDict As AcadDictionary Set oTblDict = ThisDrawing.Dictionaries.Item("ACAD_TABLESTYLE") Dim oTblStyle As AcadTableStyle Set oTblStyle = oTblDict.Item("MyTableStyle") If Err Then ' 新しい表スタイル "MyTableStyle" を作成 Err.Clear Set oTblStyle = oTblDict.AddObject("MyTableStyle", "AcDbTableStyle") ' タイトル欄の設定(背景色:青、文字色:白、文字高さ:4.0) Dim oColor As AcadAcCmColor Set oColor = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.25") oColor.ColorIndex = acWhite oTblStyle.SetColor acTitleRow, oColor oColor.ColorIndex = acBlue oTblStyle.SetBackgroundColorNone acTitleRow, False oTblStyle.SetBackgroundColor acTitleRow, oColor oTblStyle.SetTextHeight acTitleRow, 4# oTblStyle.TitleSuppressed = False ' 列見出し欄の色設定(背景色:白、文字色:緑、文字高さ:2.5) oColor.ColorIndex = acWhite oTblStyle.SetColor acHeaderRow, oColor oColor.ColorIndex = acGreen oTblStyle.SetBackgroundColorNone acHeaderRow, True oTblStyle.SetBackgroundColor acHeaderRow, oColor oTblStyle.SetTextHeight acHeaderRow, 2.5 oTblStyle.HeaderSuppressed = False ' データ欄の色設定(背景色:なし、文字色:白、文字高さ:2) oColor.ColorIndex = acWhite oTblStyle.SetColor acDataRow, oColor oTblStyle.SetBackgroundColorNone acDataRow, True oTblStyle.SetTextHeight acDataRow, 2 oTblStyle.SetAlignment acDataRow, acMiddleCenter End If ' 配置基点を指示 Dim ptBase As Variant ThisDrawing.Utility.InitializeUserInput 1 ptBase = ThisDrawing.Utility.GetPoint(, vbCrLf & "表の配置点を指定:") ' 表特性の算出 Dim nRow As Integer Dim nCol As Integer Dim dHeight As Double nRow = ThisDrawing.ModelSpace.Count + 2 ' タイトル+列見出し nCol = 3 dHeight = ThisDrawing.GetVariable("TEXTSIZE") ' 現在のレイアウトに表を配置 Dim oTbl As IAcadTable Set oTbl = ThisDrawing.ActiveLayout.Block.AddTable(ptBase, nRow, nCol, dHeight, dHeight * 10#) oTbl.RegenerateTableSuppressed = True oTbl.StyleName = "MyTableStyle" oTbl.GenerateLayout ' タイトルの設定 oTbl.SetText 0, 0, "モデル空間図形の色一覧" oTbl.SetRowHeight 0, 7# oTbl.SetText 1, 0, "ハンドル番号" oTbl.SetText 1, 1, "クラス名" oTbl.SetText 1, 2, "色" oTbl.SetRowHeight 1, 5# ' データの設定 Dim nRowCnt As Integer Dim strField As String Dim oEnt As AcadEntity nRowCnt = 2 For Each oEnt In ThisDrawing.ModelSpace ' ハンドル番号 oTbl.SetText nRowCnt, 0, oEnt.Handle ' クラス名 oTbl.SetText nRowCnt, 1, oEnt.ObjectName ' フィールド式(オブジェクトID で特定したオブジェクトの色) strField = "%<\AcObjProp Object(%<\_ObjId " & CStr(oEnt.ObjectID) & ">%).TrueColor>%" oTbl.SetText nRowCnt, 2, strField ' 行高さの設定 oTbl.SetRowHeight nRowCnt, 5# ' 行カウンタ nRowCnt = nRowCnt + 1 Next oTbl.RegenerateTableSuppressed = False End Sub   このマクロコードでは、表スタイルを登録して表に使用しています。表スタイルの内容と図面の尺度が適切でない場合がありますので、必要に応じて文字高さ等を変更してください。AutoCAD VBA では、表スタイルは TableStyle オブジェクト で作成・編集することが出来ます。この例では、椅子のブロック参照の色を水色(cyan)から青(blue)に変更しています。    
記事全体を表示
Issue VBA マクロで特定のブロック名パターンを持つブロックのブロック属性を得たいのですが、可能でしょうか? 例えば、図面内の A で始まるブロック名を持つすべてのブロックのみを対象にする、といった方法です。   Solution 特定のブロック名パターンに検索には、選択セットのフィルタ リストにアスタリスク記号でワイルドカード(*)を組み合わせて指定することが出来ます。A で始まるブロック名を持つブロックは、A* で指定可能です。   次のコードは、ワイルドカードを含めたブロック名パターンを指定して、対象ブロック参照を取得、ブロック属性の有無をチェックして、ブロック属性が含まれる場合に属性のタグと値を表示するものです。なお、*fix* や *tub など、ワイルドカードはブロック名中、どこに置いても指定することが出来ます。   Public Sub GetBlockAttribute2() On Error Resume Next Dim sset As AcadSelectionSet ThisDrawing.SelectionSets.Item("ssblocks").Delete Set sset = ThisDrawing.SelectionSets.Add("ssblocks") ThisDrawing.Utility.InitializeUserInput NoNull returnString = ThisDrawing.Utility.GetString(True, "対象のブロック名を入力 [すべて (*) ] : ") If returnString = "" Then returnString = "*" End If Dim FilterType(1) As Integer Dim FilterData(1) As Variant FilterType(0) = 0 FilterData(0) = "Insert" FilterType(1) = 2 FilterData(1) = returnString sset.Select acSelectionSetAll, , , FilterType, FilterData If sset.Count > 0 Then Dim ent As AcadEntity For Each ent In sset Dim blkRef As AcadBlockReference Set blkRef = ent ThisDrawing.Utility.Prompt vbCrLf & blkRef.Name & " ブロック参照が検出されました." Dim varAttributes As Variant varAttributes = blkRef.GetAttributes If UBound(varAttributes) < 0 Then ThisDrawing.Utility.Prompt vbCrLf & " ブロック参照に属性がありません..." Else Dim strAttributes As String For Each blkAttr In varAttributes strAttributes = "" strAttributes = strAttributes & " タグ名: " & blkAttr.TagString & " - 属性値 " & blkAttr.TextString & vbLf & " " ThisDrawing.Utility.Prompt vbCrLf & strAttributes Next End If Next Else ThisDrawing.Utility.Prompt vbCrLf & returnString & " ブロック名パターンに合致するブロック参照がありません..." End If End Sub   次の例では、ブロック名パターン * で全ブロックのブロック属性を、A* で A で始まるブロック名を持つブロック参照のブロック属性を表示しています。  
記事全体を表示
質問 AutoCADのActiveX APIを.NET アプリケーションから実行すると「呼び出し先が呼び出しを拒否しました。 (HRESULT からの例外:0x80010001 (RPC_E_CALL_REJECTED))」エラーが発生することがある。 毎回同じAutoCADのAPIの実行でエラーが発生するわけではなく、また発生頻度もまちまち(発生せずに実行できる場合もある)で規則性は見られない状況。   回答 AutoCADがビジー状態(=何らかの処理中)にあるために、Remote Procedure Call (ここでは、カスタムアプリーケーションからの、AutoCADのAPIの呼び出し)を受け付けることが出来ない状態であるため、APIの呼出しが拒否されている可能性が高い状況です。 外部プロセスからのAcitveX APIの実行は、Windowsの低レベルレイヤーではクライアントアプリケーション(この場合は外部プロセスのカスタムアプリ)が、サーバ側のアプリケーション(この場合はAutoCAD)のメインスレッドに対してWindows Messageを送信する形で、プロセス間でのAPIの実行が行われています。   このため、AutoCAD側のメインスレッドが何らかの別の処理を行っている状態にある場合、Windows Messageが処理されず呼び出し元のアプリケーションは待ちの状態となります。 呼び出し元のアプリケーションが無限に処理待ちの状態となってしまうことを防ぐ機構として、一定時間の経過後に例外を送信する仕組みがActiveXに備わっており、タイトルにあるようなエラーとして出現いたします。   通常は、AcitveXの実行系のデフオルトのリトライ処理で問題なくAPIを実行することが出来ますが、実行環境の状態や処理内容に依存して、エラーが発生するケースがあります。このような場合カスタムプログラム側でIMessageFilterのRetryRejectedCallで、ActiveX APIの呼び出しをリトライをする機構を実装することにより、状況が改善する可能性があります。   以下のブログ記事にて、C#でのIMessageFilterのリトライ処理を実装のサンプルコードが掲載されております。 https://www.keanw.com/2010/02/handling-com-calls-rejected-by-autocad-from-an-external-net-application.html   また、以下のサンプルコードは、上記ブログ記事の IMessageFilterのリトライ処理部をVB.NETに置き換えたものとなります。 Imports System.Runtime.InteropServices Imports Microsoft.Win32 Imports System Imports Microsoft.VisualBasic <ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000016-0000-0000-C000-000000000046")> Public Interface IMessageFilter <PreserveSig()> Function HandleInComingCall(ByVal dwCallType As Integer, ByVal hTaskCaller As IntPtr, ByVal dwTickCount As Integer, ByVal lpInterfaceInfo As IntPtr) As Integer <PreserveSig()> Function RetryRejectedCall(ByVal hTaskCallee As IntPtr, ByVal dwTickCount As Integer, ByVal dwRejectType As Integer) As Integer <PreserveSig()> Function MessagePending(ByVal hTaskCallee As IntPtr, ByVal dwTickCount As Integer, ByVal dwPendingType As Integer) As Integer End Interface Public Class Form1 Implements IMessageFilter Public Sub New() InitializeComponent() Dim oldFilter As IMessageFilter = Nothing CoRegisterMessageFilter(Me, oldFilter) End Sub Private Function IMessageFilter_HandleInComingCall(ByVal dwCallType As Integer, ByVal hTaskCaller As IntPtr, ByVal dwTickCount As Integer, ByVal lpInterfaceInfo As IntPtr) As Integer Implements IMessageFilter.HandleInComingCall Return 0 End Function Private Function IMessageFilter_RetryRejectedCall(ByVal hTaskCallee As IntPtr, ByVal dwTickCount As Integer, ByVal dwRejectType As Integer) As Integer Implements IMessageFilter.RetryRejectedCall 'retry in a second. Return 1000 End Function Private Function IMessageFilter_MessagePending(ByVal hTaskCallee As IntPtr, ByVal dwTickCount As Integer, ByVal dwPendingType As Integer) As Integer Implements IMessageFilter.MessagePending Return 1 End Function <DllImport("ole32.dll")> Private Shared Function CoRegisterMessageFilter(ByVal lpMessageFilter As IMessageFilter, ByRef lplpMessageFilter As IMessageFilter) As Integer End Function End Class    
記事全体を表示
現象 Inventor 2025で、.NET FrameworkをターゲットにしてビルドしたC#アプリケーションからiLogicを実行すると、System.Runtime.InteropServices.COMException HResult=0x80131165 Message=Typelib エクスポート: タイプ ライブラリが登録されていません。 (HRESULT からの例外:0x80131165) Source=mscorlibが発生する。 エラーはiLogicの実行だけではなく、iLogicのAPIを実行すると発生する。   なお、同じソースコードでInventor 2024以下のバージョンではエラーは発生せずにiLogicを実行することが出来る。   以下のサンプルコードの場合、 auto.RunRule(doc, "Rule1");でエラーとなる。 var type = Type.GetTypeFromProgID(ProgId) ?? throw new Exception($"Failed to get type from '{ProgId}'"); var app = (Inventor.Application)Activator.CreateInstance(type); app.Visible = true; var addin = app.ApplicationAddIns.get_ItemById(ILogicAddInClassId); try { if (!addin.Activated) { addin.Activate(); } } catch (Exception ex) { throw new Exception("Failed activating iLogic addin", ex); } var doc = app.Documents.Open(@"<path to ipt file>"); dynamic auto = addin.Automation; auto.RunRule(doc, "Rule1"); 診断 InventorのiLogic APIはActiveX/COM Automationを用いてAPIを公開しています。Inventor 2025の場合Inventor 本体が従来の.NET Frameworkから.NET(.NET 8)を使用するよう更新がされており、iLogic機能を提供するコンポーネントも.NET 8を使用しております。   一方で、.NETでは.NET系の言語からCOM/ActiveX を実行する際の利用されるCOM Callable WrapperにITypeInfoのサポートを削除する変更が加えられています(.NET FrameworkではITypeInfoのサポートされていた)。   このため、.NET FrameworkをターゲットにしてビルドしたC#アプリケーションから、iLogicのAPIを遅延バインディング(dynamicキーワドを用いる形で、iLogic APIを呼び出す)を用いて利用すると、.NET で実装されていないITypeInfo情報を取得する処理(GetITypeInfoFromIDispatch 関数)が実行され、エラーが発生します。 解決策 以下のような方法で、エラーの回避が可能です。   1.対象のカスタムアプリケーションを.NETを使用するようにマイグレーションを行う   2.何らかの事情で、.NET へのマイグレーションが出来ない場合、対象のアプリーションをVB.NETを用いて開発する。VB.NETの場合、上述の問題となっている関数GetITypeInfoFromIDispatchを利用しない形で、遅延バインディングによるAPI実行を行っているため、エラーとなりません。   3.Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCallを利用する 2のVB.Netでアプリケーションを開発した場合、VB.NETが内部的に利用している、遅延バインディングでのAPI実行を行う、低レベルのAPIを使用することでC#からもiLogic APIの実行が可能となります。   NewLateBinding.LateCall(auto, ((object)auto).GetType(), "RunRule1", new object[] { doc, "Rule" }, null, null, null, false);   4.dynamic 変数をobject型にCastしたのちにGetType().InvokeMember()を行う ((object)auto).GetType().InvokeMember("RunRule", BindingFlags.Public | BindingFlags.InvokeMethod, null, auto, new object[] { doc, "Rule1" });   3及び4の方法は、ソースコードの記述が非常に煩雑でわかりにくくなるため、iLogic APIの利用箇所が少ない場合などの回避としてご利用ください。      
記事全体を表示
Issue コマンド フラグに CommandFlags.UsePickSet を指定したカスタムコマンドで Editor.SelectImplied メソッドを使い、事前選択したオブジェクトを取得しようとしています。使用しているコードは次のとおりです。   [CommandMethod("MyCommand", CommandFlags.Modal | CommandFlags.UsePickSet)] public void MyCommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; PromptSelectionResult psr = ed.SelectImplied(); if (psr.Status == PromptStatus.OK) { ed.WriteMessage("\n{0} 個のオブジェクトが選択されました ...", psr.Value.GetObjectIds().Length.ToString()); } else { ed.WriteMessage("\nオブジェクトが選択されていません"); } }   このコードで事前選択したオブジェクトは取得出来ますが、コマンド実行時にオブジェクトの選択状態が解除されてしまいます。       コマンド実行時にのブジェクト選択状態の解除を抑止することは出来ますか?   Solution 事前選択したオブジェクトの選択状態を維持したままにするには、定義したカスタム コマンドのコマンド フラグに CommandFlags.Redraw を加える必要があります。コマンド定義内のコードになにかを加える必要はありません。   [CommandMethod("MyCommand", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)] public void MyCommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; PromptSelectionResult psr = ed.SelectImplied(); if (psr.Status == PromptStatus.OK) { ed.WriteMessage("\n{0} 個のオブジェクトが選択されました ...", psr.Value.GetObjectIds().Length.ToString()); } else { ed.WriteMessage("\nオブジェクトが選択されていません"); } }  
記事全体を表示
Issue VBA コードでブロック参照に設定されているブロック属性を取得する手順を教えてください。   Solution 挿入されているブロック参照は AcadBlockReference オブジェクト として取得することが出来ます。   AcadBlockReference オブジェクト には属性を取得する GetAttributes メソッド が用意されているので、このメソッドを介して各属性の情報を取得することが出来ます。   なお、ブロック参照の定義情報であるブロック定義(Block オブジェクト)には複数の属性定義(Attribute オブジェクト)を登録出来るので、 GetAttributes メソッドが複数が属性(AttributeReference オブジェクト)を扱えるよう、配列を返すことにご注意ください。   次の例は、選択したブロック参照から属性のタグと値を表示するコードです。VBA コード上、 GetAttributes メソッドが返すのが Variant 型になっています。   Public Sub GetBlockAttribute() Dim returnObj As AcadObject Dim basePnt As Variant On Error Resume Next ThisDrawing.Utility.GetEntity returnObj, basePnt, "ブロック参照を選択:" If Err = 0 Then If returnObj.EntityName = "AcDbBlockReference" Then Dim blkRef As AcadBlockReference Set blkRef = returnObj ThisDrawing.Utility.Prompt vbCrLf & blkRef.Name & " ブロック参照が選択されました." Dim varAttributes As Variant varAttributes = blkRef.GetAttributes If UBound(varAttributes) < 0 Then ThisDrawing.Utility.Prompt vbCrLf & "ブロック参照に属性がありません..." Else Dim strAttributes As String For Each blkAttr In varAttributes strAttributes = "" strAttributes = strAttributes & " タグ名: " & blkAttr.TagString & " - 属性値 " & blkAttr.TextString & vbLf & " " ThisDrawing.Utility.Prompt vbCrLf & strAttributes Next End If ElseIf returnObj.EntityName <> " AcDbBlockReference" Then ThisDrawing.Utility.Prompt vbCrLf & "ブロック参照ではありません..." End If Else ThisDrawing.Utility.Prompt vbCrLf & "何も選択されませんでした..." End If End Sub    
記事全体を表示
Issue 連続実行で図形を順番に開いて、処理、保存しようとしています。図面を順次開く必要があるので、定義コマンドに CommandFlags.Session フラグを指定してアプリケーション実行コンテキスト コマンドにしていますが、この実行コンテキストだと、 開いた図面に対して Editor.Command メソッドでコマンド実行させることが出来ません。    次の C# コードでは、C:\temp フォルダ内の図面(.dwg)を順に開き、ZOOM コマンドを実行、図面を同じ名前で保存するものですが、ZOOM コマンドの実行で例外エラーになってしまいます。  [CommandMethod("UpdateDrawings", CommandFlags.Session)] public void UpdateDrawings() { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; DocumentCollection docMgr = Application.DocumentManager; Document doc = null; try { string[] fnames = Directory.GetFiles(@"c:\temp", "*.dwg"); foreach (string fname in fnames) { ed.WriteMessage("\n--- {0}", fname); doc = docMgr.Open(fname, false); Application.DocumentManager.MdiActiveDocument.Editor.Command("ZOOM", "E"); doc.CloseAndSave(fname); } } catch (Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage("\n ERROR:{0}", ex.Message); } } なにかよい方法はないでしょうか?    Solution プリケーション実行コンテキスト コマンド(CommandFlags.Session フラグ指定コマンド)では、Editor.Command メソッドを利用したコマンドの同期コマンド呼び出しは出来ません。 今回のようなケースでは、通常、Document.SendStringToExecute メソッドで非同期的に実行させたいコマンドを送信することで、便宜上、ドキュメント実行コンテキスト でコマンド実行する対応が考えられます。 また、実行する内容にもよりますが、AutoCAD .NET API 環境では、DocumentCollection.ExecuteInCommandContextAsync メソッドを用いることで、アプリケーション実行コンテキスト コマンド内でドキュメント実行コンテキストを非同期的(Async/Await)にコマンド実行することも可能です。 [CommandMethod("UpdateDrawings", CommandFlags.Session)] public async void UpdateDrawings() { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; DocumentCollection docMgr = Application.DocumentManager; Document doc = null; try { string[] fnames = Directory.GetFiles(@"c:\temp", "*.dwg"); foreach (string fname in fnames) { ed.WriteMessage("\n--- {0}", fname); doc = docMgr.Open(fname, false); await Application.DocumentManager.ExecuteInCommandContextAsync( async (obj) => { await Application.DocumentManager.MdiActiveDocument.Editor.CommandAsync("ZOOM", "E"); }, null ); doc.CloseAndSave(fname); } } catch (Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage("\n ERROR:{0}", ex.Message); } } 同様に、 スクリプト(.scr)を用いた処理も考えることも出来ます。 ご参考:AutoCAD 雑学:図面のサムネイル画像 - Technology Perspective from Japan (typepad.com)
記事全体を表示
Issue カスタムコマンドで意図的にオブジェクトを選択させて、コマンド終了後も選択状態を維持させたいと思っています。次のようなコードを作成してみましたが、期待した状態になりません。   [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; Database db = doc.Database; PromptEntityOptions peo = new PromptEntityOptions("\nオブジェクトを選択:"); PromptEntityResult per = ed.GetEntity(peo); if (per.Status == PromptStatus.OK) { using (Transaction tr = db.TransactionManager.StartTransaction()) { Entity ent = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForWrite); ent.Highlight(); tr.Commit(); } } }   具体的には、オブジェクトのハイライトは維持するものの、事前選択のようにグリップが表示されません。また、[プロパティ] パレットには選択したオブジェクトのプロパティも表示されません。      事前選択した状態のように、ハイライトとグリップ表示、[プロパティ] パレットへのプロパティ表示を実装するには、どのようにしたらいいでしょうか?   Solution 事前選択の状態は、Editor.SetImpliedSelection メソッドで選択状態にしたい ObjectId 配列を指定することで実装することが出来ます。   [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nオブジェクトを選択:"); PromptEntityResult per = ed.GetEntity(peo); if (per.Status == PromptStatus.OK) { ObjectId[] objIds = [per.ObjectId]; ed.SetImpliedSelection(objIds); } }    
記事全体を表示
Issue ObjectARX Wizard の入手とインストール方法について押してください。   Solution ObjectARX Wizard は、https://aps.autodesk.com/developer/overview/autocad ページからダウンロードすることが出来ます。また、対応するバージョン毎に Github リポジトリからダウンロードすることも出来ます。   例えば、AutoCAD 2025 用の ObjectARX Wizard は、https://github.com/ADN-DevTech/ObjectARX-Wizards/raw/ForAutoCAD2025/ObjectARXWizardsInstaller/ObjectARXWizard.zip からダウンロードすることが出来ます。   ObjectARX Wizard のインストールでは、次の点に注意してインストールすることをお勧めします。 インストーラにデジタル署名がない旨の警告へ対応する。 管理者権限で起動したコマンドプロンプトで msiexec を使ってインストールする。 インストール時に Windows の ユーザーアカウント制御(UAC)の設定を オフ にする。 各注意点の詳細は、次のとおりです。   1.インストーラにデジタル署名がないない旨の警告へ対応する ObjectARX Wizard のインストーラ(.msi ファイル)にはデジタル署名が施されていないため、インストーラを起動しても警告が表示されてしまいます。インストール時には、次の手順でインストーラを実行してください。   2.管理者権限ドで起動したコマンドプロンプトで msiexec を使ってインストールする​ コマンド プロンプトを管理者権限で起動するには、スタート ボタンから [Windows システム ツール] >> [コマンド プロンプト] を見つけて、マウスの右ボタン メニューから [その他] >> [管理者として実行] を選択してください。 管理者権限で起動したコマンド プロンプトから、次のように、msiexec を使って ObjectARX Wizard をインストールしてください。 msiexec /i <ObjectARXWizardsName>.msi   3.インストール時に Windows の ユーザーアカウント制御(UAC)の設定を オフ にする 上記 1. ~ 2. でインストールしても ObjectARX Wizard が正しく動作しない場合は、ユーザ アカウント制御 (UAC)  の設定を一時的に無効にしてから再インストールすることをお勧めします。UAC を無効にしないと、インストール自体が成功しても、システム レジストリへの書き込みが出来ていない場合があります。    インストール中の RDS 入力について Registreterd Developer Symbol(RDS) は、アプリケーションの開発元を識別し てアプリケーション間で登録されたコマンドの競合を防ぐために使用されていましたが、.NET API への移行も進んだため、その役割を終えて、現在、登録サイトは削除されています。インストール中の次の画面では、単に任意の半角アルファベット 4 文字を入力してください。
記事全体を表示
Issue .NET 8 に対応した AutoCAD 2025 用の .NET Wizard はありますか?   Solution .NET 8 に対応した AutoCAD 2025 用の .NET Wizard は、https://aps.autodesk.com/developer/overview/autocad ページ、または Github リポジトリ(https://github.com/ADN-DevTech/AutoCAD-Net-Wizards/releases/download/v2025/PluginVsix.zip) からダウンロードすることが出来ます。   インストール AutoCAD 2025 用の .NET Wizard は、従来の .msi インストーラに代わって、VSIX テクノロジを採用した Visual Studio 2022 の機能拡張として、.vsixインストーラで提供されています。 ダウンロードした ZIP には PluginVsix.vsix ファイルが含まれていますので、任意の場所に解凍してダブルクリックすると、VSIX Installer 画面が表示されます。 [Install] ボタンをクリックして画面の指示に従ってインストールしてください。   Visual Studio 2022 がインストールされている必要があります。 AutoCAD 2025 用 .NET Wizard は、GUID を共有していた AutoCAD 2024 以前までの .NET Wizard と異なり、VSIX ベースの Visual Studio 機能拡張なので、AutoCAD 2024 以前のバージョン用に用意されたいずれか 1 つの .NET Wizard と共存インストールと運用が出来ます。   プロジェクト作成 Visual Studio 2022 を起動後に「新しいプロジェクトの作成」を選択して ”autocad” の文字でフィルタリングすると、C# プロジェクト用の「AutoCAD 2025 Plugin CS」と Visual Basic プロジェクト用の「AutoCAD 2025 Plugin VB」テンプレートが表示されます。 開発に使用したい言語のテンプレートを選択して [次へ(N)] で画面を進めると、プロジェクト名の入力とプロジェクトの作成場所を指定出来ます。両者を指定後に  [次へ(N)] をクリックすると、スケルトン プロジェクトが作成されます。 プロジェクト作成時には、NuGet サーバーからオンラインで AutoCAD 2025 用のアセンブリを解決します。NuGet パッケージから転換されたアセンブリは、C:\Users\<username>\.nuget\packages\autocad.net\25.0.1\lib\net8.0 フォルダに配置されます。 C:\Users\<username>\.nuget\packages\autocad.net\25.0.1\lib\net8.0 フォルダに配置されたアセンブリは、自動的にプロジェクトに参照設定されます。   デバッグ .NET Wizard(AutoCAD 2025 Template)で作成されたプロジェクトには、”Acad” デバッグ プロファイルが作成されています。   ”Acad” デバッグ プロファイルには、デバッグ時に起動する acad.exe へのパスが含まれますが、インストールした環境にあわせたパスの見直しはおこなわれていません。このまま、”Acad” デバッグ プロファイルでデバッグを開始するとエラーになってしまいます。   ”Acad” デバッグ プロファイル の acad.exe へのパスを変更するには、作成したプロジェクト フォルダ配下のフォルダ(C# プロジェクト:<project name>\<project name\Properties フォルダ、VB プロジェクト:<project name>\My Project フォルダ)の launchSettings.json を直接開いて、環境にあわせて acad.exe のパスに "executablePath" の値を変更後、launchSettings.jsonを保存してください。 { "profiles": { "AutoCAD_2025_Plugin_CS1": { "commandName": "Project" }, "Acad": { "commandName": "Executable", "executablePath": "C:\\Program Files\\Autodesk\\AutoCAD 2025\\acad.exe" } } }   アンインストール Visual Studio 2022 の [機能拡張(X)] メニューから [Manage Extensions...] をクリックして [機能拡張の管理] ダイアログを表示させたら、「インストール済み」の機能拡張の中から「AutoCAD 2025 Template」を選択して、[アンインストール(U)] ボタンでアンインストール出来ます。
記事全体を表示
Issue Excel VBA から Excel シート上のテーブル値に応じた作図が出来ますか?   Solution AutoCAD の ActiveX オートメーションは、Windows の COM 機構を利用します。AutoCAD のカスタマイズを手助けする AutoCAD API のとおり、Microsoft Office 製品は、自身の機能を COM サーバー として公開、内部の VBA を COM クライアントとして公開しているので、AutoCAD VBA から Excel を操作したり、Excel VBA から AutoCAD を操作することが出来ます。     Excel VBA から AutoCAD の ActiveX オートメーション インタフェースを利用するには、Excel VBA からAutoCAD オブジェクト情報を公開している AutoCAD タイプライブラリ(AutoCAD Type Library)を参照設定するだけです。    次のコードは、Excel の「精密テーブル」タブのテーブル上のカーソル列の値を読み取って、AutoCAD 図面のモデル空間に「精密滑車」ブロックを挿入するものです。   Option Explicit Public Sub CommandButton1_Click() On Error Resume Next Dim oApp As AcadApplication Set oApp = GetObject(, "AutoCAD.Application.25") If Err Then Debug.Print "AutoCAD が起動されていません..." Set oApp = CreateObject("AutoCAD.Application.25") End If oApp.Visible = True If oApp.Documents.Count = 0 Then MsgBox "アクティブな図面がありません..." Exit Sub End If Dim oDoc As AcadDocument Set oDoc = oApp.ActiveDocument oDoc.SetVariable "DIMASZ", 0.1 oDoc.SetVariable "DIMEXE", 0.2 oDoc.SetVariable "DIMEXO", 0.1 oDoc.SetVariable "DIMGAP", 0.02 oDoc.SetVariable "DIMTXT", 0.1 Call oDoc.ActiveDimStyle.CopyFrom(oDoc) Dim oModel As AcadModelSpace Set oModel = oDoc.ModelSpace Dim oEntity As AcadEntity For Each oEntity In oModel If oEntity.ObjectName = "AcDbBlockReference" Then Dim oBlockRef As AcadBlockReference Set oBlockRef = oEntity If oBlockRef.Name = "精密滑車" Then oBlockRef.Delete End If End If Next Err.Clear oDoc.Regen (acActiveViewport) Dim ptBase As Variant ptBase(0) = 0#: ptBase(1) = 0# Dim oBlock As AcadBlock Set oBlock = Nothing Set oBlock = oDoc.Blocks.Item("精密滑車") If oBlock Is Nothing Then Set oBlock = oDoc.Blocks.Add(ptBase, "精密滑車") Else For Each oEntity In oBlock oEntity.Delete Next End If Dim SelectedRange As Range Set SelectedRange = Application.ActiveCell Dim SelectedRow As Long SelectedRow = SelectedRange.Row Dim OD As Double Dim Bore As Double Dim A As Double Dim B As Double OD = Sheets("滑車テーブル").Cells(SelectedRow, 2) Bore = Sheets("滑車テーブル").Cells(SelectedRow, 3) A = Sheets("滑車テーブル").Cells(SelectedRow, 4) B = Sheets("滑車テーブル").Cells(SelectedRow, 5) Dim ptVertexs(0 To 17) As Double ptVertexs(0) = 0#: ptVertexs(1) = Bore * -0.5 ptVertexs(2) = ptVertexs(0): ptVertexs(3) = A * -0.5 ptVertexs(4) = B: ptVertexs(5) = ptVertexs(3) ptVertexs(6) = ptVertexs(4): ptVertexs(7) = ptVertexs(3) - (OD - A) * 0.5 ptVertexs(8) = ptVertexs(6) + 0.05: ptVertexs(9) = ptVertexs(7) ptVertexs(10) = ptVertexs(8) + 0.15: ptVertexs(11) = ptVertexs(9) ptVertexs(12) = ptVertexs(10) + 0.05: ptVertexs(13) = ptVertexs(9) ptVertexs(14) = ptVertexs(12): ptVertexs(15) = ptVertexs(1) ptVertexs(16) = ptVertexs(0): ptVertexs(17) = ptVertexs(1) Dim oPLine As AcadLWPolyline Set oPLine = oBlock.AddLightWeightPolyline(ptVertexs) oPLine.SetBulge 4, -0.5 Dim oLoop1(0 To 0) As AcadEntity Set oLoop1(0) = oPLine Dim pt1(0 To 2) As Double Dim pt2(0 To 2) As Double pt1(0) = 0#: pt1(1) = 0#: pt1(2) = 0# pt2(0) = ptVertexs(14): pt2(1) = 0#: pt2(2) = 0# Dim oColor As AcadAcCmColor Set oColor = AcadApplication.GetInterfaceObject("AutoCAD.AcCmColor.25") Call oColor.SetRGB(255, 0, 0) Dim oHatch1 As AcadHatch Set oHatch1 = oBlock.AddHatch(acHatchPatternTypePreDefined, "ANSI31", True, acHatchObject) oHatch1.AppendOuterLoop (oLoop1) oHatch1.PatternScale = 0.01 oHatch1.TrueColor = oColor oHatch1.Evaluate Dim oLoop2(0 To 0) As AcadEntity Set oLoop2(0) = oLoop1(0).Mirror(pt1, pt2) Dim oHatch2 As AcadHatch Set oHatch2 = oBlock.AddHatch(acHatchPatternTypePreDefined, "ANSI31", True, acHatchObject) oHatch2.AppendOuterLoop (oLoop2) oHatch2.PatternScale = 0.01 oHatch2.TrueColor = oColor oHatch2.Evaluate pt1(0) = 0#: pt1(1) = Bore * -0.5: pt1(2) = 0# pt2(0) = 0#: pt2(1) = pt1(1) + Bore: pt2(2) = 0# Call oBlock.AddLine(pt1, pt2) pt1(0) = ptVertexs(12) pt2(0) = ptVertexs(12) Call oBlock.AddLine(pt1, pt2) Dim oDimAligned As AcadDimAligned Dim ptLoc(0 To 2) As Double pt1(0) = ptVertexs(12): pt1(1) = ptVertexs(11) pt2(0) = ptVertexs(12): pt2(1) = pt1(1) + OD ptLoc(0) = pt1(0) + 1.2: ptLoc(1) = Abs(pt1(1) - pt2(1)) * 0.5: ptLoc(2) = 0# Set oDimAligned = oBlock.AddDimAligned(pt1, pt2, ptLoc) pt1(0) = ptVertexs(0): pt1(1) = ptVertexs(7) + A + (OD - A) pt2(0) = ptVertexs(0) + B: pt2(1) = ptVertexs(7) + A + (OD - A) ptLoc(0) = Abs(pt1(0) - pt2(0)) * 0.5: ptLoc(1) = pt1(1) + 1# Set oDimAligned = oBlock.AddDimAligned(pt1, pt2, ptLoc) pt1(0) = ptVertexs(0): pt1(1) = ptVertexs(3) pt2(0) = ptVertexs(0): pt2(1) = pt1(1) + A ptLoc(0) = pt1(0) - 1.2: ptLoc(1) = Abs(pt1(1) - pt2(1)) * 0.5 Set oDimAligned = oBlock.AddDimAligned(pt1, pt2, ptLoc) pt1(0) = ptVertexs(0): pt1(1) = ptVertexs(3) + (A - Bore) * 0.5 pt2(0) = ptVertexs(0): pt2(1) = pt1(1) + Bore ptLoc(0) = pt1(0) - 0.75: ptLoc(1) = Abs(pt1(1) - pt2(1)) * 0.5 Set oDimAligned = oBlock.AddDimAligned(pt1, pt2, ptLoc) '挿入基点を指定する場合 'Dim ptInsert As Variant 'oDoc.Utility.InitializeUserInput 1 'ptInsert = oDoc.Utility.GetPoint(, vbCrLf & "挿入点を指定:") '挿入基点を原点で固定する場合 Dim ptInsert(0 To 2) As Double ptInsert(0) = 0#: ptInsert(1) = 0# Call oModel.InsertBlock(ptInsert, "精密滑車", 1#, 1#, 1#, 0#) oApp.ZoomExtents End Sub
記事全体を表示
Issue VBA で拡張エンティティ データを付加・参照・削除するには、それぞれ、どのようなマクロを作成すればいいでしょうか?   Solution 拡張エンティティ データは、AutoCAD 図面内の任意のオブジェクトに任意のカスタム データの付加、参照する手法です。   AutoCAD の標準コマンドは、付加された拡張エンティティ データを認識しないので、標準ユーザー インタフェースに値が表示されることはありませんが、逆に、ユーザから付加された固有データを隠蔽することが可能です。また、プログラムを介在させない限り、拡張エンティティ データを削除したり、値を変更したりすることができないので、ユーザーによる改変を防止することもできます。    次のコードは、拡張エンティティ データを付加する SetXData マクロ、参照する GetXData マクロ、削除する RemoveXData マクロの例です。 Public Sub GetXData() 'オブジェクト選択 Dim ptPick As Variant Dim oEnt As Object Dim oUtil As AcadUtility Set oUtil = ThisDrawing.Utility oUtil.GetEntity oEnt, ptPick, "拡張オブジェクトデータを参照する図形を選択:" '拡張オブジェクトデータ取得 Dim vXDataType As Variant Dim vXDataValue As Variant oEnt.GetXData "MYDATA", vXDataType, vXDataValue If VarType(vXDataType) = vbEmpty Then oUtil.Prompt (vbCrLf & "拡張オブジェクトデータ 'MYDATA' が付加されていません...") Else 'データ表示 oUtil.Prompt (vbCrLf & "年齢は " & CInt(vXDataValue(2))) oUtil.Prompt (vbCrLf & "身長は " & CDbl(vXDataValue(3))) oUtil.Prompt (vbCrLf & "体重は " & CDbl(vXDataValue(4))) oUtil.Prompt (vbCrLf & "人相は " & CStr(vXDataValue(5))) End If End Sub Public Sub SetXData() 'オブジェクト選択 Dim ptPick As Variant Dim oEnt As Object Dim oUtil As AcadUtility Set oUtil = ThisDrawing.Utility oUtil.GetEntity oEnt, ptPick, "拡張オブジェクトデータを付加する図形を選択:" '拡張オブジェクトデータ取得 Dim vXDataType As Variant Dim vXDataValue As Variant oEnt.GetXData "MYDATA", vXDataType, vXDataValue If VarType(vXDataType) <> vbEmpty Then oUtil.Prompt (vbCrLf & "既に拡張オブジェクトデータ 'MYDATA' が付加されています...") Else '入力 Dim nAge As Integer oUtil.InitializeUserInput (7) nAge = oUtil.GetInteger(vbCrLf & "年齢を入力(整数):") Dim dHeight As Double oUtil.InitializeUserInput (7) dHeight = oUtil.GetReal(vbCrLf & "身長を入力(実数):") Dim dWeight As Double oUtil.InitializeUserInput (7) dWeight = oUtil.GetReal(vbCrLf & "体重を入力(実数):") Dim strLooks As String strLooks = oUtil.GetString(True, vbCrLf & "人相を入力(文字):") 'データ付加 Dim nDataType(0 To 6) As Integer Dim vDataValue(0 To 6) As Variant nDataType(0) = 1001 'アプリケーション名 vDataValue(0) = "MYDATA" 'アプリケーション名 nDataType(1) = 1002 'コントロール文字 vDataValue(1) = "{" 'コントロール文字 nDataType(2) = 1070 '年齢(整数) vDataValue(2) = nAge '年齢(整数) nDataType(3) = 1040 '身長(実数) vDataValue(3) = dHeight '身長(実数) nDataType(4) = 1040 '体重(実数) vDataValue(4) = dWeight '体重(実数) nDataType(5) = 1000 '人相(文字) vDataValue(5) = strLooks '人相(文字) nDataType(6) = 1002 'コントロール文字 vDataValue(6) = "}" 'コントロール文字 oEnt.SetXData nDataType, vDataValue End If End Sub Public Sub RemoveXData() 'オブジェクト選択 Dim ptPick As Variant Dim oEnt As Object Dim oUtil As AcadUtility Set oUtil = ThisDrawing.Utility oUtil.GetEntity oEnt, ptPick, "拡張オブジェクトデータを削除する図形を選択:" '拡張オブジェクトデータ取得 Dim vXDataType As Variant Dim vXDataValue As Variant oEnt.GetXData "MYDATA", vXDataType, vXDataValue If VarType(vXDataType) <> vbEmpty Then 'データ付加 Dim nDataType(0) As Integer Dim vDataValue(0) As Variant nDataType(0) = 1001 'アプリケーション名 vDataValue(0) = "MYDATA" 'アプリケーション名 oEnt.SetXData nDataType, vDataValue Else oUtil.Prompt (vbCrLf & "拡張オブジェクトデータ 'MYDATA' が付加されていません...") End If End Sub 1 オブジェクトへの付加サイズ総量が 16 キロバイトまでに制限されています。 削除したい拡張エンティティ データのアプリケーション名を SetXData メソッドで上書きすると、同じアプリケーション名の拡張エンティティ データを削除することが出来ます。 付加されている拡張エンティティ データは、Express Tools の XDLIST コマンドで参照することが出来ます。
記事全体を表示
Issue オブジェクト イベント ハンドラを使わずに、特定のオブジェクト タイプの編集を抑止することは出来ますか?   Solution 特定のオブジェクト タイプ(クラス)の編集を抑止する目的では、ObjectARX と .NET API で利用することが出来るオーバールール(Overrule)プロトコルを使用して、既定の振る舞いを変更することが可能です。   次の C# コードは、Open メソッドをオーバールール プロトコルでオーバライドし、書き込みモードのオブジェクト オープン時に例外を発生させることで、円弧(ARC)の編集を抑止する例となります。MyCommand コマンドの実行でオーバールールを有効化したり、無効化したりしています。  using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.GraphicsInterface; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System; using System.Windows.Controls; [assembly: CommandClass(typeof(AutoCAD_CSharp_plug_in1.MyCommands))] namespace AutoCAD_CSharp_plug_in1 { public class MyCommands { public class OpenOverrule : ObjectOverrule { public override void Open(DBObject dbObject, OpenMode mode) { if (mode == OpenMode.ForWrite) { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; ed.WriteMessage("\nModifying ARC is not allowed..."); base.Open(dbObject, mode); ed.Regen(); throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.NotApplicable); } } } static OpenOverrule _overrule = null; [CommandMethod("MyCommand")] static public void MyCommand() { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; if (_overrule == null) { _overrule = new OpenOverrule(); ObjectOverrule.AddOverrule(RXObject.GetClass(typeof(Arc)), _overrule, false); ObjectOverrule.Overruling = true; ed.WriteMessage("\nBegin modifying ARC overrule"); } else { ObjectOverrule.RemoveOverrule(RXObject.GetClass(typeof(Arc)), _overrule); _overrule.Dispose(); _overrule = null; ed.WriteMessage("\nEnd modifying ARC overrule"); } } } }  
記事全体を表示
Issue 現在オープンしている図面の図形を別の図面にコピーしたいのですが、コピー元の図形が参照している画層や線種を一緒にコピーすることは出来ますか?   もし、可能なら、寸法をコピーする際に参照している寸法スタイルを、テキスト文字をコピーする際に参照している文字スタイルを同時にコピー出来ると便利です。   Solution AutoCAD には、オブジェクトの参照関係(つながり)を維持したままコピーをおこなう ディープクローン という機構が存在しています。   ディープクローンを使用すると、図形そのもののコピーだけでなく、そのオブジェクトが参照している他のオブジェクトも深く(ディープ)参照して、元の状態を維持したまま対象図形を別の図面にコピーすることが可能です。例えば、図面 A の線分が同じ図面の ”通り芯” 画層している場合、その線分を図面 B にディープクローンすると、”通り芯” 画層も一緒に、そして、自動的にコピーしてくれます。寸法スタイルや文字スタイルも同様にコピーされます。   VBA が利用する ActiveX オートメーションでは、CopyObjects メソッド でディープクローンを利用することが出来ます。    次の VBA マクロはタイル状に並べた左側の図面のモデル空間の図形を、右側の図面にディープクローンするものです。VBA マクロ実行前、右側の図面には図形や画層はありませんが、図形のディープクローン時に画層もコピーされていることがわかります。   Public Sub DeepClone() Dim A As AcadDocument Set A = ThisDrawing.Application.ActiveDocument Dim B As AcadDocument Set B = ThisDrawing.Application.Documents.Item(1) ThisDrawing.Application.ActiveDocument = A Dim entity As AcadEntity Dim retObjects As Variant Dim index As Integer Dim length As Integer ReDim objCollection(0 To A.ModelSpace.Count - 1) As Object index = 0 For Each entity In A.ModelSpace ThisDrawing.Utility.Prompt (vbCrLf & entity.ObjectName) Set objCollection(index) = entity index = index + 1 Next retObjects = A.Database.CopyObjects(objCollection, B.ModelSpace) ThisDrawing.Application.ActiveDocument = B For index = 0 To length retObjects(index).Update Next B.Application.ZoomExtents End Sub  AutoCAD ActiveX オートメーションでは、ディープクローン先に参照している画層やスタイルがあると、画層やスタイルのディープクローンはおこなわれません(上書きはしません)。 
記事全体を表示
Issue AutoCAD を使用していると、テーブル(*Tnn ) / 寸法(*Dnn)/ ハッチング( *Xnn)などの匿名ブロックが作成されています。( nn は図面内で一意になるような数字)   INSERT コマンドや BLOCK コマンドのユーザ インタフェースには匿名ブロック名が表示されないので、カスタマイズ運用時に便利なのですが、この匿名ブロックを AutoCAD .NET API で作成することは出来ますか?   Solution API で(ユーザー定義で)登録することが出来る匿名ブロックの作成では、新しく作成するブロック名に "*U" の名前をつけることで、AutoCAD が図面内で重複しないように数字を付加してブロック名を定義します。 次の C# コードは、円を含む匿名ブロックを作成するものです。   Database db = HostApplicationServices.WorkingDatabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { try { // 匿名ブロック定義の作成 BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite); BlockTableRecord blkdef = new BlockTableRecord(); Circle oCirc = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0); blkdef = new BlockTableRecord(); blkdef.Name = "*U"; bt.Add(blkdef); tr.AddNewlyCreatedDBObject(blkdef, true); blkdef.AppendEntity(oCirc); tr.AddNewlyCreatedDBObject(oCirc, true); ed.WriteMessage("\n匿名ブロック名 : {0}", blkdef.Name); // 匿名ブロック参照の作成 Point3d pt = new Point3d(100.0, 100.0, 0.0); BlockReference blkref = new BlockReference(pt, blkdef.ObjectId); BlockTableRecord model = (BlockTableRecord)tr.GetObject(bt["*MODEL_SPACE"], OpenMode.ForWrite); model.AppendEntity(blkref); tr.AddNewlyCreatedDBObject(blkref, true); tr.Commit(); } catch (Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage("\n例外エラー : {0}", ex.ToString()); } }
記事全体を表示
Issue 現在オープンしている図面に配置されている "TEST" ブロック参照を、別の図面に定義されている同じ名前のブロック定義を元に置き換えたいのですが、AutoCAD VBA で可能でしょうか?    Solution AutoCAD VBA で現在の図面上のブロック参照を置き換えるには、置き換え対象のブロック定義を持つ図面をオープン後、ブロック定義を現在の図面にディープクローン、同ブロック定義を元にブロック参照を挿入する必要があります。 この場合、ディープクローン前に現在の図面から置き換え対象のブロック定義と、同ブロック定義を元に挿入されているブロック参照を削除しておく必要があります。   現在の図面(ブロック参照を置き換える図面を図面 A、置き換えるブロック定義を含む外部図面を図面 B とすると、おおまかに次のような手順となります。   図面 A を変数に保存 図面 A 上で対象となるブロック参照数を把握 図面 A 上で対象となるブロック参照の挿入パラメーターをオブジェクト変数に保存 図面 A 上で対象となるブロック参照のを削除 図面 A 上で対象となるブロック定義を削除 ブロック定義をディープクローンするため図面 B をオープン 図面 B 上でディープクローンするブロック定義を変数に保存 対象となるブロック定義を CopyObjects メソッド でディープクローン 図面 B をクローズ ディープクローンしたブロック定義を元に保持したパラメーターで挿入 この実装例は次の通りです。    クラス モジュール(Parameters クラス定義): Option Explicit ' ブロック参照パラメーター Public X As Double Public Y As Double Public Z As Double Public XS As Double Public YS As Double Public ZS As Double Public R As Double Private Sub Class_Initialize() X = 0# Y = 0# Z = 0# XS = 0# YS = 0# ZS = 0# R = 0# End Sub   プロシージャ: Public Sub ReplaceBlock() ' 図面 A を変数に保存 Dim A As AcadDocument Set A = ThisDrawing.Application.ActiveDocument ' 図面 A 上で対象となるブロック参照数を把握 Dim target As String target = "TEST" Dim entity As AcadEntity Dim block As AcadBlockReference Dim length As Integer length = 0 For Each entity In A.ModelSpace If entity.ObjectName = "AcDbBlockReference" Then Set block = entity If block.Name = target Then length = length + 1 End If End If Next ' 図面 A 上で対象となるブロック参照の挿入パラメーターをオブジェクト変数に保存 Dim index As Integer index = 0 ReDim params(length - 1) As Parameters For Each entity In A.ModelSpace If entity.ObjectName = "AcDbBlockReference" Then Set block = entity If block.Name = target Then Set params(index) = New Parameters params(index).X = block.InsertionPoint(0) params(index).Y = block.InsertionPoint(1) params(index).Z = block.InsertionPoint(2) params(index).XS = block.XScaleFactor params(index).YS = block.YScaleFactor params(index).ZS = block.ZScaleFactor params(index).R = block.Rotation index = index + 1 End If End If Next ' 図面 A 上で対象となるブロック参照のを削除 For Each entity In A.ModelSpace If entity.ObjectName = "AcDbBlockReference" Then Set block = entity If block.Name = target Then block.Delete End If End If Next ' 図面 A 上で対象となるブロック定義を削除 A.Blocks.Item(target).Delete ' ブロック定義をディープクローンするため図面 B をオープン Dim B As AcadDocument Set B = A.Application.Documents.Open("<your_own_path>\B.dwg") ' 図面 B 上でディープクローンするブロック定義を変数に保存 Dim objCollection(0) As Object Set objCollection(0) = B.Blocks.Item(target) ThisDrawing.Application.ActiveDocument = A ' 対象となるブロック定義をディープクローン Dim retObjects As Variant retObjects = B.Database.CopyObjects(objCollection, A.Blocks) ' 図面 B をクローズ B.Close ' ディープクローンしたブロック定義を元に保持したパラメーターで挿入 Dim insertionPnt(0 To 2) As Double For index = 0 To length - 1 insertionPnt(0) = params(index).X insertionPnt(1) = params(index).Y insertionPnt(2) = params(index).Z Set block = A.ModelSpace.InsertBlock(insertionPnt, target, params(index).XS, params(index).YS, params(index).ZS, params(index).R) Next End Sub    
記事全体を表示
Issue 次のような「MS Pゴシック」を持つ文字スタイルを作成したいのですが、TextStyleTableRecord.FileName プロパティへの指定方法がわかりません。 どうすれば「MS Pゴシック」を指定することが出来ますか?   Solution 「MS Pゴシック」フォントは、TrueType Collection ファイルとして「MS ゴシック」や「MS UI Gothic」などと共に定義されています。   定義ファイル名は msgothic.ttc になり、FileName プロパティが要求する .ttf ファイルに合致しないため、同プロパティに指定することが出来ません。   この場合、.次のコードのように、ttf に分解した状態のファイル名で指定することが可能です。   Database db = HostApplicationServices.WorkingDatabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { TextStyleTable tbl = (TextStyleTable)tr.GetObject(db.TextStyleTableId, OpenMode.ForWrite); if (!tbl.Has("スタイル1")) { TextStyleTableRecord rec = new TextStyleTableRecord(); rec.Name = "スタイル1"; rec.FileName = "MS PGothic.ttf"; tbl.Add(rec); tr.AddNewlyCreatedDBObject(rec, true); } else { ed.WriteMessage("\nスタイル1 文字スタイルは既に登録されています..."); } tr.Commit(); }   また、オンラインヘルプ フォントを割り当てる(.NET) のように  FontDescriptor オブジェクトで指定することも出来ます。  Database db = HostApplicationServices.WorkingDatabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { TextStyleTable tbl = (TextStyleTable)tr.GetObject(db.TextStyleTableId, OpenMode.ForWrite); if (!tbl.Has("スタイル1")) { TextStyleTableRecord rec = new TextStyleTableRecord(); rec.Name = "スタイル1"; tbl.Add(rec); rec.Font = new FontDescriptor("MS Pゴシック", false, false, 128, 50); tr.AddNewlyCreatedDBObject(rec, true); } else { ed.WriteMessage("\nスタイル1 文字スタイルは既に登録されています..."); } tr.Commit(); }   ご参考: 128 - FontDescriptor.CharacterSet 値:LOGFONT 構造体 の lfCharSet 50 - FontDescriptor.PitchAndFamily 値:LOGFONT 構造体 の lfPitchAndFamily
記事全体を表示