C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA(最近はPMillマクロとFusion360APIが多い)

再び、再インストール

再び、デバッグが出来ない状態に陥る・・・。
これと同じ状況。
socket.timeout: timed out - Autodesk Community

・Win10 Pro
Fusion360 Ver2.0.8560
VSCode Ver1.46.1
・MsPythpn VerVer2020.6.90262

結局、どちらが悪いのか不明のまま、Fusion360VSCode共に
完全なアンインストール&再インストール
Fusion360からVSCodeが起動しなくなった時の対処方法 - C#ATIA
イロイロと吹っ飛ぶので再設定が面倒・・・。

こちらの記載でアカウントクリアされると記載しましたが、
こちらのサイトからアカウントにログインし
Autodesk
Fusion360のインストールファイルをDLすればライセンスを
維持出来ます。


ちょっと余談ですが、職場と自宅で同一のスクリプト・アドインを
利用出来るようにしたいため自作のものは全て、MS社のOneDriveに
入れています。
先日「キャッシュデータをクリア」したのですが、その際デフォルト
フォルダ以外のスクリプト・アドインが全て消えてしまします。
(ファイル自体が削除されるのではなく、再取り込みが必要となります)
・・・面倒。


先日の大型Updateからだったのかなぁ。

parameters.itemByName

少し前からFusion360APIフォーラムでは、CAMのAPIの対応に対しての
不満のレスが幾つか目につきます。

こちらのHelpのWath'sNew(APIはちょっと前からUpdate 無しです)を見ても
Fusion 360 Help
・・・時間が経ったら変わっちゃうので画像も残しておきますが
f:id:kandennti:20200624234315p:plain
一番上の「executeTextCommand」以外は全てCAM関係です。
中の人が頻繁に「CAMのAPIは積極的に取り組んでいる」と言う記述は
決して嘘じゃないんです。にも関わらず、不満のレスが連続的に出てきます。

原因の一つがWath'sNewに記載され新たに追加されたオブジェクトのHelpが、
上手くリンクされていない事です。

もう一つがプロパティがObjectCollectionになっているものが多い事です。
ObjectCollectionはコレクション(リスト)の為、中身がはっきりしないんです。

最後にサンプルコードが無い事です。
これ、やっと中の人が今日フォーラムに記載しました。
Solved: Re: Idea: complete the CAM api, or at least advance it some since 2016. - Autodesk Community
SetupやOperation(ツールパス)のparametersプロパティが
一番収穫有りそうだとは感じてましたが、サンプル無いと
わからないですよ、これは。

ロフトフューチャーを編集する

こちらのトピにレスが付かなかったので挑戦してみました。
How to edit a loft by API - Autodesk Community


ロフトフューチャーを修正したいと言う内容です。多分。
既にあるデータを修正することは今までやったことが無かったので
色々と苦労しました。

あちらにも画像を載せましたが、こんなデータです。
f:id:kandennti:20200619190157p:plain
3個のスケッチに円を描き、一番下と一番上でロフトを作っています。
そこに中間のスケッチの円を入れる処理で考えました。
このロフトを修正する作業はGUIでも結構面倒ですよね?

ロフトが成立するプロファイルの順番だとか、成立するプロファイルとか
ロフトより前に作ってあるスケッチだとか、諸々の条件を出したら
キリが無いので、その辺はクリアしている事にしておいてください。

最初に戸惑ったのがタイムラインです。
f:id:kandennti:20200619190209p:plain
この位置(マーカーポジションと呼ぶようです)でロフトを修正したら
駄目なんですね。
f:id:kandennti:20200619190222p:plain
この位置なら良いみたいです。過去は変えちゃいけないみたいです。
未来はいくらでも変更出来る!
未来は俺が作る!!
俺の後ろに道が出来る!!!
って事なんですね。(スケッチは過去のものも変更出来ます・・・)


続いてるロフトのセクションの修正ですが、ここもつっかえました。
質問者さんも "deleteMe(削除)は出来る" って記載しています。
確かに出来るっぽいのですが、上記のサンプルでは出来ませんでした。
理由は簡単です。2個のセクションでロフトを作っているので、
1個削除するとロフトとして成立しない為、エラーとなってしまします。

最初は全てセクションをクリアし、望んでいるセクションの順番で
再度追加すれば良いかな? と思っていたのですが、作戦失敗です。


続いて、こちらのメソッドに気が付きました。
Fusion 360 Help
リオーダーでセクションの順番を変更できそうです。
とりあえず、中間にしたいセクションを追加(一番最後)して、
reorderメソッドで順番変えれば良さそうだな と。

ところが、中間にしたいセクションを追加した時点でエラー。
当然、順番的にNGな事はわかっていたのですが・・・。

CATIAのGSDの接合の場合は、HybridShapeFactoryのaddNew~で
2つのReferenceを引数にする必要があるのですが、その後1個削除しても
エラーにならないんですよね。最終的に2個以上あれば良いので
途中で条件を満たしていなくても大丈夫なんです。
Fusion360は即実行になってしまうのでかなり勝手が違います。

冷静に考えると、ロフトのセクションの順番変えて大丈夫な場面は
ほぼ無いと思うのですがどうでしょ?reorderメソッドは存在している
意味がほぼ無いような気がしています。


この時点でほぼ絶望的になり、あのトピは見なかったことにしようかな?
とすら思いましたよ。
ダミーのセクションを作成しエラーを回避しようとも考えましたが
・2個以上のセクションを維持する
・追加出来るのは最後のみ
をどうしてもクリアするダミーセクションを思い付きません。


ところがよく見ると、LoftSection.entityプロパティはread/writeプロパティ
じゃないですか!
Fusion 360 Help

セクションを足し引きするのではなく、セクションが持っているエンティティを
入れ替えるだけで済むじゃない!!


と言うわけであのコードとなりました。
CATIAとは勝手が違うんですね。

円すい上の2点の最短距離をAPIで2

こちらの続きです。
円すい上の2点の最短距離をAPIで1 - C#ATIA

完成しました。
解決済み: Re: 円すい上の2点の最短距離 - Autodesk Community

#Fusion360API Python script
#Author-kantoku
#Description-円錐上の2点の最短距離

import adsk.core, adsk.fusion, traceback
import math

_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)

# 1ステップの角度(deg)
STEP_ANG = 5

def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface
        des  :adsk.fusion.Design = _app.activeProduct
        root :adsk.fusion.Component = des.rootComponent

        # 円錐
        cone :adsk.fusion.BRepFace = root.bRepBodies.item(0).faces.item(1)

        # 展開図スケッチ
        sktDevelop :adsk.fusion.Sketch = root.sketches.itemByName('展開図')

        dims :adsk.fusion.SketchDimensions = sktDevelop.sketchDimensions
        dimAng :adsk.fusion.SketchDimension = getDimensionByName(dims, 'd13')
        dimTgt :adsk.fusion.SketchDimension = getDimensionByName(dims, 'd14')
        dimTmp :adsk.fusion.SketchDimension = getDimensionByName(dims, 'd11')

        # 作業スケッチ
        sktWork :adsk.fusion.Sketch = root.sketches.itemByName('作業')

        dims = sktWork.sketchDimensions
        dimPrt :adsk.fusion.SketchDimension = getDimensionByName(dims, 'd8')
        pntSkt :adsk.fusion.SketchPoint = sktWork.sketchPoints.item(4)

        # カメラ
        vp :adsk.core.Viewport = _app.activeViewport
        cam :adsk.core.Camera = vp.camera
        viewLng = cam.eye.vectorTo(cam.target).length

        # 結果スケッチ
        sktRes :adsk.fusion.Sketch = root.sketches.add(root.xYConstructionPlane)

        # 円錐上に点作成
        pntRes = adsk.fusion.SketchPoint.cast(None)
        for v in range(0,120 + STEP_ANG,STEP_ANG):
            # 展開スケッチ更新
            dimAng.parameter.value = math.radians(v)
            dimTmp.isDriving = False
            dimTgt.isDriving = True
            dimTgt.isDriving = False
            dimTmp.isDriving = True

            # 作業スケッチ更新
            dimPrt.parameter.value = dimTgt.parameter.value

            # 結果スケッチに取り込み
            includes = sktRes.include(pntSkt)
            pntRes :adsk.fusion.SketchPoint = includes.item(0)
            pntRes.isReference = False

            # 画面更新
            updateCam(cone, pntRes.geometry, viewLng)

            # 画面が固まるのを防ぐ
            adsk.doEvents()

        # 曲線作成
        pnts = adsk.core.ObjectCollection.create()
        [pnts.add(p) for p in sktRes.sketchPoints]
        pnts.removeByIndex(0)
        sktRes.sketchCurves.sketchFittedSplines.add(pnts)

        # 邪魔な点非表示
        sktRes.arePointsShown = False

    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

# カメラの更新
def updateCam(
    brep :adsk.fusion.BRepFace,
    tgt :adsk.core.Point3D,
    viLng :float):

    vec :adsk.core.Vector3D = getViewVec(brep, tgt)
    vec.scaleBy(viLng)

    eye :adsk.core.Point3D = tgt.copy()
    eye.translateBy(vec)

    vp :adsk.core.Viewport = _app.activeViewport
    cam :adsk.core.Camera = vp.camera

    cam.eye = eye
    cam.target = tgt
    cam.upVector = adsk.core.Vector3D.create(0, 0, 1)
    vp.camera = cam

    _app.activeViewport.refresh()

# サーフェス上の点位置の法線取得
def getViewVec(
    brep :adsk.fusion.BRepFace,
    pnt :adsk.core.Point3D) -> adsk.core.Vector3D:

    eva :adsk.core.SurfaceEvaluator = brep.evaluator
    vec = adsk.core.Vector3D.cast(None)
    _,vec = eva.getNormalAtPoint(pnt)
    vec.normalize()

    return vec

# モデリングパラメータ名から寸法取得
def getDimensionByName(
    dims :adsk.fusion.SketchDimensions,
    name :str) -> adsk.fusion.SketchDimension:

    lst =[d for d in dims if d.parameter.name == name]
    if len(lst) < 1:
        return None
    
    return adsk.fusion.SketchDimension.cast(lst[0])

全く使いまわしのきかないものです・・・。

普段はループ内で複数の処理するの嫌なのですが、動画にしたかったので
あえて遅くなるようにしています。
画面も一緒に追いかけるようにしたのですが、

    cam.upVector = adsk.core.Vector3D.create(0, 0, 1)

最初にこの処理を入れ忘れ、結構酔いそうになりました。

円すい上の2点の最短距離をAPIで1

こちらの問題、他人にやらせてばかりで申し訳ないので、
僕っぽさを出すためにスクリプトで挑戦したいと考えてます。
解決済み: 円すい上の2点の最短距離 - Autodesk Community

スピードだけ求めたら、座標値を計算して曲線を求めた方が間違いなく
早いのですが、もうちょっとGUIの考え方に近い方法にしたい気がしてます。

作戦的にはこんな感じです。
こちらの展開図なのですが
f:id:kandennti:20200619094905p:plain
緑部分の角度を0~120°まで変化させ、赤部分の長さを取得します。
この長さは、三次元の状態の頂点から距離です。
f:id:kandennti:20200619094918p:plain
最終的にはこの方法で取得した大量の点からスプラインを作成すればOKな
ハズです。


展開図の赤部分は非駆動寸法なのです。これFusion360は式とかで
利用する事が出来ないんですよね。かなり不便です。
f:id:kandennti:20200619094932p:plain
でもAPIでは数値を取得出来ると言う事を僕は知っていました。
その為、こんな感じのものを作成しました。

#Fusion360API Python script
import adsk.core, adsk.fusion, traceback

_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)

def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface
        des  :adsk.fusion.Design = _app.activeProduct
        root :adsk.fusion.Component = des.rootComponent

        skt :adsk.fusion.Sketch = root.sketches.item(0)

        dims :adsk.fusion.SketchDimensions = skt.sketchDimensions
        dimAng :adsk.fusion.SketchDimension = dims.item(6)
        dimTgt :adsk.fusion.SketchDimension = dims.item(5)
        
        for v in range(10):
            dimAng.parameter.value = math.radians(v)
            print('{} : {}'.format(
                dimAng.parameter.expression, 
                dimTgt.parameter.expression))

    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

各".item(XX)"のインデックス値は事前に調べているため、あまり利用価値のない
ものとなってます。すいません。

内容的には最初の作戦通り、10回ほど角度を変化させて長さを取得しプリントで
垂れ流しているだけです。
結果はこんな感じです。

0.000 ° : 19.6577201 mm
1.000 ° : 19.6577201 mm
2.000 ° : 19.6577201 mm
3.000 ° : 19.6577201 mm
4.000 ° : 19.6577201 mm
5.000 ° : 19.6577201 mm
6.000 ° : 19.6577201 mm
7.000 ° : 19.6577201 mm
8.000 ° : 19.6577201 mm
9.000 ° : 19.6577201 mm

ん! 角度変えても長さが変わってない。
GUIの操作(手動)では非駆動寸法は反応しているので、画面上をUpdate
してくれそうな

_app.activeViewport.refresh()

adsk.doEvents()

とか入れるのですが、どうしても長さが変化してくれない。
かなり悩みましたが、非駆動寸法はGUIの扱いと異なるようです。


仕方が無いので、GUIで偶に行う方法を取り込むことに。
f:id:kandennti:20200619094951p:plain
赤部分を駆動に切り替えればOKなのですが、過拘束となるためNGです。
その為、過拘束を避ける方法を作ります。
・角度(緑)を変更
・過拘束回避用に一か所(オレンジ)を非駆動に変更
・長さ(赤)を駆動に変更
・長さを非駆動に変更
・回避用を駆動に変更
と言う泥臭い方法を1サイクルとしました。

#Fusion360API Python script
import adsk.core, adsk.fusion, traceback
import math

_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)

def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface
        des  :adsk.fusion.Design = _app.activeProduct
        root :adsk.fusion.Component = des.rootComponent

        skt :adsk.fusion.Sketch = root.sketches.item(0)

        dims :adsk.fusion.SketchDimensions = skt.sketchDimensions
        dimAng :adsk.fusion.SketchDimension = dims.item(6)
        dimTgt :adsk.fusion.SketchDimension = dims.item(5)
        dimTmp :adsk.fusion.SketchDimension = dims.item(2)

        _app.activeViewport.refresh()        
        for v in range(10):
            dimAng.parameter.value = math.radians(v)
            dimTmp.isDriving = False
            dimTgt.isDriving = True
            dimTgt.isDriving = False
            dimTmp.isDriving = True

            print('{} : {}'.format(
                dimAng.parameter.expression, 
                dimTgt.parameter.expression))

    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

実行した結果は

0.000 ° : 30.000 mm
1.000 ° : 29.4117648 mm
2.000 ° : 28.8547744 mm
3.000 ° : 28.3269564 mm
4.000 ° : 27.8264254 mm
5.000 ° : 27.3514627 mm
6.000 ° : 26.9004985 mm
7.000 ° : 26.4720968 mm
8.000 ° : 26.0649413 mm
9.000 ° : 25.6778239 mm

無事、長さも変わりました。
まだ始まったばかり・・・。

Fusion Team ウェビナー

ウェビナーって言わないのかな?日本では。

Fusion Team ウェビナーの動画がUpされていました。
https://www.youtube.com/watch?v=zo-PaGa030Q&feature=youtu.be

これ興味があって申し込んではいたものの、時間が合わずに参加できませんでした。
まぁ申し込んだ時点で、時間的には無理だろうなぁとは感じていたのですが。

比較的、他のものは短期間でUpされていたのですが、見たいと思っていた
これだけがナカナカUpされなかったので。

今は時間が無いので、後でじっくりお勉強させてもらいます。