Autodesk Community Tips- ADNオープン
Autodesk Community Tipsではちょっとしたコツ、やり方、ショートカット、アドバイスやヒントを共有しています。
ソート順:
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
記事全体を表示
質問 .Net で、Inventor API AutoCADBlock.GetPromptTextValues()でブロックの属性値が取得できない。 VBAからはAutoCADBlock.GetPromptTextValues()で値が取得できているため、データの問題ではありません。.Netからは、AutoCADBlock.GetPromptTextValues()を利用できないのでしょうか? 回答 .Net言語からAutoCADBlock.GetPromptTextValues()を利用する場合、outパラメータの引数をメソッド実行前にstring配列で初期化する必要があります。   以下はC#の場合のサンプルとなります。 object tags = new string[] { }; object attrs = new string[] { }; oAcadBlock.GetPromptTextValues(out tags, out attrs);
記事全体を表示
現象 Autocad 2022のVBAでCreateObject("VL.Application.16")を実行すると「実行エラー-2147220999(800701f9): オートメーション エラーです。DLLでエラーが発生しました」となってします。 同じ処理は、旧バージョンのAutoCADでは問題なく動作をしていました。   解決策 AutoCAD 2022以降のバージョンでは、CreateObject()で"VL.Application.16"を取得できないように変更がされております。VBAのプログラムから、AutoCADのActiveX APIで直接オブジェクトを取得するAPIが存在しないAutoCADのCOMモデル内のオブジェクトを取得する場合には、CreateObject()ではなくAutoCAD ApplicationオブジェクトのGetInterfaceObject メソッド(ActiveX) を利用することを推奨いたします。   今回の場合、以下のサンプルコードの様に変更することで対応が可能です。 なお、以下サンプルコードの変数appはAutoCADのActiveX APIでのApplicationオブジェクトが格納された変数となります。   Set VL = app.GetInterfaceObject("VL.Application.16")  
記事全体を表示
質問 InventorのアドインでVault接続状態を確認し、接続していない場合はログインをしてVaultのConnectionを取得したい。 回答 Vault APIのConnectionManager.Instance.Connectionにより接続中のVaultコネクションオブジェクトを取得することができます。 接続されていない場合は、InventorのVaultログインコマンド(内部名:ContentLoginCmdIntName)を実行することで、ログインダイアログを表示することが可能です。   以下は、上述のAPIを使用したサンプルコードとなります。 using VDF = Autodesk.DataManagement.Client.Framework; using VB = Connectivity.Application.VaultBase; VDF.Vault.Currency.Connections.Connection conn = VB.ConnectionManager.Instance.Connection; if (null == conn) { try { ControlDefinition oCtlDef = m_inventorApplication.CommandManager.ControlDefinitions["ContentLoginCmdIntName"]; oCtlDef.Enabled = true; oCtlDef.Execute(); conn = VB.ConnectionManager.Instance.Connection; } catch (Exception ex) { } } if (null != conn) { MessageBox.Show(String.Format("Vault = {0}, UserID = {1}, User Name = {2}",conn.Vault, conn.UserID, conn.UserName)); }   なお、Visual Stuidoプロジェクトの参照設定で、Vault SDK配下のAutodesk.DataManagement.Client.Framework.dllおよびVaultインストールフォルダ配下のConnectivity.Application.VaultBase.dllファイルの参照の追加が必要となる点にご留意ください。  
記事全体を表示
質問 AutoCAD Plant3D .net APIで機器にノズルがついているかを判定する方法はありますか   回答 機器に設定したノズルは、Plant3Dの.net API Equipment.AllSubPartsにより取得が可能です。 ノズルが設定されていない場合、Equipment.AllSubParts.Countが0となるため、これによりノズルの有り無しを判定が可能です。 以下は選択したエンティティのEquipment.AllSubParts.Countを取得し、コマンドラインにメッセージを表示するサンプルコードです。   Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityResult res = ed.GetEntity("Pick Object : "); if (res.Status == PromptStatus.OK) { ObjectId objectId = res.ObjectId; Database trDatabase = objectId.Database; using (Transaction tr = trDatabase.TransactionManager.StartTransaction()) { Equipment equipment = tr.GetObject(objectId, OpenMode.ForRead) as Equipment; if( equipment != null) { ed.WriteMessage("\n Selected equipment has {0} nozzles.", equipment.AllSubParts.Count); } else { ed.WriteMessage("\n Selected entity is not a equipment."); } } }  
記事全体を表示
質問 AutoCAD .net APIで寸法拘束パラメータとユーザ定義パラメータをグループ化するグループフィルタを作成する方法はありますか。 回答 AutoCADのデータ構造として、グループフィルタはAssocNetworkのXData(拡張データ)にアプリケーション 名ACAD_NETWORK_GROUPSにて定義されます。グループフィルタの情報は、アプリケーションACAD_NETWORK_GROUPSの開始エントリ(1001,ACAD_NETWORK_GROUPS)に続いて、(1070,1)(1000, グループフィルタ名1)(1070,2)(1000, グループフィルタ名2)の形でデータを保持します。 ここで、Dxfグループ コード1070の値はグループフィルタの内部Idを、Dxfグループ コード1000の値はグループフィルタ名に対応します。   例えば拡張データの内容が(1001,ACAD_NETWORK_GROUPS)(1070,1)(1000, グループフィルタ1)(1070,2)(1000, グループフィルタ2)の場合、グループフィルタとして”グループフィルタ1”と”グループフィルタ2”が定義されており、それぞれの内部Idが1と2である状態となります。   グループフィルタ内のパラメータについては、上述の内部Idをパラメータ側から参照する形でAssocVariableのxDataに保存されている形となります。 AssocVariableのxDataにはアプリケーション名PARAMETER_GROUPSにて、(1001,PARAMETER_GROUPS)(1070,1)(1070,2)といった形でデータが保持されておりDxfグループコード1070の値が上述のグループフィルタのIdとなります。   このため、グループフィルタ(パラメータグループ)を新規作成する場合は、AssocNetworkのxDataに追加をする形となります。 また、既存のグループフィルタ内のパラメータを取得する場合には、AssocNetworkのxDataから対象のグループフィルタのIdを取得したのちに、各AssocVariableのxDataを参照して、PARAMETER_GROUPSアプリケーションに対象のグループフィルタのIdを持つデータがあるかを確認する形となります。   以下は新規のグループフィルタを作成するサンプルコードとなります。 [CommandMethod("AddFilterGroup")] public static void AddFilterGroup() { Document dc = Application.DocumentManager.MdiActiveDocument; Database db = dc.Database; Editor ed = dc.Editor; ObjectId networkId = AssocNetwork.GetInstanceFromObject(db.CurrentSpaceId, false, true, "ACAD_ASSOCNETWORK"); if (networkId == ObjectId.Null) return; const string APP_NAME = "ACAD_NETWORK_GROUPS"; PromptResult pr = ed.GetString("Type filter name to create."); string groupFilterName = pr.StringResult; using (Transaction tx = db.TransactionManager.StartTransaction()) { RegAppTable regTable = (RegAppTable)tx.GetObject(db.RegAppTableId, OpenMode.ForRead); if (!regTable.Has(APP_NAME)) { regTable.UpgradeOpen(); RegAppTableRecord app = new RegAppTableRecord(); app.Name = APP_NAME; regTable.Add(app); tx.AddNewlyCreatedDBObject(app, true); } using (AssocNetwork network = tx.GetObject(networkId, OpenMode.ForWrite, false) as AssocNetwork) { ResultBuffer rb = network.XData; if (rb != null) { IEnumerator enu = rb.GetEnumerator(); while (enu.MoveNext()) { TypedValue wk = (TypedValue)enu.Current; ed.WriteMessage("\n" + wk.TypeCode.ToString() + " = " + wk.Value.ToString()); } int nextIndex = 1; var wrapper = rb.Cast<TypedValue>(); //Find "ACAD_NETWORK_GROUPS" in xData if (0 != wrapper.Where<TypedValue>( tv => tv.Value.ToString() == APP_NAME && tv.TypeCode == 1001).Count<TypedValue>()) { //if there is "ACAD_NETWORK_GROUPS" in xData, check duplication of filter. bool inTargetApp = false; if (0 != wrapper.Where(tv =>{ if (inTargetApp) { if (tv.TypeCode == 1000 && tv.Value.ToString() == groupFilterName) { return true; } else if (tv.TypeCode == 1001) { inTargetApp = false; } } else { if (tv.Value.ToString() == APP_NAME && tv.TypeCode == 1001) { inTargetApp = true; } } return false; }).Count()) { //abort if there is same filter name. ed.WriteMessage("\nThe group fileter already exists."); tx.Abort(); return; } else { inTargetApp = false; nextIndex = wrapper.Max<TypedValue>(tv => { if (inTargetApp) { if (tv.TypeCode == 1070) { return Convert.ToInt32(tv.Value); } else if (tv.TypeCode == 1001) { inTargetApp = false; } } else { if (tv.Value.ToString() == APP_NAME && tv.TypeCode == 1001) { inTargetApp = true; } } return 0; } ) + 1; rb = new ResultBuffer(); inTargetApp = false; bool added = false; foreach (var tv in wrapper) { if (inTargetApp) { //start of next application if (tv.TypeCode == 1001) { inTargetApp = false; added = true; rb.Add(new TypedValue(1070, nextIndex)); rb.Add(new TypedValue(1000, groupFilterName)); } rb.Add(tv); } else { rb.Add(tv); if (tv.Value.ToString() == APP_NAME && tv.TypeCode == 1001) { inTargetApp = true; } } } if(!added) { rb.Add(new TypedValue(1070, nextIndex)); rb.Add(new TypedValue(1000, groupFilterName)); } } } else { //Add "ACAD_NETWORK_GROUPS" if not found. rb.Add(new TypedValue(1001, APP_NAME)); rb.Add(new TypedValue(1070, nextIndex)); rb.Add(new TypedValue(1000, groupFilterName)); } network.XData = rb; } else { network.XData = new ResultBuffer(new TypedValue(1001, APP_NAME), new TypedValue(1070, 1), new TypedValue(1000, groupFilterName)); } } tx.Commit(); } ed.Command("PARAMETERS"); }   また、以下は指定したパラメータグループに含まれているパラメータを確認するサンプルコードとなります。 [CommandMethod("GetFilterGroupParameters")] public static void GetFilterGroupParameters() { Document dc = Application.DocumentManager.MdiActiveDocument; Database db = dc.Database; Editor ed = dc.Editor; ObjectId networkId = AssocNetwork.GetInstanceFromObject(db.CurrentSpaceId, false, true, "ACAD_ASSOCNETWORK"); if (networkId == ObjectId.Null) return; const string APP_NAME = "ACAD_NETWORK_GROUPS"; PromptResult pr = ed.GetString("Type filter name to get parameters."); string groupFilterName = pr.StringResult; using (Transaction tx = db.TransactionManager.StartTransaction()) { RegAppTable regTable = (RegAppTable)tx.GetObject(db.RegAppTableId, OpenMode.ForRead); if (!regTable.Has(APP_NAME)) { ed.WriteMessage("\n There is no spcified parameter group."); return; } using (AssocNetwork network = tx.GetObject(networkId, OpenMode.ForWrite, false) as AssocNetwork) { ResultBuffer rb = network.XData; if (rb == null) { ed.WriteMessage("\n There is no spcified parameter group."); return; } IEnumerator enu = rb.GetEnumerator(); while (enu.MoveNext()) { TypedValue wk = (TypedValue)enu.Current; ed.WriteMessage("\n" + wk.TypeCode.ToString() + " = " + wk.Value.ToString()); } var wrapper = rb.Cast<TypedValue>(); bool inTargetApp = false; int targetIndex = 0; bool found = false; foreach(var tv in wrapper) if (inTargetApp) { if(tv.TypeCode == 1070) { targetIndex = Convert.ToInt32(tv.Value); } else if(tv.TypeCode == 1000 && tv.Value.ToString() == groupFilterName) { found = true; break; } } else { if (tv.Value.ToString() == APP_NAME && tv.TypeCode == 1001) { inTargetApp = true; } } } if (!found) { ed.WriteMessage("\n There is no spcified parameter group."); return; } //Now iterate though AssocActions to find variable which has targetIndex in it's xData. foreach (ObjectId actionId in network.GetActions) { if (actionId == ObjectId.Null) continue; DBObject obj = tx.GetObject(actionId, OpenMode.ForRead); if (actionId.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(AssocVariable)))) { AssocVariable var = obj as AssocVariable; ed.WriteMessage("\n - AssocVariable " + var.Name + " = " + var.Expression); ResultBuffer pRb = var.XData; if (pRb != null) { var pWrapper = pRb.Cast<TypedValue>(); //loop thourough result buffer to find typedvalue with (1070, targetIndex). inTargetApp = false; foreach (var tv in pWrapper) { if (inTargetApp) { if (tv.TypeCode == 1070 && targetIndex == Convert.ToInt32(tv.Value)) { ed.WriteMessage(" is referenced by specified group."); } else if(tv.TypeCode == 1001) { inTargetApp = false; } } else { if (tv.Value.ToString() == "PARAMETER_GROUPS" && tv.TypeCode == 1001) { inTargetApp = true; } } } } } } } tx.Commit(); } }
記事全体を表示
質問 AutoCADの.net APIで寸法拘束の拘束フォームを変更する方法はありますか。 回答 残念ながら、AutoCADの.net APIには寸法拘束の拘束フォームを変更するAPIはありません。 一方でObjectARX C++のAPIには対応するAPIが存在するため、.netのプログラムからは、P/Invoke を用いることで.netから寸法拘束の拘束フォームを変更することが可能です。   寸法拘束の拘束フォームの変更には、ObjectARX C++の寸法線の基底クラスAcDbDimensionの、isConstraintDynamic()メソッドおよびsetConstraintDynamic(bool isDynamic)メソッドを使用します。   isConstraintDynamic()メソッドは、その戻り値で現在の拘束フォームの設定状態を確認することが出来ます(true:ダイナミック, false:注釈)。 また、setConstraintDynamic(bool isDynamic)メソッドは、引数に指定した値で拘束フォームの設定状態を変更することが可能です。   以下は、AutoCAD 2023でP/Invokeを用いて.net で作成したAutoCADのカスタムコマンドから、選択した寸法拘束の拘束フォームの設定を変更するサンプルコードとなります。 [CommandMethod("FlipConstraintsForm")] public void FlipConstraintsForm() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; var option = new PromptEntityOptions("\n" + "Select a dimension constraints."); PromptEntityResult result = ed.GetEntity(option); if (result.Status != PromptStatus.OK) return; ObjectId id = result.ObjectId; using (Transaction tx = db.TransactionManager.StartTransaction()) { Dimension dim = tx.GetObject(id, OpenMode.ForWrite) as Dimension; DatabaseExtensions.DatabaseExtensions.Dimension_FlipConstraintsForm(dim); tx.Commit(); } } //DatabaseExtensions.cs namespace DatabaseExtensions { public class DatabaseExtensions { private static class AcDbDimension { [DllImport("acdb24.dll", CallingConvention = CallingConvention.ThisCall, CharSet = CharSet.Unicode, EntryPoint = "?isConstraintDynamic@AcDbDimension@@QEBA_NXZ")] [return: MarshalAs(UnmanagedType.Bool)] public static extern Boolean isConstraintDynamic(IntPtr dimension); [DllImport("acdb24.dll", CallingConvention = CallingConvention.ThisCall, CharSet = CharSet.Unicode, EntryPoint = "?setConstraintDynamic@AcDbDimension@@QEAA?AW4ErrorStatus@Acad@@_N@Z")] public static extern ErrorStatus setConstraintDynamic(IntPtr dimension, [MarshalAs(UnmanagedType.Bool)] Boolean bDynamic); } public static void Dimension_FlipConstraintsForm(Dimension dim) { dim.UpgradeOpen(); bool isDynamic = AcDbDimension.isConstraintDynamic(dim.UnmanagedObject); AcDbDimension.setConstraintDynamic(dim.UnmanagedObject, !isDynamic); } } }   DllImportによりImportするdllファイル名は、対象のAutoCADのバージョンに依存して変わる点にご留意ください。   なお、P/Invokeを用いたAPIの実装方法についてはこちらの記事に開設がありますので、ご参照ください。
記事全体を表示
Issue Civil3DのImportSubassembly APIでSubassemblyComposerで作成したサブアセンブリが正しく挿入されmせん。API自体はエラーもなく実行できていますが、挿入したサブアセンブリには作成時に設定したパラメータも表示されず、また形状もSubassemblyComposerで作成したものではなく、「○」の状態となってしまう。 なお、対象のサブアセンブリはツールパレットには読み込まれており、GUIからは正しく図面に挿入することが出来ています。   Solution ImportSubassembly APIの不具合により、正しく挿入ができていない状況と思われます。   ImportSubassemblyの引数に指定しているatcファイルをテキストエディタで開き、ファイル内のDataTypeの記述を編集することでImportSubassembly にて配置をすることが可能となります。   DataType="long" → DataType="Long" DataType="double" → DataType="Double" DataType="bool" → DataType="Bool" DataType="string" → DataType="String"  
記事全体を表示
Issue 図面ファイルを開いた際に、その図面ファイルの DWG ファイル形式が表示されます。 この情報を AutoCAD .NET API で取得することは出来ますか?    Solution 図面ファイル形式は、Database.OriginalFileVersion プロパティで返される DwgVersion 値で取得することが出来ます。    次のコードは、その C# 使用例です。   [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; Database db = Application.DocumentManager.MdiActiveDocument.Database; ed.WriteMessage("\nSaved DWG format:{0}", GetDwgFormat(db.OriginalFileVersion)); } private string GetDwgFormat(DwgVersion ver) { string dwgFormat = string.Empty; switch (ver) { case DwgVersion.AC1002: dwgFormat = "AutoCAD 2.5 形式"; break; case DwgVersion.AC1003: dwgFormat = "AutoCAD 2.6 形式"; break; case DwgVersion.AC1004: dwgFormat = "AutoCAD R9 形式"; break; case DwgVersion.AC1006: dwgFormat = "AutoCAD R10 形式"; break; case DwgVersion.AC1009: dwgFormat = "AutoCAD R11/R12 形式"; break; case DwgVersion.AC1012: dwgFormat = "AutoCAD R13 形式"; break; case DwgVersion.AC1014: dwgFormat = "AutoCAD R14 形式"; break; case DwgVersion.AC1015: dwgFormat = "AutoCAD 2000 形式"; break; case DwgVersion.AC1021: dwgFormat = "AutoCAD 2007 形式"; break; case DwgVersion.AC1024: dwgFormat = "AutoCAD 2010 形式"; break; case DwgVersion.AC1027: dwgFormat = "AutoCAD 2013 形式"; break; case DwgVersion.AC1032: dwgFormat = "AutoCAD 2018 形式"; break; case DwgVersion.AC1800: case DwgVersion.AC1800a: dwgFormat = "AutoCAD 2004 形式"; break; default: dwgFormat = "Unknown 形式"; break; } return dwgFormat; }    
記事全体を表示
Issue .NET API で開発したアドイン アプリのアセンブリを他のコンピューターで動作テストしようとしています。 一旦、アセンブリを共有サーバーにアップロードして他のコンピューターにダウンロードすると、そのアセンブリがロード出来ません。  具体的には System.IO.FileLoadException 例外エラーが表示されてロードできません。 どうすればいいでしょうか?     Solution .NET Framework のセキュリティ ポリシーにより、クラウド ストレージを含むネットワーク リソースからダウンロードしたアセンブリ ファイルは読み込みがブロックされています。 Windows エクスプローラーからアセンブリのプロパティ ダイアログを表示させると、「許可する」項(Windows バージョンによっては「ブロック解除」項)が表示されます。 この項目にチェックしてブロックを解除すると、NETLOAD 出来るようになります。 一度、NETLOAD 時に例外エラーが発生した場合には、次の NETLOAD 作業前に AutoCAD を再起動してください。(キャッシュされたアセンブリ情報をクリアする目的)
記事全体を表示
Issue AutoCAD .NET API:ダウンロードしたアセンブリが NETLOAD 出来ない - Autodesk Community の内容に沿ってブロック解除したアドイン アプリ アセンブリがロード出来ません。  なぜでしょうか?     Solution アセンブリ ファイルのブロックを解除しても改善が見られないようでしたら、SECURITYOPTIONS コマンドで [セキュリティ オプション] ダイアログの信頼できるパスにアセンブリ ファイルの配置パスをに追加してみてください。     セキュリティ オプションを変更したら、AutoCAD を再起動して、再度、NETLOAD してみてください。   ご参考: AutoCAD 2016 のセキュリティとアドインのデジタル署名 - Technology Perspective from Japan (typepad.com) アドイン ロード時の警告ダイアログ抑止 - Technology Perspective from Japan (typepad.com)
記事全体を表示
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 MSPACE[モデル空間] コマンドや PSPACE[ペーパー空間] コマンド のように、レイアウト上に配置したビューポートの編集モードを変更するメソッドはありますか?     Solution Editor.SwitchToModelSpace メソッドと Editor.SwitchToPaperSpace メソッドがそれぞれ該当します。   Editor.SwitchToModelSpace メソッドは、現在のビューポートをモデル空間編集モードに切り替えます。同様に、Editor.SwitchToPaperSpace メソッドは、現在のビューポートをペーパー空間編集モードに切り替えます。   AutoCAD のオンラインヘルプ「AutoCAD 2024 Developer and ObjectARX ヘルプ | 浮動ビューポート(.NET) | Autodesk」も参考にしてください。
記事全体を表示
Issue 寸法が参照する画層が、同寸法の削除後も削除出来ません。     ただし、一度、図面を保存して開き直すと削除出来ます。 図面を開き直さなくても、この画層を削除したいのですが、AutoCAD .NET API で可能でしょうか?   Solution AutoCAD .NET API では、Database.ReclaimMemoryFromErasedObjects メソッドでメモリ上の図面データベースからオブジェクトを削除する方法を利用することが出来ます。   このメソッドは、元々、32 ビット環境で大規模図面を操作する際の消費メモリ低減を狙ったものですが、図面を保存して開き直さなくても、同じセッションで図面データベース内の削除フラグが付いたオブジェクトをメモリから削除することが可能です。 下記コード例では、対象の寸法オブジェクトの削除後に ReclaimMemoryFromErasedObjects メソッドで同オブジェクトをメモリ上から削除、その後、参照画層と寸法を表現していた匿名ブロックを削除している点にご注意ください。 後半の処理(下部の Using スコープ)がないと、AUDIT コマンドで図面破損が報告されてしまうので注意が必要です。 少し趣旨が異なりますが、ちょうど、LAYDEL[画層削除] コマンドが処理する内容と似ています。   Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptEntityOptions peo1 = new PromptEntityOptions("\n削除する寸法を選択:"); PromptEntityResult pent = ed.GetEntity(peo1); if (pent.Status != PromptStatus.OK) { return; } ObjectIdCollection erased = new ObjectIdCollection(); ObjectId layId = ObjectId.Null; ObjectId blkId = ObjectId.Null; using (Transaction tr = db.TransactionManager.StartTransaction()) { Dimension dim = (Dimension)tr.GetObject(pent.ObjectId, OpenMode.ForWrite); erased.Add(pent.ObjectId); layId = dim.LayerId; blkId = dim.DimBlockId; dim.Erase(); tr.Commit(); } db.ReclaimMemoryFromErasedObjects(erased); using (Transaction tr = db.TransactionManager.StartTransaction()) { LayerTableRecord lay = (LayerTableRecord)tr.GetObject(layId, OpenMode.ForWrite); lay.Erase(); BlockTableRecord blk = (BlockTableRecord)tr.GetObject(blkId, OpenMode.ForWrite); blk.Erase(); tr.Commit(); }  
記事全体を表示
Issue Database.CurrentSpaceId プロパティでアクティブなレイアウトのレイアウト(ペーパー空間)の BlockTableRecord を取得して、対応する Layout を得ています。   [CommandMethod("GetLayoutId", CommandFlags.NoTileMode | CommandFlags.Modal)] public void GetLayoutId() { Database acCurDb = Application.DocumentManager.MdiActiveDocument.Database; Editor acDocEd = Application.DocumentManager.MdiActiveDocument.Editor; using (Transaction acTr = acCurDb.TransactionManager.StartTransaction()) { ObjectId objId = acCurDb.CurrentSpaceId; BlockTableRecord oRec = (BlockTableRecord)acTr.GetObject(objId, OpenMode.ForRead); if (oRec.IsLayout) { Layout oLay = (Layout)acTr.GetObject(oRec.LayoutId, OpenMode.ForRead); acDocEd.WriteMessage("\nCurrent LayoutId:{0}, Tab Name:{1}", oLay.ObjectId.ToString(), oLay.LayoutName); } acTr.Commit(); } }   ただ、レイアウト上のビューポートでモデル空間がアクティブになっていると、モデル空間を表す BlockTableRecord に対するレイアウト名(モデル空間のタブ名「モデル」は英語の「Model」)が表示されてしまいます。      ビューポートでモデル空間がアクティブな状態でも、アクティブなレイアウトに対応する Layout を得ることは出来るでしょうか?   Solution Database.CurrentSpaceId プロパティは、アクティブな空間の ID を返すプロパティです。 アクティブなレイアウトタブに対応する BlockTableRecord の ID を得るためには、システム変数 CTAB を利用することが出来ます。   [CommandMethod("GetLayoutId2", CommandFlags.NoTileMode | CommandFlags.Modal)] public void GetLayoutId2() { Database acCurDb = Application.DocumentManager.MdiActiveDocument.Database; Editor acDocEd = Application.DocumentManager.MdiActiveDocument.Editor; string strLay = (string)Application.GetSystemVariable("CTAB"); using (Transaction acTr = acCurDb.TransactionManager.StartTransaction()) { BlockTable oTbl = (BlockTable)acTr.GetObject(acCurDb.BlockTableId, OpenMode.ForRead); Layout oLay; BlockTableRecord oRec; foreach (ObjectId objId in oTbl) { oRec = (BlockTableRecord)acTr.GetObject(objId, OpenMode.ForRead); if (oRec.IsLayout) { oLay = (Layout)acTr.GetObject(oRec.LayoutId, OpenMode.ForRead); if (oLay.LayoutName == strLay) acDocEd.WriteMessage("\nCurrent LayoutId:{0}, Tab Name:{1}", oLay.ObjectId.ToString(), strLay); } } acTr.Commit(); } }  
記事全体を表示
Issue 特定の作図コマンドの実行を抑止する目的で、CommandWillStart イベント ハンドラ内で Document.SendStringToExecute メソッドを使って ESC コード(C#:"\x1B"、VB.NET:Chr$(27) )を送信してコマンドの実行をキャンセルしています。   Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; doc.SendStringToExecute("\x1B\x1B", false, true, false);   他にコマンドの実行を抑止する方法はないでしょうか?   Solution ドキュメント ウィンドウに表示されている図面に作図をする場合、AutoCAD は内部的にドキュメントをロックします。   ドキュメント ロックはアプリケーション実行コンテキストで定義したコマンドの実装時に必要になる知識と言えますが、この仕組みをイベント ハンドラで取得、利用することが出来ます。   この場合、DocumentLockModeChanged イベント ハンドラで DocumentLockModeChangedEventArgs.Veto メソッドを呼び出すことで、作図コマンドの実行時にドキュメント ロックを拒否してコマンドの実行そのものを抑止することが出来ます。    次の C# コードは、LINE コマンドの実行を抑止する例です。   ... [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; Application.DocumentManager.DocumentLockModeChanged += DocumentEvent_LockModeChanged_Handler; } private static void DocumentEvent_LockModeChanged_Handler(object sender, DocumentLockModeChangedEventArgs e) { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; if (e.GlobalCommandName == "LINE") { e.Veto(); ed.WriteMessage(string.Format("\n{0} command was vetoed\n", e.GlobalCommandName)); } } ...    
記事全体を表示
Issue 寸法を分解すると寸法値にあたる文字が MText オブジェクトとして分解されます。 この MText オブジェクトについて、MText.Contents プロパティから寸法値の文字を取得すると、寸法値にないコードが返される場合があります。   例:\A1;57,{\H0.7x;\S66^;}   このコードはどのようなものでしょうか?   Solution このコードは、マルチテキストの整形するために用意された「書式コード」と呼ばれるコードで、AutoCAD のオンラインヘルプ ページで内容を確認することが出来ます。 AutoCAD 2024 ヘルプ | 他のテキスト エディタの書式コード リファレンス | Autodesk AutoCAD .NET API で MText オブジェクトの文字列の内容を確認する場合には、Contents プロパティが書式コード付きの内容を、Text プロパティが書式コードを削除した内容を返すので、用途に応じてプロパティを使い分けることが出来ます。   Database db = HostApplicationServices.WorkingD、atabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nMText オブジェクトを選択:"); peo.SetRejectMessage("\nMText オブジェクトではありません."); peo.AddAllowedClass(typeof(MText), true); PromptEntityResult pent = ed.GetEntity(peo); if (pent.Status != PromptStatus.OK) { return; } using (Transaction tr = db.TransactionManager.StartTransaction()) { Entity ent = tr.GetObject(pent.ObjectId, OpenMode.ForRead) as Entity; ed.WriteMessage("\nObject Type : " + ent.GetType().ToString()); MText mtext = (MText)ent; ed.WriteMessage("\n\tMText Text : {0}", mtext.Text); ed.WriteMessage("\n\tMText Contents : {0}", mtext.Contents); tr.Commit(); }   寸法オブジェクトを分解せずに、AutoCAD .NET API :分解せずに寸法文字の情報を取得するには? (autodesk.co.jp) の方法も利用することが可能です。 
記事全体を表示
質問 AutoCAD Plant3D .net API でデータマネージャで表示されているガスケットのプロパティ情報を取得したい。 回答 ガスケット(≒ コネクタ)の場合、Connector.AllSubPartsからサブパーツ数を取得し、DataLinksManager.MakeAcPpObjectId()をsubIndexを指定してrowIdを取得後にDataLinksManager.GetAllProperties()を実行することでプロパティを取得することが可能となります。   以下は、選択したガスケットのプロパティ情報を取得するC#のサンプルコードとなります。 [CommandMethod("GetPipingProperties")] public void GetPipingProperties() { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityResult res = ed.GetEntity("Pick Object obtain properties : "); if (res.Status == PromptStatus.OK) { ObjectId objectId = res.ObjectId; PlantProject currentProj = PlantApplication.CurrentProject; PipingProject pipingProj = (PipingProject)currentProj.ProjectParts["Piping"]; DataLinksManager dlm = pipingProj.DataLinksManager; int rowId = dlm.FindAcPpRowId(res.ObjectId); List<KeyValuePair<string, string>> properties; properties = dlm.GetAllProperties(rowId, true); for (int i = 0; i < properties.Count; i++) ed.WriteMessage("\nProperty name:" + properties[i].Key + " = " + properties[i].Value); Database trDatabase = objectId.Database; using (Transaction tr = trDatabase.TransactionManager.StartTransaction()) { Connector connector = tr.GetObject(objectId, OpenMode.ForRead, false, true) as Connector; if (connector != null) { SubPartCollection subPartCollection = connector.AllSubParts; int index = 1; foreach (object connectorSubPart in subPartCollection) { int acPcRowId = dlm.FindAcPpRowId(dlm.MakeAcPpObjectId(objectId, index)); List<KeyValuePair<string, string>> subProps = dlm.GetAllProperties(acPcRowId, true); if (subProps != null) { foreach(var subProp in subProps) ed.WriteMessage("\nProperty name:" + subProp.Key + " = " + subProp.Value); } index++; } } } } }
記事全体を表示
質問 AutoCAD .net APIで寸法補助線の開始、終了点と寸法線と寸法補助線の交差点の座標を取得したいのですが、方法はありますか。 回答 AutoCADの.net APIには、直接的に寸法補助線の開始・終了点や寸法線と寸法補助線の交差点の座標を取得するメソッドやプロパティはありません。このため、対象の寸法線の幾何情報から算出して取得する必要があります。 最も簡便な方法としては、対象の寸法線をExplodeにより分解し、分解して取得したオブジェクトの内容から計算をして取得する形となります。   以下は、平行寸法線に対して、寸法補助線の開始・終了点や寸法線と寸法補助線の交差点に点オブジェクトを作成するC#のサンプルコードです。  private static void makePoint(Point2d point, Transaction tx, BlockTableRecord acBlkTblRec) { DBPoint acPoint = new DBPoint(new Point3d(point.X, point.Y, 0)); acPoint.SetDatabaseDefaults(); acBlkTblRec.AppendEntity(acPoint); tx.AddNewlyCreatedDBObject(acPoint, true); } [CommandMethod("GetPointsOnAlignedDimension")] public static void GetPointsOnAlignedDimension() { Document dc = Application.DocumentManager.MdiActiveDocument; Database db = dc.Database; Editor ed = dc.Editor; PromptSelectionOptions pso = new PromptSelectionOptions(); pso.MessageForAdding = "\nSelect an Aligned Dimension:"; pso.SingleOnly = true; pso.SinglePickInSpace = true; PromptSelectionResult psr = ed.GetSelection(pso); if (psr.Status != PromptStatus.OK) return; SelectionSet ss = psr.Value; SelectedObject so = ss[0]; if (!so.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(AlignedDimension)))) { ed.WriteMessage("\nSelected entity is not Aligned Dimension..."); return; } ObjectId id = so.ObjectId; using (Transaction tx = db.TransactionManager.StartTransaction()) { try { // Open the Block table for read BlockTable acBlkTbl = tx.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; // Open the Block table record Model space for write BlockTableRecord acBlkTblRec = tx.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord; AlignedDimension dim = tx.GetObject(id, OpenMode.ForRead) as AlignedDimension; DBObjectCollection col = new DBObjectCollection(); dim.Explode(col); Point3d dimLoc = dim.DimLinePoint; Point3d xPt1 = dim.XLine1Point; Point3d xPt2 = dim.XLine2Point; Line2d entityLine = new Line2d(new Point2d(xPt1.X, xPt1.Y), new Point2d(xPt2.X, xPt2.Y)); Line2d dimensionLine = new Line2d(new Point2d(dimLoc.X, dimLoc.Y), entityLine.Direction); Line2d lineStargingFromPt1 = entityLine.GetPerpendicularLine(new Point2d(xPt1.X, xPt1.Y)); Line2d lineStargingFromPt2 = entityLine.GetPerpendicularLine(new Point2d(xPt2.X, xPt2.Y)); Point2d interSection1 = lineStargingFromPt1.IntersectWith(dimensionLine).First(); Point2d interSection2 = lineStargingFromPt2.IntersectWith(dimensionLine).First(); makePoint(interSection1, tx, acBlkTblRec); makePoint(interSection2, tx, acBlkTblRec); foreach(DBObject dbObj in col) { Line line = dbObj as Line; if (line == null) { continue; } Point2d startPt = new Point2d(line.StartPoint.X, line.StartPoint.Y); Point2d endPt = new Point2d(line.EndPoint.X, line.EndPoint.Y); if (lineStargingFromPt1.IsOn(startPt) && lineStargingFromPt1.IsOn(endPt)) { makePoint(startPt, tx, acBlkTblRec); makePoint(endPt, tx, acBlkTblRec); } else if (lineStargingFromPt2.IsOn(startPt) && lineStargingFromPt2.IsOn(endPt)) { makePoint(startPt, tx, acBlkTblRec); makePoint(endPt, tx, acBlkTblRec); } } db.Pdmode = 34; db.Pdsize = 1; tx.Commit(); } catch (System.Exception e) { tx.Abort(); ed.WriteMessage(e.Message); } } }   平行寸法線以外の場合にも、Explodeしたオブジェクトから各寸法線の特徴に合わせて幾何計算を行うことで取得が可能です。
記事全体を表示
質問 InventorのAPIを使って、Inventorのコマンドを実行する方法はありますか。   回答 Inventorの各コマンド(カスタムコマンドを含む)はCommandManagerオブジェクトからControlDefinition オブジェクトとして取得することが出来ます。 取得したControlDefinition オブジェクトのExecuteメソッドを実行することで、コマンドを実行することが可能です。   以下は"Vaultステータスを更新"コマンドを実行するサンプルコードとなります。 ' Get the CommandManager object. Dim oCommandMgr As CommandManager = ThisApplication.CommandManager ' Get control definition. Dim oControlDef As ControlDefinition = oCommandMgr.ControlDefinitions.Item("VaultRefresh") ' Execute the command. Call oControlDef.Execute   ControlDefinitions.Itemメソッドに指定する引数は、取得するコマンドの名称となります。   コマンドの名称の取得方法としては、以下の2つの方法があります。   1.以下のサンプルコード(VBA)を実行し、出力されるファイル内から取得する Sub PrintCommandNames() ' Get the CommandManager object. Dim oCommandMgr As CommandManager Set oCommandMgr = ThisApplication.CommandManager ' Get the collection of control definitions. Dim oControlDefs As ControlDefinitions Set oControlDefs = oCommandMgr.ControlDefinitions ' Open the file and print out a header line. Dim oControlDef As ControlDefinition Open "C:\temp\CommandNames.txt" For Output As #1 Print #1, Tab(10); "Command Name"; Tab(75); _ "Description"; vbNewLine ' Iterate through the controls and write out the name. For Each oControlDef In oControlDefs Print #1, oControlDef.InternalName; Tab(55); _ oControlDef.DescriptionText Next ' Close the file. Close #1 End Sub   2.Inventor SDKに付属のEventWatcherを使用し、Inventorでコマンドを実行してコマンド名を取得する   EventWatcherは、Inventorに付属のInventor SDKをインストールすると以下のフォルダにあります。 C:\Program Files\Autodesk\<Inventor Version>\SDK\DeveloperTools\Tools\EventWatcher\bin\Release   EventoWatcherを起動し、左側のリストから「UserInputEvents.OnActivateCommand」をチェックされた状態で、InventorでAPIから実行したいコマンドを実行すると、実行されたコマンド名がウィンドウに表示されます。 取得したコマンド名をControlDefinitions.Itemメソッドの引数に指定することで、対象のコマンドを取得することが出来ます。     なお、コマンド実行時にダイアログが表示されるタイプのコマンド(例:押し出し コマンド)の場合、ダイアログ内で指定するパラメータ(押し出しコマンドの場合、押し出し方向や距離 等)の指定についてはコマンドの機能となり、コマンドを実行するAPIから制御(指定)することが出来ません。   このようなタイプのコマンドの場合、APIからユーザの入力なしに実行したい場合は、InventorのAPIを用いて処理を作成する必要があります(もちろん処理には、希望の処理に対応するInventorのAPIが公開されている必要があります)。  
記事全体を表示