本日のお題は『UNDOを実装する』です。
前回の記事でUNDO, REDOを実行する方法を紹介しました。
今回はUNDOを実行した際に『戻る位置(UNDOポイント)』を、プログラムから定義する方法を紹介したいと思います。
1. 環境
FreeCAD 0.18
2. 使用するAPI
下記2つのメソッドを使用します。
- App.ActiveDocument.openTransaction("文字列")
-
App.ActiveDocument.commitTransaction()
1つ目のメソッドでUNDOポイントの定義を開始し、その後、2つ目のメソッドを実行することでUNDOポイントを作成(確定)します。
3. 何のために使うのか
自作のプログラムを作っている方であれば、お気づきかもしれませんが、プログラムを実行した後、実行前の状態に戻す操作ができず、モデルを開き直したりしていませんか。
例えば下図のような時系列を想像してください。
この場合、図のUNDOポイント③の地点からUNDOを実行した場合、②の地点まで戻ってしまいます。
普通に考えれば、点線で書かれている自作プログラムを実行した地点まで戻りたいと思いますよね?
上記より、UNDOを的確な場所に配置するのはマクロプログラム開発において、とても重要なことなのです。
4. プログラムを書いてみよう
どうせなので今回は、以前紹介した『ベクトル確認用矢印ソリッド』のプログラムに対して、UNDOポイントを作成する処理を追加してみましょう。
# -*- 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プログラミングのトップページに飛びます。
よろしければご参照くださいませ。