Autodesk Community Tips- ADNオープン
Autodesk Community Tipsではちょっとしたコツ、やり方、ショートカット、アドバイスやヒントを共有しています。
ソート順:
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 .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 次のような「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 連続実行で図形を順番に開いて、処理、保存しようとしています。図面を順次開く必要があるので、定義コマンドに 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 寸法を分解すると寸法値にあたる文字が MText オブジェクトとして分解されます。 この MText オブジェクトについて、MText.Contents プロパティから寸法値の文字を取得すると、寸法値にないコードが返される場合があります。   例:\A1;57,{\H0.7x;\S66^;}   このコードはどのようなものでしょうか?   Solution このコードは、マルチテキストの整形するために用意された「書式コード」と呼ばれるコードで、AutoCAD のオンラインヘルプ ページで内容を確認することが出来ます。 AutoCAD 2024 ヘルプ | 他のテキスト エディタの書式コード リファレンス | Autodesk AutoCAD .NET API で MText オブジェクトの文字列の内容を確認する場合には、Contents プロパティが書式コード付きの内容を、Text プロパティが書式コードを削除した内容を返すので、用途に応じてプロパティを使い分けることが出来ます。   Database db = HostApplicationServices.WorkingDatabase; 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 iLogicで現在開いているファイルがVaultに登録されているかを知る方法はありますか。 回答 Inventor iLogicからVaultのAPIを用いて、Vaultのチェックイン状態を確認することが可能です。   Vaultでのチェックイン状態を知るためには、対象のファイルのVualtのフォルダ構造のパス情報を用いてDocumentService.FindLatestFilesByPaths()メソッドを利用します。     以下は、現在Inventorで開いているファイルおよびその参照ファイルがVaultに登録されているかを確認し、Vaultに登録されていない場合は、iLogicのログにファイルのパスを出力するサンプルコードとなります。   なお、サンプルコードではわかりやすさを優先して、1ファイルずつDocumentService.FindLatestFilesByPaths()メソッドを実行していますが、 DocumentService.FindLatestFilesByPaths()メソッドには複数のパス情報を配列として指定可能なため、パフォーマンスを考慮した場合には、まとめて実行することをお勧めいたします。     ◆iLogicのファイルヘッダ AddReference "Autodesk.Connectivity.WebServices.dll" Imports AWS = Autodesk.Connectivity.WebServices AddReference "Autodesk.DataManagement.Client.Framework.Vault.dll" Imports VDF = Autodesk.DataManagement.Client.Framework AddReference "Connectivity.Application.VaultBase.dll" Imports VB = Connectivity.Application.VaultBase AddReference "Autodesk.DataManagement.Client.Framework"   ・ iLogicソース  Sub Main() Dim conn As VDF.Vault.Currency.Connections.Connection conn = VB.ConnectionManager.Instance.Connection If conn Is Nothing Then MessageBox.Show("Vaultにログインしていません。") Return End If Dim rootFolder As String rootFolder = conn .WorkingFoldersManager.GetWorkingFolder("$/").FullPath For Each doc As Inventor.Document In ThisDoc.Document.AllReferencedDocuments If (FindFileInVault(doc.FullFileName, rootFolder, conn)) Then Else Logger.Trace("{0} is not checked in to Vault ", doc.FullFileName) End If Next End Sub Public Function FindFileInVault(localfilePath As String, workingfolder As String, conn As VDF.Vault.Currency.Connections.Connection) As Boolean Dim VaultPath As String = localfilePath.Replace(workingfolder, "$/") VaultPath = VaultPath.Replace("\", "/") Dim VaultPaths() As String = New String() {VaultPath} Dim wsFiels() As AWS.File = conn.WebServiceManager.DocumentService.FindLatestFilesByPaths(VaultPaths) If wsFiels(0).Id <> -1 Then Return True End If Logger.Trace("localfilePath is {0}", localfilePath) Logger.Trace("VaultPath={0}, id={1}", VaultPath, wsFiels(0).Id) Return False End Function  
記事全体を表示
質問 AutoCAD .net API でパレットを作成しました。パレットには、テキストボックスを配置したカスタムコントロールを配置しています。パレットを表示しテキストボックスに値を入力している途中で、マウスカーソルをパレットから外すと、フォーカスがテキストボックスから外れ、以後のキー入力はAutoCADのコマンド入力として処理されてしまいます。 パレットからマウスカーソルを外してもフォーカスが外れないようにすることはできますか。   回答 PaletteSetを継承したクラスを作成し、KeepFocusメソッドをオーバライドして、フォーカスを外したくない場合には戻り値falseを戻すように実装することで実現が可能です。   以下は、テキストボックス(textBox1)を配置したユーザコントロール(UserControl1)をパレットに配置し、textBox1にフォーカスがある場合は、コントロールからフォーカスを外さない処理をKeepFocusメソッドに記述したサンプルコードとなります。   public class MyPalettSet : PaletteSet { private UserControl1 uctl1 = new UserControl1(); public MyPalettSet(string name) : base(name) { this.Style = PaletteSetStyles.ShowTabForSingle | PaletteSetStyles.ShowPropertiesMenu | PaletteSetStyles.ShowAutoHideButton | PaletteSetStyles.ShowCloseButton; this.MinimumSize = new System.Drawing.Size(400, 100); this.Add("uctl", uctl1); this.Visible = true; this.Size = new System.Drawing.Size(400, 100); this.DockEnabled = DockSides.None; } public override bool KeepFocus { get { return uctl1.Controls["textBox1"] != null ? uctl1.Controls["textBox1"].Focused : false; } } }
記事全体を表示
Issue AutoCAD のダイナミック ブロックについて、VBA でどの程度操作ができるかわかりません。 モデル空間などに配置されているダイナミック ブロックのパラメータの状態を取得したり、パラメータの値を更新して、形状や表示状態を変更することはできますか?   Solution ダイナミックブロックとして配置されているブロック参照からは、ある程度の情報を取得したり、その値を変化させることができます。ただし、現在のバージョンでは一部制限があるため、すべての情報の制御や、パラメータ間の関連付けを得ることができません。   ブロック参照からダイナミックブロック固有の情報にアクセスするには、AcadBlockReference オブジェクトの GetDynamicBlockProperties メソッドを使用して、パラメータ情報を含むコレクションを取得します。このコレクションには、DynamicBlockReferenceProperty オブジェクトがパラメータ(アクションとの組み合わせ)数分含まれます。   DynamicBlockReferenceProperty オブジェクトを取得した後は、このオブジェクトが持つプロパティを使って、パラメータ別の情報にアクセスできます。つまり、ダイナミック ブロック参照の現在の設定値を得ることが可能です。   なお、パラメータによっては、ルックアップ テーブルや可視テーブルなど、リスト化された情報も存在します。このような場面では、パラメータを表す DynamicBlockReferenceProperty.Value プロパティは配列として返されます。これをチェックすれば、その内容を AllowedValues プロパティから閲覧することもできます。   添付のコードは、ダイナミックブロックの情報を取得する例です。   Dim nDataIndex As Long Dim vDataInfo As Variant Dim oData As AcadDynamicBlockReferenceProperty Dim nListIndex As Long Dim vListInfo As Variant Dim nRound As Integer Dim oEnt As AcadEntity Dim oBlkRef As AcadBlockReference nRound = ThisDrawing.GetVariable("LUPREC") For Each pEnt In ThisDrawing.ModelSpace If pEnt.ObjectName = "AcDbBlockReference" Then Set oBlkRef = pEnt If oBlkRef.IsDynamicBlock Then ThisDrawing.Utility.Prompt vbCrLf & "***** ダイナミックブロック - " ThisDrawing.Utility.Prompt oBlkRef.EffectiveName & " : " & oBlkRef.Name nCtrlIndex = 1 For nDataIndex = LBound(oBlkRef.GetDynamicBlockProperties) To UBound(oBlkRef.GetDynamicBlockProperties) Set oData = oBlkRef.GetDynamicBlockProperties(nDataIndex) If oData.show Then ' パラメータ名ラベル ThisDrawing.Utility.Prompt vbCrLf & oData.PropertyName & " : " ' パラメータが配列か確認 vDataInfo = oData.Value If IsArray(vDataInfo) Then ' 座標データの場合 ThisDrawing.Utility.Prompt Round(vDataInfo(0), nRound) & "," & Round(vDataInfo(1), nRound) & "," & Round(vDataInfo(2), nRound) Else ' リスト要素か確認 vListInfo = oData.AllowedValues If UBound(vListInfo) > 0 Then ' リスト要素の場合 For nListIndex = LBound(vListInfo) To UBound(vListInfo) If VarType(vDataInfo) = vbDouble Then ThisDrawing.Utility.Prompt vbCrLf & vbTab & CStr(Round(vListInfo(nListIndex), nRound)) Else ThisDrawing.Utility.Prompt vbCrLf & vbTab & vListInfo(nListIndex) End If Next nListIndex If VarType(vDataInfo) = vbDouble Then ThisDrawing.Utility.Prompt vbCrLf & vbTab & "現在値 : " & CStr(Round(vDataInfo, nRound)) Else ThisDrawing.Utility.Prompt vbCrLf & vbTab & "現在値 : " & vDataInfo End If Else ' 通常データの場合 If VarType(vDataInfo) = vbDouble Then ThisDrawing.Utility.Prompt Round(vDataInfo, nRound) Else ThisDrawing.Utility.Prompt vDataInfo End If End If End If End If ThisDrawing.Utility.Prompt vbCrLf Next End If End If Next
記事全体を表示
Issue 選択セットで条件に合った複数のオブジェクトを取得する際、特定の座標を持つ要素を条件に設定するにはどうしたらいいでしょうか?   Solution 選択セットのフィルタリングで座標を扱う際には、オンラインヘルプ 概要 - 選択セットのフィルタ リストでの関係テスト(AutoLISP) で触れられている、カンマ区切りで関係演算子を利用する方法を利用することが出来ます。   点グループ コードの場合、X、Y、Z に対するテストを結合して単一の文字列にできます。このとき、各演算子をカンマで区切ります(たとえば、">,>,*")。文字列から演算子を省略すると、すべてを選択する演算子 "*" とみなされます(たとえば、"=,<>" では Z がチェックされません)。 次のコードは、円オブジェクトの中心のX 座標が 123.45 以上123.46 以下で、Y 座標が 500.0、Z 座標値を無視するフィルタリングを指定した C# コードの例です。 Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; TypedValue[] typeAry = new TypedValue[9]; typeAry.SetValue(new TypedValue((int)DxfCode.Operator, "<and"), 0); typeAry.SetValue(new TypedValue((int)DxfCode.Start, "CIRCLE"), 1); typeAry.SetValue(new TypedValue((int)DxfCode.Operator, "<and"), 2); typeAry.SetValue(new TypedValue((int)DxfCode.Operator, ">=,=,*"), 3); typeAry.SetValue(new TypedValue((int)DxfCode.XCoordinate, new Point3d(123.45, 500.0, 0.0)), 4); typeAry.SetValue(new TypedValue((int)DxfCode.Operator, "<=,=,*"), 5); typeAry.SetValue(new TypedValue((int)DxfCode.XCoordinate, new Point3d(123.46, 500.0, 0.0)), 6); typeAry.SetValue(new TypedValue((int)DxfCode.Operator, "and>"), 7); typeAry.SetValue(new TypedValue((int)DxfCode.Operator, "and>"), 8); SelectionFilter filter = new SelectionFilter(typeAry); PromptSelectionResult psr = ed.SelectAll(filter); if (psr.Status == PromptStatus.OK) { SelectionSet sset = psr.Value; ed.WriteMessage("\nNumber of objects selected : {0}", sset.Count.ToString()); ObjectIdCollection objIds = new ObjectIdCollection(sset.GetObjectIds()); using (Transaction tr = db.TransactionManager.StartTransaction()) { Entity ent; foreach (ObjectId objId in objIds) { ent = (Entity)tr.GetObject(objId, OpenMode.ForRead); ent.Highlight(); } tr.Commit(); } } else { Application.ShowAlertDialog("\nNumber of objects selected: 0"); }  
記事全体を表示