興味があろうがなかろうが。

なるべく役に立つ、とがった内容を記していきたいと思います。

【FreeCADプログラミング】あるエッジに平行なエッジの本数を数える

本日のお題は『あるエッジに平行なエッジの本数を数える』です。

久しぶりの演習課題となります。ぜひ最初は回答を見ずにチャレンジしてみてください。

とりあえず、これまでの記事を使えば、ある程度実装できると思います。

1. 環境

  • FreeCAD 0.18

2. 例題の内容

マクロ起動前に直線エッジを1本選択し、マクロ起動後、ログに本数分の★を表示して終了します。

3. 手順

ロジックは以下のようになるかと思います。

  1. 起動前に選択されたエッジを取得
  2. 1で取得したエッジからベクトルを取得
  3. ドキュメント内のすべての直線エッジを取得
  4. 3で取得したエッジのベクトルと、2で取得したベクトルが同一なエッジを
    かき集める
  5. 4で取得したエッジ群をループして、ログに★を表示

4. プログラムを書いてみよう

今回は以前の『矢印ソリッド作成』の演習課題ほど、詳細なロジック検討は不要ですので、早速プログラムを紹介していきます。

可能であれば、回答を見る前にチャレンジしてみて頂きたいと思います。

# -*- coding: utf-8 -*-

#import ptvsd
#print("Waiting for debugger attach")
# 5678 is the default attach port in the VS Code debug configurations
#ptvsd.enable_attach(address=('localhost', 5678), redirect_output=True)
#ptvsd.wait_for_attach()

import FreeCAD
import FreeCADGui

#平行判定メソッド
def IsParallel(vector1, vector2):
	tolerance = 0.0001
	dotProduct = vector1.dot(vector2)
	#1から0.9999 もしくは -0.9999から-1 までの間であれば平行とする
	if((-1 <= dotProduct and dotProduct <= -1 + tolerance) or (1 - tolerance <= dotProduct and dotProduct <= 1 )):
		return True
	else:
		return False

##### ここからメイン処理 #####

#選択されたエッジを取得
sel = FreeCADGui.Selection.getSelectionEx()

#単位化を忘れずに!
targetEdge = sel[0].SubObjects[0]
baseVec = FreeCAD.Vector(
    targetEdge.Vertexes[0].X - targetEdge.Vertexes[1].X,
    targetEdge.Vertexes[0].Y - targetEdge.Vertexes[1].Y,
    targetEdge.Vertexes[0].Z - targetEdge.Vertexes[1].Z
).normalize()

# アクティブなドキュメントを取得
activeDoc = App.ActiveDocument

# アクティブドキュメントから作成履歴群を取得
histories = activeDoc.Objects

parallelEdges = list()  #平行なエッジ群
for history in histories:
    solidObj = history.Shape

    # エッジを取得
    edgeObjs = solidObj.Edges

    for edgeObj in edgeObjs:
        if(type(edgeObj.Curve) is Part.Line and len(edgeObj.Vertexes) == 2):
            #単位化を忘れずに!
            targetVec = FreeCAD.Vector(
                edgeObj.Vertexes[0].X - edgeObj.Vertexes[1].X,
                edgeObj.Vertexes[0].Y - edgeObj.Vertexes[1].Y,
                edgeObj.Vertexes[0].Z - edgeObj.Vertexes[1].Z
            ).normalize()

            #平行判定
            isPara = IsParallel(baseVec, targetVec)
            if(isPara == True):
                parallelEdges.append(edgeObj)

# 重複した要素が入っている可能性が高いため重複除去して使用
for wkEdge in set(parallelEdges):
    FreeCAD.Console.PrintMessage("★")
    # 選択したエッジと同一のエッジはカウントしないようにしたかったが、
    # 同一であるか判定するための要素が見当たらない。。。
    # ポインタは同一になるかと思いきや、毎回別のアドレスを生成している模様。
    # 現状、端点位置が同一であるか以外に確認する術が見当たらない。これはちょっとヤバイ。
    #
    # if(targetEdge != wkEdge):
    #     # 自分と同一ではないエッジ
    #     FreeCAD.Console.PrintMessage("★")
    # else:
    #     FreeCAD.Console.PrintMessage("☆")
FreeCAD.Console.PrintMessage("\n")

とりあえず、立方体のエッジを1つ選択して実行してみると、以下のようになります。

f:id:appli-get:20200306150300p:plain

確認用に立方体の1エッジを選択して起動
★★★★

一応合っているようですね。

4. 補足

実は上記のプログラムには少々問題があります。

4.1. あるEdgeと、あるEdgeが同一か判定する方法が見当たらない

ソースコードの最下部(コメントになっている部分)を見てください。

実はこの演習課題では元々、最初に選択したエッジと同一のエッジが見つかった場合は、その時だけ『☆』を表示する予定でした

しかし、今回調べていてわかりましたが、エッジ同士が同一かどうかを判断する方法が現状ありません(見つかっていないだけだとは思いますが)。

私の想定では、『if(targetEdge != wkEdge):』のようにアドレスの比較でうまくいくかと思っていたのですが、ダメでした。

一見、大きな問題には見えないかもしれませんが、これはかなり重要です。

今回の記事では、これ以上深追いしませんが、後日調査してみたいと思います。
(もしかしたら、私のコードが良くないだけかもしれませんし!)

5. 最後に

これがホンモノの案件だったら、調査のために思わぬ出費を被るところでしたね。

おーなんだかリアルで怖い。

更なる情報をお探しの方は!

下記のリンクから、FreeCADプログラミングのトップページに飛びます。

よろしければご参照くださいませ。

www.interested-or-not.com