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

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

【FreeCADプログラミング】UNDOポイントを実装する

 

本日のお題は『UNDOを実装する』です。

前回の記事でUNDO, REDOを実行する方法を紹介しました。

www.interested-or-not.com

今回はUNDOを実行した際に『戻る位置(UNDOポイント)』を、プログラムから定義する方法を紹介したいと思います。

1. 環境

FreeCAD 0.18

2. 使用するAPI

下記2つのメソッドを使用します。

  1. App.ActiveDocument.openTransaction("文字列")
  2. App.ActiveDocument.commitTransaction()

1つ目のメソッドでUNDOポイントの定義を開始し、その後、2つ目のメソッドを実行することでUNDOポイントを作成(確定)します。

3. 何のために使うのか

自作のプログラムを作っている方であれば、お気づきかもしれませんが、プログラムを実行した後、実行前の状態に戻す操作ができず、モデルを開き直したりしていませんか。

例えば下図のような時系列を想像してください。

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

自作プログラムにUNDOポイントを定義しなかった場合の時系列

 

この場合、図のUNDOポイント③の地点からUNDOを実行した場合、②の地点まで戻ってしまいます。

普通に考えれば、点線で書かれている自作プログラムを実行した地点まで戻りたいと思いますよね?

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

UNDOポイント③からUNDOを実行した場合の時系列

上記より、UNDOを的確な場所に配置するのはマクロプログラム開発において、とても重要なことなのです。

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

どうせなので今回は、以前紹介した『ベクトル確認用矢印ソリッド』のプログラムに対して、UNDOポイントを作成する処理を追加してみましょう。 

www.interested-or-not.com 

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

import FreeCAD
import FreeCADGui
import Part
import JoinFeatures
import BOPTools.JoinFeatures
import math
import sys

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()

# ビュー上の選択されたオブジェクトを取得
# (フェースを選択を前提にしている。他のタイプが選択されたときの例外処理は入れていない)
sel = FreeCADGui.Selection.getSelectionEx()

if(len(sel) != 0):
	# UNDOポイントの定義開始
	App.ActiveDocument.openTransaction("CreateVectorSolid")

	# ピック位置と、ピック位置の法線ベクトルを取得
	pickCoord = sel[0].PickedPoints[0]
	selectedFace = sel[0].SubObjects[0]
	faceSurface = selectedFace.Surface
	uvCoord = faceSurface.parameter(pickCoord)
	normalVec = selectedFace.normalAt(uvCoord[0], uvCoord[1])
	print(str(normalVec))
	
	# 円錐の作成(デフォルトはheightが10mmになる)
	App.ActiveDocument.addObject("Part::Cone","Cone")
	App.ActiveDocument.ActiveObject.Label = "Cone"
	App.ActiveDocument.recompute()
	
	cone = App.ActiveDocument.getObject("Cone")
	App.ActiveDocument.getObject("Cone").Radius1 = '0 mm'
	App.ActiveDocument.getObject("Cone").Placement = App.Placement(App.Vector(0,0,0),App.Rotation(App.Vector(0,1,0),180))
	
	# 円柱の作成(デフォルトはheightが10mmになる)
	App.ActiveDocument.addObject("Part::Cylinder","Cylinder")
	App.ActiveDocument.ActiveObject.Label = "Cylinder"
	App.ActiveDocument.recompute()
	
	# 円錐と円柱がスレスレの位置にあると、和が取れない可能性があるので、0.1mm重なるように設定
	cylinder = App.ActiveDocument.getObject("Cylinder")
	App.ActiveDocument.getObject("Cone").Placement = App.Placement(App.Vector(0,0,19.99),App.Rotation(App.Vector(0,1,0),180))
	
	# 円錐と円柱の和を取る
	App.activeDocument().addObject("Part::MultiFuse","Fusion")
	App.activeDocument().Fusion.Shapes = [App.activeDocument().Cylinder,App.activeDocument().Cone,]
	App.ActiveDocument.recompute()
	
	# 絶対座標系
	xAxis = FreeCAD.Vector(1,0,0)
	yAxis = FreeCAD.Vector(0,1,0)
	zAxis = FreeCAD.Vector(0,0,1)
	
	# 法線ベクトルを単位化(おそらくデフォルトで単位化されているはずだが念のため)
	normalVec.normalize()
	
	# Z軸との外積を取得する(Z軸を軸に外積を取るのがミソ)
	rotationAxis = zAxis.cross(normalVec)
	
	# 回転のAPIの入力が度数を欲しているため変換
	angle = zAxis.getAngle(normalVec) * 180 / math.pi
	
	# ソリッドの移動と回転  
	App.activeDocument().getObject("Fusion").Placement = App.Placement(App.Vector(pickCoord.x,pickCoord.y,pickCoord.z),App.Rotation(rotationAxis, angle))

	#UNDOポイントの定義終了
	App.ActiveDocument.commitTransaction()

フェースを選択してから本マクロを実行すると、その選択した地点に矢印ソリッドが作成されます。

その後、キーボードで『Ctrl + Z』もしくは、FreeCADのメニューから『編集 - 元に戻す』を実行してみましょう。マクロの実行前まで戻りましたね。

ちなみに、以前の記事で紹介した矢印ソリッドのプログラムを実行すると、マクロのプログラム実行より一つ前のUNDOポイントまで戻ってしまっていました。

(上の時系列の図でいうと、③から②の地点に戻っていました。)

5. UNDOの多用はできるだけ控える

なにかと便利で強力なUNDOですが、多用するのはオススメしません

その理由は、一般的にUNDOポイントの作成は多くのメモリを消費するためです。

考えてみてください。UNDOポイントを置くということは、現在の状態を事細かに記録しておくことになります。

記録したり、戻すだけで重い処理になることは必然ですよね?

以上の理由から、絶対に必要な時以外はできるだけ使わないようにすることをオススメします。

6. まとめ

  • UNDOを作るときはApp.ActiveDocument.openTransaction()と、

    App.ActiveDocument.commitTransaction()を使用する。

  • UNDOポイントの作成は多くのメモリを消費する可能性が高いことが多いため、必要最小限で利用する。

7. 最後に

UNDOポイントの実装は自作プログラムを作成する際、必ず必要になります。

プログラムのテンプレートを作っている方は、あらかじめコードを組み込んでおいても良いかもしれませんね。

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

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

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

www.interested-or-not.com