きゃんブロ

きゃんなブログ

自作npm、square-dxf-checker完成までの道のり#3 四角形になる条件設定と面積の算出

こんにちは。
aya-kyanです。

「自作npm、square-dxf-checker完成までの道のり」というタイトルでDXFの図形を判断し、面積を計算するというnpmを作成した過程について書いています。
今回が3番目の記事で、最終回です。
前回の記事は下記からどうぞ。

aya-kyan.hatenablog.com

 

「次回は、長方形になる条件設定について書きます。」と書いてから、かなり時間が経ってしまいました。
次に書きたいネタが出てきたので、この話を早く終わらせなくてはいけないと思い再び書いています。(早く書きなさい。)

本題に入ります。

 

長方形になる条件

長方形になる条件はなんでしょうか。
これは小学校で習いましたね。
正解は、「4つの角が全て等しい」です。
この条件に、「4つの辺の長さが全て等しい」も加わると、正方形になります。
したがって、正方形は長方形の仲間です。

今回は、DXFの中から情報を取り出し、それが長方形であることを確認します。
そのためには、下記のことが分かれば良いでしょう。

  • 図形を構成する辺が4本ある
  • 4つの角が全て等しい(=4隅の角が90度である)

まず、辺が4本なければ、長方形は作れませんね。
辺は少なすぎても多すぎてもダメで、4本でなければ他の図形が描画されていると判断してよさそうです。
それに加えて、長方形の条件である4隅の角が90度であることを証明できればよさそうです。
4隅の角が90度であることが証明できれば、平行四辺形、台形である可能性はなくなります。

 

長方形であることを証明する手順

長方形になる条件がわかりました。
それでは、どのようにすればそれを証明できるでしょうか。
熟考した結果、下記のような手順で証明すればいいのではないかと考えました。

  1. 4本の線を、下記の2ペアに分ける
    1. 水平な線2本
    2. 垂直な線2本
  2. それぞれのペアの線同士が同じ長さであることを確認する
    1. 水平な線同士が同じ長さである
    2. 垂直な線同士が同じ長さである
  3.  それぞれのペアの線が平行であることを確認する
    1. 水平である2本の線が平行である
    2. 垂直である2本の線が平行である
  4. 始点、もしくは終点が同じ座標であることを確認する
    1. 水平な線の座標同士
    2. 垂直な線の座標同士
    3. 水平な線の座標と、垂直な線の座標同士

これだけ書いてもわからないと思うので、詳細に説明をしていきます。

線の長さ、水平/垂直、平行であるかは確認済み

前回の記事で説明した情報をもとに、すでに下記のことができています。

  • 水平/垂直な線ごとにペアで分ける
  • 線の長さの取得

これにより、先述した1~3の条件は確認済みです。
再度、ターミナル上で出力したものを下記に記載します。

【Side View】
Vertical line in side view:
 [
  {
    StartPoint: [ '324.126701', '199.219757' ],
    EndPoint: [ '324.126701', '99.219757' ]
  },
  {
    StartPoint: [ '334.126701', '199.219757' ],
    EndPoint: [ '334.126701', '99.219757' ]
  }
]
Length of first line: 100
Length of second line: 100
These lines are same length.

Horizontal line in side view:
 [
  {
    StartPoint: [ '324.126701', '99.219757' ],
    EndPoint: [ '334.126701', '99.219757' ]
  },
  {
    StartPoint: [ '324.126701', '199.219757' ],
    EndPoint: [ '334.126701', '199.219757' ]
  }
]
Length of first line: 10
Length of second line: 10
These lines are same length.

Thickness: 10 

【Front View】
Vertical line in front view:
 [
  {
    StartPoint: [ '293.924544', '199.219757' ],
    EndPoint: [ '293.924544', '99.219757' ]
  },
  {
    StartPoint: [ '93.924544', '99.219757' ],
    EndPoint: [ '93.924544', '199.219757' ]
  }
]
Length of first line: 100
Length of second line: 100
These lines are same length.

Horizontal line in front view:
 [
  {
    StartPoint: [ '93.924544', '199.219757' ],
    EndPoint: [ '293.924544', '199.219757' ]
  },
  {
    StartPoint: [ '293.924544', '99.219757' ],
    EndPoint: [ '93.924544', '99.219757' ]
  }
]
Length of first line: 200
Length of second line: 200
These lines are same length.

水平/垂直の判断基準について少し復習をすると下記のようになります。

辺Aの始点から終点の、x座標の差分が0、かつy座標には差分がある

→ 辺Aは垂直方向

辺Aの始点から終点の、y座標の差分が0、かつx座標には差分がある

→ 辺Aは水平方向

前回、上記のように判断し、それぞれのグループでペアを作っていました。
したがって、それぞれのペアに属している線同士は、平行であると言えます。
なぜなら、水平な線のペアであれば、どちらの線も水平なので平行であると言えます。

*斜めに描画されている四角形はどうするんだ!というツッコミが入りそうですが、今回は考えないことにします。

さらに、始点から終点の差分から線の長さも取得していました。
以上より、線の長さ、水平/垂直であること、平行であることは確認済みです。

始点、もしくは終点が同じ座標であることを確認

1~3の条件は確認済みとなりました。
あとは4の条件を確認するのみです。
まずは、なぜこれを確認する必要があるのかを見ていきましょう。

水平/垂直である線の座標同士を確認する理由

もし確認しなかった場合、下記の画像のように線の位置がずれる可能性が生まれます。

これでは四角形を形作ることはできません。

水平な線と、垂直な線のそれぞれの座標同士を確認する理由

もし確認しなかった場合、下記のように4本の線同士が重ならない可能性が生まれます。

水平、垂直であることは確認できても重ならないのであれば四角形にはなりません。

座標が一致するか確認

下記のようなロジックで実装してみました。

  1. 垂直線の全ての座標を取得し配列に入れる(仮にarray1とする)
  2. 水平線の全ての座標を取得し配列に入れる(仮にarray2とする)
  3. array1の重複を削除
  4. array2の重複も削除
  5. 四角形であれば点が4点残るはずなので、array1とarray2が等しいか確認し、trueであれば検証OK

ちなみに、JavaScriptでは == で配列同士を判定することができないようです。

array1 = [ '199.219757', '324.126701', '334.126701', '99.219757' ]
array2 = [ '199.219757', '324.126701', '334.126701', '99.219757' ]
array1 == array2 //false

自作npm、square-dxf-checker完成までの道のり#2 DXFの構造

こんにちは。
aya-kyanです。

 

「自作npm、square-dxf-checker完成までの道のり」というタイトルでDXFの図形を判断し、面積を計算するというnpmを作成した過程について書いています。
今回は、2番目の記事です。

 

この記事では、DXFファイルからどのように座標情報や辺の情報を取得したのかについて書きます。
前回の記事は下記よりどうぞ。

aya-kyan.hatenablog.com

 

 

DXFの構造について

まずは、下記のようにわかりやすく書いてくれているものがあるので、この二つの記事から読むことをお勧めします。

qiita.com

qiita.com

 

これから説明することを理解するには、下記を押さえればOKです。

  • DXFは2行でひとつ
  • グループコードというものがある

こちらをもとに話を進めていきます。
以後、DXFの中身を記載する際は全て2行を1行にまとめたものを記載します。
先にお勧めした記事をめんどくさくて読んでおらず、「2行を1行...?」とwakaran状態になっている方は、元々のdxfファイルの中身だけ押さえておいてください。
こんな感じになっています。

0
SECTION
  2
HEADER
  9
$ACADVER
  1
AC1027
  9
$ACADMAINTVER
 70
   125
  9
$DWGCODEPAGE
  3
ANSI_932
  9
$LASTSAVEDBY
  1
thangas
  9
$REQUIREDVERSIONS
160
                 0
  9
$INSBASE
 10
.
.
.
#続く

今回、開発をするにあたり長方形のDXFファイルを用意しました。
開くと、下記のようになっています。

image.png

始点と終点を見つける

AutoCADの公式を見たところ、DXFでは

  • 10, 20, 30でx, y, z軸の始点
  • 11, 21, 31でx, y, z軸の終点

と定義づけをしているそうです。

 

これに従い、DXFファイルの中身を見て寸法らしきものを探してみました。
すると、10~30と、11~31がまとまって表示されている部分がありました。

 100 AcDbEntity
  8 表示
100 AcDbLine
 10 293.924544
 20 199.219757
 30 5.0
 11 293.924544
 21 99.219757
 31 5.0
  0 LINE
  5 B3
330 70

10, 20, 30でx, y, z軸の始点なので、始点は x 293.924544, y 199.219757, z 5.0
11, 21, 31でx, y, z軸の終点なので、終点は x 293.924544, y 99.219757, z 5.0

これで始点と終点を見つけることができました。

 

辺の長さを出し、辺が垂直方向か水平方向か判断する

上記で見つけた、始点から終点までの差分を計算してみると、
x = 293.924544 - 293.924544 = 0
y = 199.219757 - 99.219757 = 100
z = 5.0 - 5.0 = 0
となります。始点から終点にかけて、y軸方向に100の長さが表現されているとわかりますね。

ここで、最初にあげたDXFの図形を思い出してみます。

image.png

縦方向の100の長さの辺があります。

このことから、始点から終点のx座標の差分が0、かつ始点から終点のy座標には差分があるという場合はこの辺は垂直方向であると言えます。

横方向も同じようにして求めることができます。

  • 始点から終点のy座標の差分が0
  • 始点から終点のx座標の差分がある

という場合は、辺は水平方向であると言えます。

正面図の線分なのか側面図の線分なのか見分ける

正面図と、側面図の線分情報を見比べてみます。

正面図の線分情報

 0 LINE
  5 159
330 70
100 AcDbEntity
  8 表示
100 AcDbLine
 10 293.924544
 20 99.219757
 30 5.0
 11 93.924544
 21 99.219757
 31 5.0

側面図の線分情報

  0 LINE
  5 15A
330 70
100 AcDbEntity
  8 表示
100 AcDbLine
 10 324.126701
 20 199.219757
 30 100.0
 11 324.126701
 21 99.219757
 31 100.0
210 -1.0
220 0.0000000000002967
230 0.0000000000002967

二つを見比べると、側面図の方にだけ、210~230のグループコードがあることがわかります。
なぜ後者のグループコードが側面図の線分情報だとわかったかというと、AutoCADの公式によれば、210~230は押し出し方向のグループコードのようでした。
このことから、線分情報の中に210~230のグループコードが見つかった場合は側面図の線分であると特定することができます。

寸法線を見分ける

今度は、モデルの線分情報と、寸法線の線分情報だと思われるものを見比べてみます。

モデルの線分情報

100 AcDbEntity
  8 表示
100 AcDbLine
 10 293.924544
 20 199.219757
 30 5.0
 11 293.924544
 21 99.219757
 31 5.0
  0 LINE
  5 157
330 70

寸法線と思われる線分情報

100 AcDbEntity
  8 Dimensions
440 16777216
370 -2
100 AcDbLine
 10 327.626701
 20 209.719757
 30 0.0
 11 330.626701
 21 209.719757
 31 0.0
  0 SOLID
  5 19D
330 F9

違いを見つけられましたか?
答えは、寸法線の線分情報には「Dimensions」が含まれていることです。
上記の2列ずつにまとめたコード例で言うと、2行目です。

上記のような感じで、あっという間に下記情報の特定が出来ました。

  • 始点と終点
  • 辺の長さと向き
  • 側面図と正面図の線分
  • 寸法線

これらを利用し、寸法線は除外し、図形を構成している線分データのみから情報を取り出すようにコードを書きます。
コードは、githubをご確認ください。

ターミナル上に出力したものが下記です。(現時点で説明しているもののみを掲載)

【Side View】
Vertical line in side view:
 [
  {
    StartPoint: [ '324.126701', '199.219757' ],
    EndPoint: [ '324.126701', '99.219757' ]
  },
  {
    StartPoint: [ '334.126701', '199.219757' ],
    EndPoint: [ '334.126701', '99.219757' ]
  }
]
Length of first line: 100
Length of second line: 100
These lines are same length.

Horizontal line in side view:
 [
  {
    StartPoint: [ '324.126701', '99.219757' ],
    EndPoint: [ '334.126701', '99.219757' ]
  },
  {
    StartPoint: [ '324.126701', '199.219757' ],
    EndPoint: [ '334.126701', '199.219757' ]
  }
]
Length of first line: 10
Length of second line: 10
These lines are same length.

Thickness: 10 

【Front View】
Vertical line in front view:
 [
  {
    StartPoint: [ '293.924544', '199.219757' ],
    EndPoint: [ '293.924544', '99.219757' ]
  },
  {
    StartPoint: [ '93.924544', '99.219757' ],
    EndPoint: [ '93.924544', '199.219757' ]
  }
]
Length of first line: 100
Length of second line: 100
These lines are same length.

Horizontal line in front view:
 [
  {
    StartPoint: [ '93.924544', '199.219757' ],
    EndPoint: [ '293.924544', '199.219757' ]
  },
  {
    StartPoint: [ '293.924544', '99.219757' ],
    EndPoint: [ '93.924544', '99.219757' ]
  }
]
Length of first line: 200
Length of second line: 200
These lines are same length.

参考

自作npm、square-dxf-checker完成までの道のり#1 npmの概要と製作背景

はじめに

こんにちは。
aya-kyanです。

 

昨年の6月24日からFJORD BOOT CAMP(フィヨルドブートキャンプ)というオンラインのプログラミングスクールに通い始めてもうすぐ一年が経ちます。
このブログはfjordに通い始めて早々、ブログを立ち上げるプラクティスがあったことから立ち上げました。
しかし残念ながら1文字も書かれることはなく、現在に至っています。

そんな人が、急にブログを書き始めるとは、何があったのでしょうか。
そうです。ブログのタイトルにある通り、自作npmが完成しました。
この際だからこれをネタにしてブログを書いてみよう!と思い立ちました。(今までネタなかったのか?)

自作npmについても、そのようなプラクティスがあったことから作成をしました。
今回は、どのようなnpmを作成したのか、そして作成しようと思った背景を書こうと思います。

 

npm「square-dxf-checker」の概要

作成したnpmはズバリ、「square-dxf-checker」です!!!

www.npmjs.com

 

この子ができることは下記です。

  • DXFファイルをスキャンして四角形もしくは長方形であるか否かを判断
  • 四角形か長方形であれば下記の情報を出す
    • モデルを構成している辺の情報
    • 側面図から板厚情報を算出
    • 正面図から表面積を算出
  • モデルはプレート(板金もの)を想定している

npm「square-dxf-checker」を作成した背景

自分の実際の仕事と、そこから感じた事を元にこのnpmの構想を考えました。
というのも、私は金属加工業界に特化したプラットフォームを運営している会社で、カスタマーサクセスという仕事をしています(2022年6月現在)。

過去に、発注者さんと工場さんを繋ぐ仲介業をしていたことがありました。
その業務の中で、発注者さんからもらった図面を見積もるという作業をしたことがありました。
「見積もる」というのは、お客様が「この製品を作成したい、いくらでできる?」と図面を持ってくるのに対し、どのくらいの金額で製作できるかを算出することです。
(ちなみに私は板金加工のみを担当していたので、切削加工やその他加工についてはわかりません。)

見積もる過程では、そのモデルの表面積を求めるという作業があります。
表面積は、おもて面だけです。

板厚も見積もりをするのに重要ですが、算出するという大掛かりなものではありません。大体図面に書いてあります。

面積や板厚という情報を手に入れてから、ごにょごにょして見積もり金額が完成!という流れになります。
私はふとこの作業をしていて思いました。

「面積だけでも自動で求めることができれば、見積もり作業はだいぶ楽になるのでは...?」

他のものは大体ロジックが決まっていて、面積や板厚の情報をもとに材質や表面処理などの金額が算出されて、加算されていくだけでした。
面積を算出できれば、それに付随するプログラムも書けるはず。

しかも、「見積もる」という行為は、無駄になることが多いです。
お客さんの図面を見積もっても、必ず受注できるとは限りません。
なので、極力見積もる労力は削減したいところです。

そこで、面積を算出するnpmを作成しよう!と思い立ちました。
以上が背景です。

DXFから面積や板厚を取得するnpmは今までにあったのか?

このnpmを作成するにあたり、すでにこのような面積を算出するnpmはあるのか調べてみました。
「dxf area」「dxf calculate」などと調べてみましたが、見当たりませんでした。
もしかしたら私の調べ方が下手なだけで、あるのかもしれないけど...

このnpmは、四角形と長方形というシンプルな図形しか判定ができませんが、他の複雑な図形のDXFを解析できるnpmがもっと世に出てくれればいいなと思っています。
そうすれば、工場さんの見積もり作業も楽になるツールがもっと出るはず!!!

ただ、このnpmが対象としている四角形や長方形は面積を算出するのに大変ではないので、このnpmの出番はあまりなさそうです。

似たnpmを作成しようとしていて、参考にしてくれる人がいればとても嬉しいです。
次回は、npmからどのように座標や辺の情報を取り出したのかを書きます。