Autodesk Community Tips- ADNオープン
Autodesk Community Tipsではちょっとしたコツ、やり方、ショートカット、アドバイスやヒントを共有しています。
ソート順:
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(); }  
記事全体を表示
質問 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(); } }
記事全体を表示
Question InventorAPIでDocuments オブジェクト のCountプロパティの値が2022以降とそれより前のバージョンで異なりますが、なぜでしょうか。 Answer この動作は、Invewntor 2022以降で追加されたモデル状態機能に対応する形でのAPIの動作の変更となります。   モデル状態が存在する場合、2つのドキュメントがDocumentsプロパティから取得されます。 2つのドキュメントの相違点は、片方がファクトリドキュメントもう片方がメンバドキュメントとなり、APIでは以下のプロパティにて区別が可能です。 ・ファクトリドキュメント:ComponentDefinition.IsModelStateFactory プロパティがTrue ・メンバドキュメント:ComponentDefinition.IsModelStateMemberプロパティがTrue  
記事全体を表示
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 自身も拡張エンティティデータ利用していますので、既に付加されている拡張エンティティデータに影響を与えずに独自データを付加、削除するようご留意ください。
記事全体を表示
質問 Inventor APIでiPropertyの質量を取得すると値がグラムで取得されます。 Inventor APIで取得する値の単位は何でしょうか。 回答 Inventorでは各ドキュメントの表示単位を設定可能ですが、内部データべースの単位は、常に同じ単位を利用しております。 InventorのAPIはこのデータベース単位を利用いたしますので(表示単位の設定にかかわらず)、データベース単位での値が取得されます。   Inventorの表示単位や内部データベースの単位の詳細については、APIリファレンスの「Inventor APIのユーザマニュアル」-「一般的なコンセプト」-「計測単位」にまとめられています。 以下は、APIリファレンスに記載のデータベース単位の表となります。   ただし、以下のコードでiPropertyの質量を取得すると、値がデータベース単位のキログラムではなく、グラムで取得されるため注意が必要です。 ThisApplication.ActiveDocument.PropertySets.Item("Design Tracking Properties").Item("Mass").Value   質量をデータベース単位のキログラムで取得する場合は、以下のようにMassPropertesのmassプロパティから取得が可能です。 ThisApplication.ActiveDocument.ComponentDefinition.MassProperties.mass  
記事全体を表示
Issue AutoCAD .NET API でアプリケーションのフォーカス イベントを処理することは出来ますか?   Solution AutoCAD の Application ウィンドウ レベルでは、COM API の Application.AppActivate イベントと Application.AppDeactivate イベントを COM Interop でお使いいただくことが出来ます。 ご参考:COM ベースのイベントを登録する(.NET)   Autodesk.AutoCAD.Interop.AcadApplication? acAppCom = null; [CommandMethod("AddCOMEvent")] public void AddCOMEvent() { acAppCom = (Autodesk.AutoCAD.Interop.AcadApplication)Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication; acAppCom.AppActivate += new _DAcadApplicationEvents_AppActivateEventHandler(appComAppActivate); acAppCom.AppDeactivate += new _DAcadApplicationEvents_AppDeactivateEventHandler(appComAppDeactivate); } [CommandMethod("RemoveCOMEvent")] public void RemoveCOMEvent() { if (acAppCom != null) { acAppCom.AppActivate -= new _DAcadApplicationEvents_AppActivateEventHandler(appComAppActivate); acAppCom.AppDeactivate -= new _DAcadApplicationEvents_AppDeactivateEventHandler(appComAppDeactivate); acAppCom = null; } } public void appComAppActivate() { Autodesk.AutoCAD.ApplicationServices.Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; ed.WriteMessage("\n*** AppActivate ***\n"); } public void appComAppDeactivate() { Autodesk.AutoCAD.ApplicationServices.Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; ed.WriteMessage("\n*** AppDeactivate ***\n"); }  
記事全体を表示
質問 Vaultのカスタムプログラムの開発のために、Vault Exploror(Vaultクライアント)のコマンドが利用しているVault APIを知りたい。 回答 Vaultのカスタムプログラムを開発する際に、Vault Exploror(Vaultクライアント)のコマンド(またはその一部)と同様の処理を実現したい場合に、どのようなAPIを利用すればよいかを知りたい場合が多くあります。   Vault Exploror(Vaultクライアント)はコマンドの実行時に、Vault サーバのWebサービスAPIを実行してその機能を実現しているため、その通信内容をパケットキャプチャツール等で確認することで、どのWebサービスAPIが実行されているかを確認することが出来ます。   ここでは、パケットキャプチャツールのFiddler ClassicとVaultの通信内容をFiddler Classicで見やすくするエクステンションツールのvapiTraceを利用した方法を紹介します。   なお、以下手順の環境としてはVaultサーバとVaultクライアントが同一のマシン上にインストールされているテスト環境を前提としています。原理的には、別端末にインストールされている場合でも、Vaultクライアントがインストールされている環境で実行することで通信内容を確認できるはずですが、追加のFiddlerの設定が必要となる可能性があります。   手順   1.以下URLからFiddler Classicをダウンロードしてインストールします。 https://www.telerik.com/fiddler/fiddler-classic   2.以下GitHubリポジトリのリリースから、vapiTraceFiddlerExtension.zipをダウンロードし、zpiファイル解凍して、C:\Users\<ログインユーザ名>\AppData\Local\Programs\Fiddler\Inspectors 配下に配置します。 https://github.com/coolOrangeLabs/vapiTrace   3.Fiddlerを起動し[Tool]-[Option]メニューからCapture HTTPS Connections設定を有効にする。    4.Fiddlerを再起動して、Vaultクライアントを起動します。  Fiddlerの画面の左側には、キャプチャされた通信内容が時系列にリストで表示されます。URLが/AutodeskDMで始まる通信がVaultサーバとの通信となります。   リストからアイテムを選択し、右側の上下のペインでvapiTraceタブを選択すると、以下のスクリーンショットのように、上側のペインに呼び出したVault API(とその引数)、下側のペインにはAPIのレスポンスが表示され、実行されたAPIを確認することが出来ます。     リストの内容は、リストアイテムを選択して、右クリックメニュー[Remove]-[All Sessions]からクリアできるので、調査したいVaultエクスプローラのコマンドを実行前にリストをクリアし、Vaultのコマンドを実行後に[File]-[Capture Traffic]のチェックを外してキャプチャを停止することで、コマンドが実行しているAPIを効率的に調査することが出来るかと思います。   また、Vaultクライアントはコマンドの実行後にGUIを最新の情報に更新するために、情報を取得するAPIの呼び出しを行っています。カスタムプログラムの開発時には、要件に合わせてどのAPIが必要なのかの判断が必要となりますので、各APIの詳細をVault SDKのAPIリファレンスを参照して確認ください。   なお、Vaultクライアントからサーバにログインする際にVaultサーバにlocalhostを指定するとFiddlerで通信をキャプチャすることが出来ません。Vaultサーバにはマシン名を指定してください。
記事全体を表示
質問 APIでInventorを起動する際にバージョン指定する方法はありますか。 回答 AutoCAD等でGetTypeFromProgID()の引数に、"AutoCAD.Application.xx” (xxはバーンジョンを表す数値)等を渡すことでバージョンを指定して起動することが出来るため、Inventorも同様の方法で起動する方法を探している状況かと思います。   残念ながら、InventorではAutoCADとはCOMのレジストリ登録の仕組みが異なっており、CreateInstance()でバージョンを指定して起動することが出来ません。   プログラムから指定のバージョンのInventorを起動する場合、以下の2通り方法があります。 1.カスタムプログラムからexeを起動する 2.カスタムプログラムから、CreateInstance()関数の実行時に、CreateInstance()関数が参照するInventorのExeのパスが記述されている、レジストリ情報を対象バージョンのInventor.exeのパスで上書きしたのちに、GetTypeFromProgID()⇒CreateInstance()を行う。 ただし、2の方法はCLASSES_ROOT配下のレジストリ情報の書き換えを行うため、adminまたはCLASSES_ROOTの書き換えに必要なユーザ権限が必要となりるため、通常は1の方法をとることになるかと思いますので、ここでは1の方法を記載します。   以下は、1の方法でInventorを起動するヘルパークラスです。 class AdnInventorLoader { public enum Version { Inventor_2020, Inventor_2021, Inventor_2022, Inventor_2023, }; public static Inventor.Application CreateInstanceFromProcess(Version version) { try { string exePath = GetExePath(version); if (exePath != string.Empty) { CleanUpRegistry(); System.Diagnostics.Process process = System.Diagnostics.Process.Start(exePath); if (process != null) { //Wait for 5 Mins if (process.WaitForInputIdle(300000)) { while (true) { try { Inventor.Application app = Marshal.GetActiveObject("Inventor.Application") as Inventor.Application; return app; } catch (Exception ex) { if (!ex.Message.Contains("MK_E_UNAVAILABLE")) break; System.Threading.Thread.Sleep(1000); } } } } } return null; } catch { return null; } } // Clean up registry to prevent // "Re-registration" dialog // http://tinyurl.com/dx4tsnu private static bool CleanUpRegistry() { try { using (RegistryKey inventorKey =Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Autodesk").OpenSubKey("Inventor").OpenSubKey("Current Version",true)) { if (inventorKey == null) return false; inventorKey.DeleteValue("Executable"); inventorKey.DeleteValue("LastVersionRun"); inventorKey.DeleteValue("Registered"); inventorKey.DeleteValue("RegistryVersion"); inventorKey.DeleteValue("SilentMode"); inventorKey.DeleteValue("UBI"); inventorKey.Close(); return true; } } catch { return false; } } // Retrieve Inventor.exe fullpath based on version private static string GetExePath(Version version) { try { string key = string.Empty; switch (version) { case Version.Inventor_2020: key = "RegistryVersion24.0"; break; case Version.Inventor_2021: key = "RegistryVersion25.0"; break; case Version.Inventor_2022: key = "RegistryVersion26.0"; break; case Version.Inventor_2023: key = "RegistryVersion27.0"; break; default: return string.Empty; } using (RegistryKey inventorKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64). OpenSubKey("SOFTWARE"). OpenSubKey("Autodesk"). OpenSubKey("Inventor"). OpenSubKey(key)) { if (inventorKey == null) return string.Empty; string path = inventorKey.GetValue("InventorLocation") as string; inventorKey.Close(); path += "Inventor.exe"; return (System.IO.File.Exists(path) ?path : string.Empty); } } catch { return string.Empty; } } } }    利用側からは以下のように、起動するInventorのバージョンを指定する列挙値を指定して起動します。 Inventor.Application app = AdnInventorLoader.CreateInstanceFromProcess(AdnInventorLoader.Version.Inventor_2023); if (app != null) app.Visible = true;   ※この記事はブログ記事「Running programmatically a specific version of Inventor」を元に、必要な部分を抽出し、加筆修正と日本語化を行ったものとなります。
記事全体を表示
Question InventorのAPIで2D図面上の任意の2点の座標を指定して寸法を追加する方法はありますか。 Answer 入力となる座標に2D図面上で図形が存在しない場合、Inventorの図面寸法を作成することができません。   このため、任意の2点の座標から長さ寸法を挿入したい場合、スケッチ上に入力座標でポイントを作成し、ポイント間の拘束寸法を作成、作成した寸法を図面に取り込むことで寸法を発生させる必要があります。   なお、この方法で作成した寸法はスケッチでの入力点に拘束されているため、図面上の図形や、ビューの元データのモデルの更新に追随して更新されません。   また、拘束寸法をシートに取り込んだ場合、寸法値はドキュメントの規格設定によりinchまたはmmとなります。寸法値をcm等の別の単位で表示したい場合は、シートに取得したスケッチの拘束寸法に対して値の上書きを行う必要があります。なお、寸法値の上書きを行っている場合スケッチ上で拘束寸法の変更を行った場合においても、値の更新が自動で行われない(上書き値が表示される)点に注意が必要です。   以下は2点の座標を元にスケッチに点を追加、拘束寸法を作成後にシートに取り込みを行うVBAのサンプルコードです。 Dim oDoc As DrawingDocument Set oDoc = ThisApplication.ActiveDocument Dim oSheet As sheet Set oSheet = oDoc.ActiveSheet Dim oSketch As sketch Dim oDimensionConstraint As DimensionConstraint Set oDimensionConstraint = addDimensionBySketchPoint(oSheet, "スケッチ1", 10, 10, 12, 10) Dim oConsraintDimensionCollection As ObjectCollection Set oConsraintDimensionCollection = ThisApplication.TransientObjects.CreateObjectCollection oConsraintDimensionCollection.Add oDimensionConstraint 'retrieve model dimension Call oSheet.DrawingDimensions.GeneralDimensions.Retrieve(oDimensionConstraint.Parent, oConsraintDimensionCollection) End Sub Public Function addDimensionBySketchPoint(oSheet As sheet, sketchName As String, x1 As Double, y1 As Double, x2 As Double, y2 As Double) As DimensionConstraint Dim oTg As TransientGeometry Set oTg = ThisApplication.TransientGeometry Dim oSketch As DrawingSketch On Error Resume Next Set oSketch = oSheet.Sketches(sketchName) On Error GoTo 0 If oSketch Is Nothing Then Set oSketch = oSheet.Sketches.Add() End If oSketch.Edit Dim p1 As Point2d Set p1 = oTg.CreatePoint2d(x1, y1) Dim p2 As Point2d Set p2 = oTg.CreatePoint2d(x2, y2) Dim skP1 As SketchPoint Set skP1 = oSketch.SketchPoints.Add(p1, False) Dim skP2 As SketchPoint Set skP2 = oSketch.SketchPoints.Add(p2, False) Dim tp As Point2d Set tp = oTg.CreatePoint2d((x2 + x1) / 2, (y2 + y1) / 2) Dim oTwoPointDistanceDimConstraint As TwoPointDistanceDimConstraint Set oTwoPointDistanceDimConstraint = oSketch.DimensionConstraints.AddTwoPointDistance(skP1, skP2, kHorizontalDim, tp) Set addDimensionBySketchPoint = oTwoPointDistanceDimConstraint oSketch.ExitEdit  
記事全体を表示
Question Vault APIで等価性エラーが発生しているファイルを取得する方法はありますか。 Answer 等価性エラーが発生している場合、プロパティコンプライアンス プロパティの値が2となっている状況です。   このため、以下のようにプロパティコンプライアンスプロパティの値が"2"(等価性が準拠していない)状態にあるFileを検索条件に指定して取得することが可能です。 SrchCond[] cond = new SrchCond[] { new SrchCond( ){ PropDefId = 39, //プロパティコンプライアンスのプロパティID SrchOper = 3, //Is exactly (or equals) SrchTxt = "2", //等価性が準拠していない PropTyp = PropertySearchType.SingleProperty, SrchRule = SearchRuleType.Must } }; string bookmark = null; SrchStatus status; ACW.File[] files = serviceManager.DocumentService.FindFilesBySearchConditions(cond, null, null, true, true, ref bookmark, out status);    また、すでに対象のFileの配列を取得しており、その中から等価性エラーが発生しているFileを抽出する場合は、以下のようにGetPropertiesを利用して、プロパティを取得して確認する形となります。 IEnumerable<long> ids = files.Select(file => file.Id); PropInst[] properties = serviceManager.PropertyService.GetProperties( "FILE", ids.ToArray(), new long[] { 39 /*プロパティコンプライアンスのプロパティID*/} ); IEnumerable<PropInst> PropInstSelection = from propInst in properties where propInst.PropDefId == 39 && propInst.Val.ToString() == "2" /*プロパティコンプライアンスのプロパティIDで等価性が準拠していない*/ select propInst;   なお、プロパティコンプライアンスプロパティのId(=39)値は、以下のサンプルのように”FILE”エンティティのプロパティを取得してループで内容を見ることで確認が可能です。 PropDef[] fileProps = serviceManager.PropertyService.GetPropertyDefinitionsByEntityClassId("FILE");  
記事全体を表示
Question AutoCAD のActiveX API SetWindowToPlot()で指定した印刷範囲が特定の図面でずれる場合がある。 指定した範囲で正しく印刷する方法はありますか。 Answer 印刷範囲がずれる図面では、TARGETシステム変数の値に0ではない値が設定されている可能性があります。 ※TARGETシステム変数変数については、以下のリファレンスを参照 https://help.autodesk.com/view/ACD/2022/JPN/?guid=GUID-0649E4B8-B11A-411E-96CE-125BEBEB5B42   この場合、SetWindowToPlotで指定した座標がオフセットされてるため、指定した印刷範囲で印刷されません。 以下サンプルコードの様にSetWindowToPlot()に指定する点の座標を、ActiveViewport.Targetの値で減算することで、指定範囲で印刷されるようになります。   Sub Example_SetWindowToPlot() Dim point1 As Variant, point2 As Variant point1 = ThisDrawing.Utility.GetPoint(, "Click the lower-left of the window to plot.") ReDim Preserve point1(0 To 1) ' Change this to a 2D array by removing the Z position point2 = ThisDrawing.Utility.GetPoint(, "Click the upper-right of the window to plot.") ReDim Preserve point2(0 To 1) ' Change this to a 2D array by removing the Z position Dim currTarget As Variant currTarget = ThisDrawing.ActiveViewport.Target point1(0) = point1(0) - currTarget(0) point1(1) = point1(1) - currTarget(1) point2(0) = point2(0) - currTarget(0) point2(1) = point2(1) - currTarget(1) ThisDrawing.ActiveLayout.SetWindowToPlot point1, point2 ThisDrawing.ActiveLayout.PlotType = acWindow ThisDrawing.ActiveLayout.ConfigName = "DWG to PDF.pc3" ThisDrawing.Plot.DisplayPlotPreview acFullPreview End Sub  
記事全体を表示
質問 AutoCADのVBAで、以下のサンプルコードの様にコレクションの要素を取得し存在しない場合は要素を追加する処理がありますが、同様の処理をAutoLispで行う場合はどのように記述したらよいでしょうか。 Dim sset As AcadSelectionSet On Error Resume Next Set sset = ThisDrawing.SelectionSets.Item("Test") On Error GoTo 0 If sset Is Nothing Then Set sset = ThisDrawing.SelectionSets.Add("Test") End If 回答 AutoLispのvl-catch-all-applyを使用することで、コレクションに存在しないアイテムを取得する際に発生するエラーをハンドルすることが可能です。 vl-catch-all-applyには引数のリストを指定された関数に渡し、すべての例外をトラップします。   上述のVBAと同様の処理を実現する場合は以下のサンプルコードのようにlambda式を作成して処理を実行、結果の値を確認する形となります。 (setq acadObject (vlax-get-acad-object)) (setq activeDocument (vla-get-activedocument acadObject)) (setq selectionSets (vla-get-selectionsets activeDocument)) (vl-catch-all-apply '(lambda() (setq sset (vla-Item selectionSets "test")) ) ) (if (= nil sset) (progn (setq sset (vla-add selectionSets "test")) ) )    
記事全体を表示
Question AutoCADのObjectARXでハードウェアアクセラレーションをオン/オフ状態を取得する方法はありますか? Answer AutoCAD ObjectARXのAcGsManagerクラスからAcGsGraphicsKernelを取得、AcGsGraphicsKernelからAcGsConfigを取得します。 AcGsConfigのisHardwareAccelerationEnabled()メソッドにより現在のHWアクセラレーションの設定が確認できます。   なお、ビルドに当たりAcDrawBridge.libをリンクファイルに追加となります。  AcGsKernelDescriptor descriptor; descriptor.addRequirement(AcGsKernelDescriptor::k3DDrawing); AcGsGraphicsKernel* pGraphicsKernel = AcGsManager::acquireGraphicsKernel(descriptor); AcGsConfig* gsConf = pGraphicsKernel->getConfig(); if (gsConf->isHardwareAccelerationEnabled()) { acutPrintf(ACRX_T("\nHardwareAcceleration Enabled.")); } else { acutPrintf(ACRX_T("\nHardwareAcceleration Disabled.")); }
記事全体を表示
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"  
記事全体を表示
質問 AutoCADの.net APIで雲マーク(REVCLOUD)を取得する方法はありますか。   回答 AutoCADの雲マーク(RevCloudコマンドで作成される図形)は、拡張データ領域にアプリケーション名”RevcloudProps”のデータを持つLWPolylineとなっております。   このため、net APIで図形を選択する際のフィルタ条件に、図形がLWPolylineでかつアプリケーション名が”RevcloudProps”の拡張データを持つ図形指定することで雲マーク図形を取得することが可能です。   Dim dc As Document = Application.DocumentManager.MdiActiveDocument Dim db As Database = dc.Database Dim ed As Editor = dc.Editor Dim tvs(1) As TypedValue tvs.SetValue(New TypedValue(DxfCode.Start, "LWPOLYLINE"), 0) tvs.SetValue(New TypedValue(DxfCode.ExtendedDataRegAppName, "RevcloudProps"), 1) Dim sf As SelectionFilter = New SelectionFilter(tvs) Dim psr As PromptSelectionResult psr = ed.SelectAll(sf) If psr.Status<> PromptStatus.OK Then Exit Sub End If Using tx As Transaction = db.TransactionManager.StartTransaction() Try For Each id As ObjectId In psr.Value.GetObjectIds() Dim lwp As Polyline = tx.GetObject(id, OpenMode.ForWrite) Next tx.Commit() Catch e As System.Exception tx.Abort() ed.WriteMessage(e.Message) End Try End Using    
記事全体を表示
Issue AutoCAD .NET API でフォルダ内の DWG ファイルを順に開いて処理していますが、サイズの大きい図面があると相対的に処理時間が長くなってしまいます。高速化するアイデアはありますか?   Solution   AutoCAD 上に図面を開いて表示する際、描画に多く時間がかかってしまいます。 もし、ユーザインターフェース上に図面を表示する必要がないのであれば、Database.ReadDwgFile メソッドを使って、メモリ上に図面を展開する方法を採用することで、描画にかかかる時間を省いて処理全体を高速化させることが出来ます。   次のコードは、フォルダを指定後にフォルダ内の .dwg ファイルを順に Database.ReadDwgFile メソッドでメモリ展開し、モデル空間のオブジェクト タイプを表示するものです。 [CommandMethod("MyCommand", CommandFlags.Modal)] public void MyCommand() { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; using (FolderBrowserDialog fd = new FolderBrowserDialog()) { if (fd.ShowDialog() == DialogResult.OK) { string folder = fd.SelectedPath; System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(folder); IEnumerable<System.IO.FileInfo> files = di.EnumerateFiles("*.dwg", System.IO.SearchOption.AllDirectories); if (files == null) return; ed.WriteMessage("\n\t{0}", folder); foreach (System.IO.FileInfo f in files) { string file = f.FullName; ed.WriteMessage("\n - {0}", file); try { using (Database db = new Database(false, true)) { db.ReadDwgFile(file, FileOpenMode.OpenForReadAndAllShare, false, null); using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTableRecord btr = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead); foreach (ObjectId id in btr) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead); ed.WriteMessage("\n - {0}", ent.GetType().ToString()); } tr.Commit(); } } } catch (System.Exception ex) { ed.WriteMessage(ex.ToString()); } } } } }   なお、Database.ReadDwgFile メソッドの使用時には、次の点に注意が必要です。   Database.ReadDwgFile メソッドで読み込む Database インスタンスを new ステートメントで用意する必要があります。この際、最低限必要なシンボルテーブルとオーナーシップを持つ Database 構造は、読み込む DWG ファイルに定義されているため、コンストラクタには Database.Database([MarshalAs(UnmanagedType.U1)] bool, [MarshalAs(UnmanagedType.U1)] bool)  オーバーロードを使用して、第1パラメーターの値を false にして、読み込む DWG ファイルの Database 構造との競合を抑止する必要があります。 AutoCAD のユーザインターフェースに表示された Database インスタンスは、同図面を表示している MDI 子ウィンドウを閉じると、AutoCAD が Database 領域をメモリから削除します。ただし、Database.ReadDwgFile メソッドでメモリ上に展開した Database インスタンスの領域は、展開したアドイン アプリがメモリーから削除しなければなりません。削除には上、記コードのように using ステートメントを利用してスコープ内の処理後に削除させるか、using ステートメントでスコープ指定せずに Dispose メソッドを明示的に呼び出すことも出来ます。 Database.ReadDwgFile メソッドで読み込んだ Database インスタンス内の DBText オブジェクトや AttributeReference オブジェクトの位置合わせを変更する場合、Database インスタンスを HostApplicationServices.WorkingDatabase プロパティで設定していないと予期しないズレが発生する場合があります。これは、DBText クラス実装が、位置合わせ時に現在の図面データベース(Database)を参照している関係で発生してしまう現象です。Database インスタンスを HostApplicationServices.WorkingDatabase プロパティで設定して処理した場合、処理後にオリジナル(ユーザーインターフェースに開いている図面の Database インスタンスを HostApplicationServices.WorkingDatabase プロパティで再設定する必要があります。
記事全体を表示
Issue グループやブロック化していない状態の特定オブジェクトを移動や回転する際に、 イベント処理を使用せずに、アプリ内で関係のあるオブジェクトを同じように移動や回転する方法はありますか?   Solution 特定のオブジェクト タイプ(クラス)の移動や回転、縮尺変更など編集は、TransformOverrule オーバールール(Overrule)プロトコルを使用して、既定の振る舞いを変更することが可能です。ただし、イベント ハンドラーでのオブジェクト編集で同一イベントが発生してしまい、無限ループに陥らないような配慮が必要です。   次の C# コードは、MOVE コマンドや ROTATE コマンド、SCALE コマンドで円弧オブジェクト(Arc)を選択すると、青色(インデックスカラー色:5)の線分オブジェクト(Line)に同じマトリックス変換を実施するものです。   public class TransformByOverrule : TransformOverrule { public override void TransformBy(Entity ent, Matrix3d mat) { Database db = HostApplicationServices.WorkingDatabase; Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; ed.WriteMessage("\nTransformBy.TransformBy Overrule - matrix {0}", mat.ToString()); base.TransformBy(ent, mat); TypedValue[] typeval = new TypedValue[2]; typeval.SetValue(new TypedValue(62, 5), 0); typeval.SetValue(new TypedValue(0, "LINE"), 1); SelectionFilter filter = new SelectionFilter(typeval); PromptSelectionResult psr = ed.SelectAll(filter); ed.WriteMessage("\nGetSelection = {0}", psr.Status.ToString()); if (psr.Status == PromptStatus.OK) { using (Transaction tr = db.TransactionManager.StartTransaction()) { SelectionSet sset = psr.Value; foreach (ObjectId objId in sset.GetObjectIds()) { ed.WriteMessage("\nObjectTd:" + objId.ToString()); Entity slave = (Entity)tr.GetObject(objId, OpenMode.ForWrite); slave.TransformBy(mat); } tr.Commit(); } } } } static TransformByOverrule _toverrule = null; [CommandMethod("MyCommand")] static public void MyCommand() { Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; if (_toverrule == null) { _toverrule = new TransformByOverrule(); ObjectOverrule.AddOverrule(RXObject.GetClass(typeof(Arc)), _toverrule, true); ObjectOverrule.Overruling = true; ed.WriteMessage("\nBegin modifying ARC overrule"); } else { ObjectOverrule.RemoveOverrule(RXObject.GetClass(typeof(Arc)), _toverrule); _toverrule.Dispose(); _toverrule = null; ed.WriteMessage("\nEnd modifying ARC overrule"); } }        
記事全体を表示
現象 Inventor 2025以前のバージョンでは、Inventor 起動時に対応するバージョンのInventor Apprentice Serverのレジストリ登録が行われていました。 一方で、Inventor 2026起動時には、Inventor Apprentice Server 2026のレジストリ登録が行われない。 このため、異なるバージョンのInventorがインストールされている混在環境においては、以下の様な状態となります。   手順 ・Inventor 2025をインストール ・Inventor 2026およびInventor Apprentice Server 2026をインストール ・Inventor 2025を起動。⇒同時に Apprentice Server 2025のレジストリ登録が行われる。 ・Inventor 2025を終了 ・Inventor 2026を起動。 ⇒ Apprentice Server 2026のレジストリ登録は行われないため、レジストリ登録はApprentice Server 2025のままとなる。   診断 Inventor 2025 以前ではInventor Pro のインストーラに Apprentice Server のコピーが含まれており、Inventor Pro のインストール時に併せてインストールがされおり、Inventor起動時に同梱されてるApprentice Serverの情報でレジストリ登録を更新しておりました。   一方、Inventor 2026 以降ではInventor Pro のインストール時に Apprentice Server がインストールされなくなりました(より正確には、Regfee版のApprentice Server がインストールされますが、このRegfree版のApperentice ServerはInventor以外のアプリケーションからは利用できません)。また、Inventor起動時に同時に行っていた、同梱されているApprentice Serverでレジストリ登録情報の更新を行う処理も行われなくなりました。   このため以前のリリースから Inventor 2026 に切り替えてもApprentice Serverのレジストリ登録は更新されません。 解決策 Inventor 2026以降では、スタンドアロン版のApprentice Serverをインストールして、利用するようにしてください。 Inventor 2026以降で以前バージョンのApprentice Server から切り替えるには、スタンドアロン版のApprentice Serverインストールディレクトリ配下で以下のコマンドラインを実行してください。   ApprenticeRegSvr.exe /install  
記事全体を表示
Issue 選択したオブジェクトが自動調整配列複写の要素かどうか判定して、自動調整配列複写であった場合に分解する実装するには、どのようなコードを記述すればいいでしょうか?       Solution 自動調整配列複写の対象となっているオブジェクト一式は、匿名ブロック(Anonymous Block)として自動調整フレームワークで管理、維持されています。   自動調整配列複写の判定には、AcDbAssocArrayActionBody::isAssociativeArray() メンバー関数を利用することが出来ます。同様に、分解には AcDbAssocArrayActionBody::explode() メンバー関数 を利用することが出来ます。   次のコードは、選択したオブジェクトが自動調整配列複写の構成要素だった場合に、トップレベルの調整配列複写を分解する例です。   ads_name ename; ads_point pt; int stat = acedEntSel(_T("\nオブジェクトを選択 : "), ename, pt); if (stat != RTNORM) return; AcDbEntity* pEnt; AcDbObjectId objId; acdbGetObjectId(objId, ename); Acad::ErrorStatus err = acdbOpenAcDbEntity(pEnt, objId, AcDb::kForRead); if (err != Acad::eOk) return; if (AcDbAssocArrayActionBody::isAssociativeArray(pEnt)) { acutPrintf(_T("\n自動調整配列です")); AcDbObjectId actId = AcDbAssocArrayActionBody::getControllingActionBody(pEnt, NULL); AcDbAssocArrayActionBody* pAryAct = NULL; err = acdbOpenAcDbObject((AcDbObject*&)pAryAct, actId, AcDb::kForWrite); if (err != Acad::eOk) { pEnt->close(); return; } if (AcDbAssocArrayPathParameters::cast(pAryAct->parameters())) acutPrintf(_T("\n - パス")); if (AcDbAssocArrayPolarParameters::cast(pAryAct->parameters())) acutPrintf(_T("\n - 円形状")); if (AcDbAssocArrayRectangularParameters::cast(pAryAct->parameters())) acutPrintf(_T("\n - 矩形状")); AcDbObjectIdArray newIds; pAryAct->explode(pEnt, newIds); pAryAct->close(); } else acutPrintf(_T("\n自動調整配列ではありません")); pEnt->close(); return;   EXPLODE コマンドで自動調整配列複写を分解する場合には、次のようなコードで AcDbAssocArrayActionBody::explode()  メンバー関数を代替することが出来ます。いずれの場合も、自動調整フレームワークが構成要素オブジェクトを保持しているため、すべてのオブジェクトを指定する必要はありません。   ads_name sset; acedSSAdd(NULL, NULL, sset); acedSSAdd(ename, sset, sset); acedCommandS(RTSTR, _T("EXPLODE"), RTPICKS, sset);      
記事全体を表示
Issue 選択したオブジェクトが自動調整配列複写の要素かどうか判定して、自動調整配列複写であった場合に分解する実装するには、どのようなコードを記述すればいいでしょうか?     Solution 自動調整配列複写の対象となっているオブジェクト一式は、匿名ブロック(Anonymous Block)として自動調整フレームワークで管理、維持されています。   自動調整配列複写の判定には、AssocArray.IsAssociativeArray メソッドを利用することが出来ます。 同様に、分解には AssocArray.Explode メソッドを利用することが出来ます。   次のコードは、選択したオブジェクトが自動調整配列複写の構成要素だった場合に、トップレベルの調整配列複写を分解する C# 例です。   Database db = HostApplicationServices.WorkingDatabase; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityResult pent = ed.GetEntity("\nオブジェクトを選択:"); if (pent.Status != PromptStatus.OK) { return; } using (Transaction tr = db.TransactionManager.StartTransaction()) { if (AssocArray.IsAssociativeArray(pent.ObjectId)) { ed.WriteMessage("\n自動調整配列です"); AssocArray ary = AssocArray.GetAssociativeArray(pent.ObjectId); var param = ary.GetParameters(); if (param as AssocArrayPathParameters != null) ed.WriteMessage("\n - パス"); if (param as AssocArrayPolarParameters != null) ed.WriteMessage("\n - 円形状"); if (param as AssocArrayRectangularParameters != null) ed.WriteMessage("\n - 矩形状"); AssocArray.Explode(pent.ObjectId); } else ed.WriteMessage("\n自動調整配列ではありません"); tr.Commit(); }   EXPLODE コマンドで自動調整配列複写を分解する場合には、次のようなコードで AssocArray.Explode メソッドを代替することが出来ます。いずれの場合も、自動調整フレームワークが構成要素オブジェクトを保持しているため、すべてのオブジェクトを指定する必要はありません。   var sset = SelectionSet.FromObjectIds(new ObjectId[] { pent.ObjectId }); ed.Command("EXPLODE", sset);    
記事全体を表示