ブロックとは複数のオブジェクトを組み合わせて一つにまとめたオブジェクトです。複雑な形状のオブジェクトを使い回すことができるため、図面の生産性が向上します。このように AutoCAD の図面を作成する上でブロックは無くてはならない機能の一つですが、これをプログラムで作成することができれば何かと使いどころがあるはずです。

なおサンプルコードは VisualStudio2005 の C# で作成し、 AutoCAD2007 / 2008 / 2009 で動作確認を行いました。

ブロック定義のサンプル

ブロック定義も他のオブジェクトと同じく、new キーワードでインスタンスを生成します。しかしその登録先は、ブロックテーブルであることに気をつけてください。ブロックテーブルに登録したら、生成したブロック定義に対してブロック内部のオブジェクトを登録していきます。

まずは下記のサンプルコードをビルドし、その成果物を AutoCAD に [NETLOAD] してください。次に [CREATE_SAMPLE] コマンドを発行すると "Sample" ブロック定義が登録されますので、[INSERT] コマンドで "Sample" ブロックを図面に挿入してみてください。

サンプルコード

[CommandMethod( "CREATE_SAMPLE" )]
public void CreateSample()
{
    Transaction trans = null;
    try
    {
        Document active_doc = Application.DocumentManager.MdiActiveDocument;
        Database active_db = active_doc.Database;
        trans = active_db.TransactionManager.StartTransaction();

        // 1. ブロックテーブルを開く
        ObjectId tbl_id = active_db.BlockTableId;
        BlockTable blk_tbl = (BlockTable)trans.GetObject( tbl_id, OpenMode.ForWrite );

        // 2. 同じ名前で登録されているブロック定義がないかをチェックする
        if( blk_tbl.Has( "Sample" ) )
        {
            active_doc.Editor.WriteMessage( "\nSample ブロックは登録済みです" );
            return;
        }

        // 3. ブロック定義オブジェクトを作成し、ブロックテーブルに登録する
        BlockTableRecord sample_blk = new BlockTableRecord();
        sample_blk.Name = "Sample";    // ブロック名
        blk_tbl.Add( sample_blk );
        trans.AddNewlyCreatedDBObject( sample_blk, true );
        active_doc.Editor.WriteMessage( "\n{0}", BlockTableRecord.ModelSpace );

        // 4. 従属図形を作成し、ブロック定義オブジェクトに登録する
        Circle small_circle = new Circle( Point3d.Origin, Vector3d.ZAxis, 50.0 );
        sample_blk.AppendEntity( small_circle );
        trans.AddNewlyCreatedDBObject( small_circle, true );

        Circle large_circle = new Circle( Point3d.Origin, Vector3d.ZAxis, 100.0 );
        sample_blk.AppendEntity( large_circle );
        trans.AddNewlyCreatedDBObject( large_circle, true );

        Line line = new Line( Point3d.Origin, new Point3d( 100, 0, 0 ) );
        sample_blk.AppendEntity( line );
        trans.AddNewlyCreatedDBObject( line, true );

        trans.Commit();
    }
    catch( System.Exception ex )
    {
        Editor edit = Application.DocumentManager.MdiActiveDocument.Editor;
        edit.WriteMessage( "\n" + ex.Message );
    }
    finally
    {
        if( trans != null )
        {
            trans.Dispose();
        }
    }
}

環境によっては、コンパイル時に "この参照を解決できませんでした" という警告が出ます。この場合 "acdbmgd.dll" と "acmgd.dll" を削除し、 AutoCAD のインストールディレクトリから参照しなおしてください。

実行結果

[ブロック挿入] ダイアログ("Sample" ブロックが登録されている)

Fig01: [ブロック挿入] ダイアログ

"Sample" ブロック挿入

Fig02: "Sample" ブロックの挿入

サンプルコード解説

ブロックテーブルを開く

データベースからブロックテーブルのオブジェクトIDを取得し、それを使ってブロックテーブルを開きます。ブロックテーブルには後でブロック定義オブジェクトを登録しますので、 ForWrite で開くことを忘れないでください。

ブロック名の重複チェック

ブロックテーブルには同じ名前のブロックを複数登録することはできず、重複して登録しようとすると eDuplicateRecordName エラーが発生します。これを避けるには BlockTable.Has() メソッドを使って事前に重複チェックをしておきます。

登録しようとした場合にどうするかはアプリケーションの仕様次第ですが、ここではメッセージを表示してコマンドを抜けることにしました。

ブロック定義オブジェクトを作成し、登録する

BlockTableRecord クラスのインスタンスを生成し、Name プロパティを設定(*1)するとブロック定義オブジェクトを作成することができます。そして、作成したブロック定義オブジェクトをブロックテーブルに登録します。

また、ブロック名に以下の文字を使用することはできません。その他の文字であれば、全角半角問わずに使用可能(*2)です。(カッコ内は ASCII コード)

従属図形を作成し、ブロック定義オブジェクトに登録する

従属図形をブロック定義オブジェクトに登録します。このサンプルでは大小二つの円と、その中心から X 軸方向に伸びる線分の三つのエンティティでブロックを作成しました(*4)

ブロックの挿入基点はデフォルトで原点(*5)に設定されています。グラフィカルに操作するかコード上で全てを再現するかの違いはありますが、ブロックエディタでブロックを作成する要領で作成すればいいでしょう。

関数仕様

SymbolTable.Has メソッド

シンボルテーブルにレコードが登録されているかを確認する。

public bool Has(
    ObjectId id
);
public bool Has(
    string key
);
引数 概要
ObjectId id 検索するレコードのオブジェクトID
string key 検索するレコードの名前

この関数はテーブルに id または key に一致するレコードが登録されている場合に true を返す。見つからない場合は false を返す。

(MINERVA 深津貴成)
  1. ^ ここで Name プロパティを指定しなくても動くことは動きますが、このようなブロックを [INSERT] コマンドで挿入することはできませんので、おそらく使い道はないでしょう。
  2. ^ AutoCAD2007 以降では、内部文字列は Unicode で実装されています。従って上記にあげた文字以外はほぼ何でもありで、例えば漢字と半角カタカナとハングルとキリル文字を混在させても想定通りに動作します。
  3. ^ " (32)" と "|(124)" は、文字列の先頭と末尾でなければ使用可能です。
  4. ^ 従属図形の登録は、モデルスペースに図形を表示する流れとそっくりですが、モデルスペースはブロック定義オブジェクトそのものですので、当然といえば当然です。モデルスペースは "*MODEL_SPACE" という名前で登録されていますが、上述の通り "*" をブロック名に使用することはできませんので、名前がかぶることはありません。
  5. ^ 挿入基点を変更するには、BlockTableRecord.Origin プロパティを使用します。