C#ATIA

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

コンポーネント残し代をコピーする

アクセス数がグッと減る、PowerMillネタです。

少し前から一部のマクロが機能しなくなりました。原因がわからない上、
再現性が良くわからずサポートさんに相談したくても出来ない状況が続いていました。

先日、手動操作で再現出来たので相談した所、バグだとわかりました。
・・・わかった所で、解決しません。代替の方法を見つけ出しマクロ化し
フォーラムに投げてみました。
Re: Surface Defaults Cloning Macro - Autodesk Community

コンテキストメニューで呼び出したツールパスのコンポーネント残し代を、他の未計算
ツールパスにコピー(正しくはクローンでした)します。
これが出来ないと、非常に困っちゃうんです。

仮にバグが解決しても、関数一ヶ所だけ修正すれば終了です。


でも、まだ解決していないんです。
昨年、苦労して作成した確認用のマクロが正しい結果を返さないんです・・・。
デフォルト [コンポーネント/残り代] と異なる設定のツールパス名を取得4 - C#ATIA
こちらは直せる気がしない。UpDateを待つしか無さそう。

カレントビューの角度や生成スタイルの取得

「ビューの角度や生成スタイルの変更」について、御質問頂きました。

変更についてのサンプルコードは書きにくいため、カレントビュー情報を
幾つか表示するサンプルコードを作ってみました。

Sub CATMain()
    
    Dim msg As String
    Dim pi As Double: pi = 4 * Atn(1)
    
    'ドキュメント
    Dim dwDoc As DrawingDocument
    Set dwDoc = CATIA.ActiveDocument
    
    'カレントビュー : 名前の変更はnameプロパティに代入
    Dim actVi As DrawingView
    Set actVi = dwDoc.Sheets.ActiveSheet.views.ActiveView
    msg = "ビュー名 : " & actVi.Name
    
    '角度 : 変更はangleプロパティに代入(単位ラジアンで!)
    msg = msg & vbCrLf & _
        "角度 : " & Round(actVi.angle * (180 / pi), 3) & "deg"
    
    'スケール : 変更はscaleプロパティに代入
    msg = msg & vbCrLf & _
        "スケール : " & actVi.Scale
    
    'スタイル : 変更は、恐らくSetGPSNameメソッド
    Dim behv As DrawingViewGenerativeBehavior
    Set behv = actVi.GenerativeBehavior
    msg = msg & vbCrLf & _
        "スタイル(のファイル名) : " & behv.GetGPSName
    
    '参照している3Dドキュメント : 変更は、下記にサンプルコード有り
    'http://kantoku.hatenablog.com/entry/2018/12/19/183339
    msg = msg & vbCrLf & _
        "参照ドキュメント : " & behv.Document.Parent.FullName
    
    
    MsgBox msg, , "** カレントビュー情報 **"
    
End Sub

※例外処理を省いている為、3Dとリンクしていないビューで実行すると
エラーになると思います。
他にも、断面や詳細図のビューの場合、どのビューを元に作成されたか?
の取得も可能です。

実行するとこんな感じです。
f:id:kandennti:20190522190026p:plain

念のためですが、ビュー名の変更はNameプロパティに代入で良いのですが
f:id:kandennti:20190522190117p:plain
IDやSuffixが関係してくると、もうちょっとややこしいです。


自分の場合も、特定の客先向けで
・PartとDrawファイル名が一致しているか?
・ファイル名がルールに基づいた名称となっているか?
・生成スタイルが適切か?
等の細々したチェック(箇条書き出来る様な内容のもの)は、マクロで行っています。
(面倒なので)

カレントビュー内のテキスト・寸法全てを削除する

「Drawのカレントビュー内のテキストと寸法を削除したいが、
 最初の1個しか削除されない」
とのご相談を頂きました。

とりあえず、検索の現行選択でテキストと寸法を選択するマクロの記録をし、
不要そうな部分を削除しつつ、変数名を修正したものがこちらです。

Sub CATMain()
    Dim dwDoc As DrawingDocument
    Set dwDoc = CATIA.ActiveDocument
    
    Dim sel As selection
    Set sel = dwDoc.selection
    
    sel.Search "(CATDrwSearch.DrwDimension + CATDrwSearch.DrwText),sel"
End Sub

実際に欲しいのは事前選択ではなくカレントビューの為、カレントビューを
事前に選択させつつ、高輝度表示もOffにします。

Sub CATMain()
    Dim dwDoc As DrawingDocument
    Set dwDoc = CATIA.ActiveDocument
    
    Dim sel As selection
    Set sel = dwDoc.selection
    
    Dim actVi As DrawingView
    Set actVi = dwDoc.Sheets.ActiveSheet.views.ActiveView
    
    CATIA.HSOSynchronized = False
    
    With sel
        .Clear
        .Add actVi
        .Search "(CATDrwSearch.DrwDimension + CATDrwSearch.DrwText),sel"
    End With

    CATIA.HSOSynchronized = True
End Sub

恐らく上手く削除出来ない原因は、ここからループ等で一個づつ削除しているのでは
無いのかな? と思います。
僕は、Drawでの要素の削除はSelectionで選択しDelete(又はCut)するしか
方法がわかりません。(GSOはもっと高速な削除方法が有ります)

確認メッセージをつけた上、削除するように変更するとこんな感じです。

Sub CATMain()
    Dim dwDoc As DrawingDocument
    Set dwDoc = CATIA.ActiveDocument
    
    Dim sel As selection
    Set sel = dwDoc.selection
    
    Dim actVi As DrawingView
    Set actVi = dwDoc.Sheets.ActiveSheet.views.ActiveView
    
    CATIA.HSOSynchronized = False
    
    '検索
    With sel
        .Clear
        .Add actVi
        .Search "(CATDrwSearch.DrwDimension + CATDrwSearch.DrwText),sel"
    End With
    
    Dim delCount As Long
    delCount = sel.Count2
    
    Dim msg As String
    
    '削除要素無し
    If delCount < 1 Then
        msg = "ビュー[" & actVi.Name & "]内に削除要素が有りません!"
        MsgBox msg, vbInformation
        GoTo fin
    End If
    
    '確認
    msg = "ビュー[" & actVi.Name & "]内の" & vbCrLf & _
        "テキスト・寸法 " & delCount & "個 全てを削除します" & vbCrLf & _
        "宜しいですか?"
    
    If MsgBox(msg, vbYesNo + vbQuestion) = vbNo Then
        GoTo fin
    End If
    
    '削除
     sel.Delete '←ここ 検索で選択したもの全てを削除
fin:
    CATIA.HSOSynchronized = True
End Sub

どうでしょうか?

点を通って平行な平面作成

CATIAだと普通に「点を通って平行」な平面は作成出来るのですが、
Fusion360は出来ないんですよね。
f:id:kandennti:20190521122333p:plain
そんなに難しいものでも無さそうに感じるのですが・・・。

こちらに質問があったので、サンプルスプリクトを作ってみました。
Create Sketch with Point and Vector - Autodesk Community

ノンパラメトリックじゃないと作成出来ないんですよ。
と言う事は、システムそのものにそのような観念が無いんですね。
需要が少ない機能なのかな?

指定した要素を新たなPartにコピペして保存

久々のCATIAのマクロです。

アクティブなPartファイル上で指定した要素を、新たなPartに ”結果として” で
コピペし保存します。

'vba NewPart_CopyAndPasteResult  using-'KCL0.0.13'  by Kantoku
'指定した要素を新たなPartファイルに"結果として"でコピペする

Option Explicit

Private Const FOOTER = "_copy"

Sub CATMain()

    'ドキュメントのチェック
    If Not CanExecute("PartDocument") Then Exit Sub
    
    '元パス
    Dim docPath As String
    docPath = CATIA.ActiveDocument.FullName
    
    'コピー
    Dim msg As String
    msg = "新たなPartにコピーする要素を選択してください / ESC-キャンセル"
    
    Call SelectItemsCopy(msg, Array("AnyObject"))
    
    'ペースト
    Dim docs As Documents
    Set docs = CATIA.Documents
    
    Dim newDoc As PartDocument
    Set newDoc = docs.Add("Part")
    
    Call SelectItems(newDoc)
    CATIA.RefreshDisplay = True
    
    '保存
    Dim newPath As String
    newPath = GetNewPath(docPath)
    
    Call newDoc.SaveAs(newPath)
    
    MsgBox "done"
    
End Sub

'ペーストパス
Private Function GetNewPath( _
    ByVal path As String) As String
    
    Dim tmp As Variant
    tmp = KCL.SplitPathName(path)
    tmp(1) = tmp(1) & FOOTER
    
    GetNewPath = KCL.GetNewName(KCL.JoinPathName(tmp))
End Function

'ペースト
Private Sub SelectItems( _
    ByVal newDoc As PartDocument)
    
    newDoc.Activate
    
    Dim sel As Selection
    Set sel = newDoc.Selection
    
    CATIA.HSOSynchronized = False
    
    With sel
        .Clear
        .Add newDoc.part
        .PasteSpecial "CATPrtResultWithOutLink"
        .Clear
    End With
    
    CATIA.HSOSynchronized = True
    
End Sub

'コピー
Private Sub SelectItemsCopy( _
    ByVal msg As String, _
    ByVal filter As Variant)
    
    Dim sel As Variant
    Set sel = CATIA.ActiveDocument.Selection
    
    sel.Clear
    Select Case sel.SelectElement3(filter, _
                                   msg, _
                                   True, _
                                   CATMultiSelTriggWhenUserValidatesSelection, _
                                   False)
        Case "Cancel", "Undo", "Redo"
            End
    End Select
    
    If sel.count < 1 Then End
    
    sel.Copy
    sel.Clear
End Sub

特に何て事の無い内容で、単に加工のためのPowerMill用にエクスポートする為です。
(ある意味、履歴無しのPartファイルを作っているような感じです)

元のPartファイルと同一フォルダに、元のファイル名 + "_copy" の新たなファイルを
作成します。

PowerMill2020

PowerMill2020がリリースされました。
日本語Helpが未だの為、英語版がこちら
Help

2019が大幅なUpDateだったのですが、2020は小幅な印象です。
・スピードの向上
 マルチコアCPU活用との事ですが、2つ起動して比べてみないと・・・
 と思ってます。
 でも、開発側は大変だっただろうな とは感じます。

・マルチスレッドリードとリンク
 リンクの再計算もマルチスレッド処理になったようです。
 こちらも結構時間かかりますので、本当なら助かります。

・上り坂の急なコーナーの仕上げ
 数年前にサポートさんに「ペンシルで必ず駆け上がるようにツールパス
 を作成するオプションが欲しいです」と伝えた事があったのですが、
 それとはちょっと違うようです。

 事前にウェビナーでこの機能の紹介は見ていたのですが、実際試してみると
 やっぱりちょっと違う印象です。
 常に駆け上がってくれないと、食い込みor工具破損 しちゃうので、
 同じかな・・・。

・モデルフィレット
 加工時間短縮の為に行うスムージングの機能で効果があるようですが、
 2019までは不具合が有ったんですね。

 動画の2:20頃の操作でメッシュを表示しているのですが、これは
 隠しコマンドです。以前、表示させる方法がサポートさんに問い合わせたら
 教えてもらいました。
 「ビュー」タブ-「外観」でダイアログを表示させた状態で、
 「Ctrl」+「Tab」でダイアログの表示が動画の様に切り替わります。
 元々開発側でメッシュ状態を確認する為の機能だったのだろうと思います。


正直な所、新機能追加より既存の機能の処理速度Upとバグ修正がユーザーに
一番喜ばれる と言う事実はかわいそう。

迷路を作る3

こちらの続きです。
迷路を作る2 - C#ATIA

最近知ったTemporaryBRepManagerのパワーを感じたくて、
修正してみました。

#FusionAPI_python test_Maze ver0.0.3
#Author-kantoku
#Description-迷路ボディの作成

'''
The MIT License (MIT)

Copyright (c) 2014 BoppreH

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''

import adsk.core, adsk.fusion, traceback
import os, sys, time
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

#thx-boppreh
#https://github.com/boppreh/maze
import maze

unit = 2.0

def run(context):
    row_num = 0
    column_num = 0
    
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        #ユーザー入力
        row_num, column_num = GetMazeSize(ui)
        if row_num == None:
            return
        
        #doc
        NewDoc(app)
        root = app.activeProduct.rootComponent
        
        des = root.parentDesign
        des.designType = adsk.fusion.DesignTypes.DirectDesignType
        bodies = root.bRepBodies
        
        #拡張
        maze.Maze.exp = expWallMap
        
        #time
        t = time.time()
        
        #迷路取得
        mz = maze.Maze.generate(row_num,column_num)
        wall = mz.exp()
        print('迷路取得:{:.2f}s'.format(time.time()- t))
        
        #cog
        halfUnit = unit*0.5
        cogs = []
        for j,y in enumerate(wall):
            for i,x in enumerate(y):
                if x:
                    cogs.append([i*unit + halfUnit, j*unit + halfUnit, halfUnit])
        print('cog:{:.2f}s'.format(time.time()- t))
                    
        #maze3D
        InitBoxs(cogs,bodies)
        print('box:{:.2f}s'.format(time.time()- t))
        
        #ParametricDesign
        des.designType = adsk.fusion.DesignTypes.ParametricDesignType
        
        #finish
        ui.messageBox('done\ntime:{:.2f}s'.format(time.time()- t))

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

def GetMazeSize(ui):
    msg = '作成する迷路のサイズを入力してください。(例: 10,10)'
    txt, cancelled = ui.inputBox(msg, 'Maze', '10,10')
    if cancelled:
        return None, None
    
    ary = txt.split(',')
    if len(ary) != 2:
        return None, None
    
    if not ary[0].isdigit() or not ary[1].isdigit():
        return None, None
    
    return int(ary[0]), int(ary[1])
    
def NewDoc(app):
    return app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)

def InitBoxs(cogs, bodies):
    tmpBrep = adsk.fusion.TemporaryBRepManager.get()    
    
    pnt3D = adsk.core.Point3D
    l_Dir = adsk.core.Vector3D.create(1.0, 0.0, 0.0)
    w_Dir = adsk.core.Vector3D.create(0.0, 1.0, 0.0)
    obb3D = adsk.core.OrientedBoundingBox3D
    
    #OrientedBoundingBox3D
    obbs = [obb3D.create(pnt3D.create(x,y,z),l_Dir,w_Dir,unit,unit,unit) 
        for (x,y,z) in cogs]
            
    #TemporaryBox
    boxs = [tmpBrep.createBox(obb) for obb in obbs]

    union = adsk.fusion.BooleanTypes.UnionBooleanType
    maze3d = boxs[0]
    
    #Union
    [tmpBrep.booleanOperation(maze3d, box, union) for box in boxs]
    
    #Add
    bodies.add(maze3d)
    
    return

#maze.Maze
def expWallMap(self):
    return [convIsWallLst(v) for v in self._to_str_matrix()[::-1]]

def convIsWallLst(lst):
    return [True if v == 'O' else False for v in lst]

自宅の非力なPCで試しましたが、10x10の設定で

Ver0.0.2 : 20.98秒
Ver0.0.3 : 2.90秒

速い! コードも短くなりました。

Ver0.0.2では時間がかかり過ぎそうなので試しませんが、

30x30 : 41.98秒
50x50 : 223.96秒

まぁ そこそこのスピードです。

f:id:kandennti:20190515002135p:plain

さらに驚くことに、あなたにも僕にも、全く役に立たない・・・。