<第14回目:’04年1月7日>

dxf ファイルを読み込むテストプログラムを作成する
 


前回はqcadの出力したdxfファイルの内容を調べました。これに基づき、dxfファイルを読み込み各エンティティを動的メモリに取り込むテストプログラムを作成しました。

dxfファイルを読みこむための構造体は以下のようなものです。2種類あり、円弧、直線、点、テキスト、円の図形を構成するエンティティ用とそれ以外のレイヤ情報テキスト用です。

// エンティティオブジェト (arc,line,point,circle,text)の構造体
struct OBJ {

    int index;                 // 連番
    int type;                  // タイプ
    int cw;                    // 切削方向
    int block;                 // 接続ブロック

    double x1;                 // DXFの端点1
    double y1;
    double x2;                 // DXFの端点2
    double y2;

    int style;                 // DXFのスタイル
    int layer;                 // DXFのレイヤ
    int color;                 // DXFの色
    int width;                 // DXFの線幅

    double cx;                 // DXFのARC,CIRCLEの中心点
    double cy;

    double cr;                  // DXFのARC,CIRCLEの半径
    double sa;                  // DXFのARC,CIRCLEのスタートアングル
    double ea;                  // DXFのARC,CIRCLEのエンドアングル

    struct OBJ *prev_obj_ptr;   // 前のオブジェクトへのポインタ
    struct OBJ *next_obj_ptr;   // 次のオブジェクトへのポインタ
};

// レイヤ情報textの構造体
struct TEXT_OBJ {
    struct OBJ *obj_ptr;         // オブジェクトへのポインタ
    int layer;                   // レイヤ
    int cw;                      // 切削方向
    float depth;                 // 切削厚
    float step;                  // 切削厚ステップ
    int speed;                   // 切削速度
    char text_str[256];          // テキスト本体
    struct TEXT_OBJ *prev_text_obj_ptr; // 前のオブジェクトへのポインタ
};

次にのエンティティを解析する部分は以下のようにしました。qcadのdxfファイルの読み込み部分のフローを参考にしています。ARC(円弧)のエンティティ部分を解析する部分を抜粋しました。

  // DXFファイルをオープンして〜
  // 各ポインタを初期化して〜

  while (!feof(rfp)) {                                 // ファイルの終りが来るまで

    strcpy(val_str, get_line());                       // 1行入力(value)

    // *******
    // Arc
    // *******
    if (!strncmp(val_str, "ARC", 3)) {                 // ARCなら

      obj_ptr = (OBJ *)malloc(sizeof(OBJ));            // メモリを取得する

      if (!obj_ptr) {
        fprintf(stderr, "Can't malloc\n");             // メモリが取得できなかった
        exit(1);
      }

      do {
        code=atoi(get_line());                         // 1行入力(code)

        if (code) {

          if (code && code!=0) {                       // codeが有効なら
            strcpy(val_str, get_line());               // 1行入力(設定値)
            if (val_str) {                             // 内容が有効なら
              switch (code) {                          // codeで処理を分岐

                case  6:  // Style
                  obj_ptr->style = atoi(val_str);
                break;

                case  8:  // Layer
                  obj_ptr->layer = get_layer(val_str);

                  if (obj_ptr->layer > 0)
                      layer_f = 1;

                  // フラグが立っていれば時計周り
                  if (obj_ptr->layer >= LAYER_CW_FLAG) {
                      obj_ptr->obj_cw = 1;
                      obj_ptr->layer = LAYER_CW_MASK & obj_ptr->layer;
                  }
                  else obj_ptr->obj_cw = 0;

                break;

                case 10:                              // Centre X
                  obj_ptr->cx = atof(val_str);
                break;

                case 20:                              // Centre Y
                  obj_ptr->cy = atof(val_str);
                break;

                case 40:                              // Radius
                  obj_ptr->cr = atof(val_str);
                break;

                case 50:                              // Start Angle
                  obj_ptr->sa = atof(val_str);
                break;

                case 51:                              // End Angle
                  obj_ptr->ea = atof(val_str);
                break;

                case 39:                              // Thickness
                  obj_ptr->width = atoi(val_str);
                break;

                case 62:                              // Color
                  obj_ptr->color = atoi(val_str);
                break;

                default:
                  break;
              }
            }
          }
        }
      } while(!!code && code!=0);                     // コードが無くなるまでループ

      obj_ptr->obj_type = OBJ_ARC;
      obj_ptr->obj_index = obj_index;

      obj_ptr->block = -1;

      // ARCは中心、半径、スタート、エンドアングルで定義されるため、端点を計算する
      obj_ptr->x1 = obj_ptr->cx + cos(obj_ptr->sa/A_RAD) * obj_ptr->cr;
      obj_ptr->y1 = obj_ptr->cy + sin(obj_ptr->sa/A_RAD) * obj_ptr->cr;
      obj_ptr->x2 = obj_ptr->cx + cos(obj_ptr->ea/A_RAD) * obj_ptr->cr;
      obj_ptr->y2 = obj_ptr->cy + sin(obj_ptr->ea/A_RAD) * obj_ptr->cr;

      obj_ptr->prev_obj_ptr = obj_last_ptr;           // 現在の前へ1つ前のポインタを設定

      if (obj_index >= 1)
          obj_last_ptr->next_obj_ptr = obj_ptr;       // 1つ前の次へ現在のポインタを設定

      obj_ptr->next_obj_ptr = (OBJ *)NULL;            // 現在の次はNULL
      obj_last_ptr = obj_ptr;                         // ラストポインタを設定
      obj_index++;                                    // 連番をインクリメント

    }

    //      ・
    //      ・
    // ARC以外の処理
    //      ・
    //      ・

  }

このプログラムを前回のテスト図形で実行した結果が以下です。動的メモリにデータを入れたあとその内容を表示したものです。でコメントを入れました。

>ARC[0] // 左側のARC
 style=0 color=0 width=0 layer=100 cw=1
 cx=170.000000 cy=100.000000 cr=130.000000
 x1=50.000000 y1=150.000000 x2=50.000000 y2=50.000000 // 計算で出した端点
 sa=157.380135 ea=202.619865

>ARC[1] // 右側のARC
 style=0 color=0 width=0 layer=100 cw=1
 cx=30.000000 cy=100.000000 cr=130.000000
 x1=150.000000 y1=50.000000 x2=150.000000 y2=150.000000
// 計算で出した端点
 sa=337.380135 ea=22.619865

>LINE[2] // 上側の直線
 style=0 color=0 width=0 layer=100 cw=1
 cx=0.000000 cy=0.000000 cr=0.000000
 x1=150.000000 y1=150.000000 x2=50.000000 y2=150.000000
 sa=0.000000 ea=0.000000

>LINE[3]
// 下側の直線
 style=0 color=0 width=0 layer=100 cw=1
 cx=0.000000 cy=0.000000 cr=0.000000
 x1=50.000000 y1=50.000000 x2=150.000000 y2=50.000000
 sa=0.000000 ea=0.000000

>CIRCLE[4]
// 原点を表すマゼンタの円
 style=0 color=13 width=5 layer=100 cw=1
 cx=100.000000 cy=0.000000 cr=5.000000
 x1=0.000000 y1=0.000000 x2=0.000000 y2=0.000000
 sa=0.000000 ea=0.000000

>TEXT[5]
// depth,speedのテキスト
 string  style=0 color=0 width=0 layer=-1 cw=0
 cx=60.487805 cy=158.048780 cr=0.000000
 x1=0.000000 y1=0.000000 x2=0.000000 y2=0.000000
 sa=0.000000 ea=0.000000

// レイヤ情報
>[TEXT]: layer=-1 cw=0 depth=1.000000 step=1.000000 speed=80 depth=1.0/1.0 speed=80

各オブジェクトレイヤ情報のテキストが正しく読み込めていることを確認ました。

次回は各オブジェクトの接続を辿ってブロックを抽出するプログラムを作成する予定です。