class ArmPanel(BasePanel): def __init__(self, frame: wx.Frame, parent: wx.Notebook, tab_idx: int): super().__init__(frame, parent, tab_idx) # 剛体リスト self.avoidance_set_dict = {} # 剛体用ダイアログ self.avoidance_dialog = AvoidanceDialog(self.frame) avoidance_tooltip = "指定文字列名のボーン追従剛体と手首・指先との接触を回避します。\n選択ボタンから、変換先モデルの回避させたいボーン追従剛体を選択してください。\n" \ + "「頭接触回避」は頭を中心とした球体剛体を自動で計算します。" alignment_tooltip = "変換先モデルの手首位置が、作成元モデルの手首とほぼ同じ位置になるよう、手首位置を調整します。" # 同じグループなので、とりあえず宣言だけしておく self.arm_process_flg_avoidance = wx.CheckBox(self, wx.ID_ANY, u"", wx.DefaultPosition, wx.DefaultSize) self.arm_process_flg_avoidance.SetToolTip(avoidance_tooltip) self.arm_process_flg_avoidance.Bind(wx.EVT_CHECKBOX, self.set_output_vmd_path) self.arm_process_flg_alignment = wx.CheckBox(self, wx.ID_ANY, u"", wx.DefaultPosition, wx.DefaultSize) self.arm_process_flg_alignment.SetToolTip(alignment_tooltip) self.arm_process_flg_alignment.Bind(wx.EVT_CHECKBOX, self.set_output_vmd_path) self.description_txt = wx.StaticText(self, wx.ID_ANY, "腕を変換先モデルに合わせて調整する事ができます。\n「接触回避」と「位置合わせ」を合わせて実行できます。(接触回避→位置合わせの順に実行)" + \ "\n腕の動きが、元々のモーションから変わる事があります。いずれもそれなりに時間がかかります。", wx.DefaultPosition, wx.DefaultSize, 0) self.sizer.Add(self.description_txt, 0, wx.ALL, 5) self.static_line01 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) self.sizer.Add(self.static_line01, 0, wx.EXPAND | wx.ALL, 5) # 剛体接触回避 ---------------- self.avoidance_title_sizer = wx.BoxSizer(wx.HORIZONTAL) # 剛体接触回避タイトルラジオ self.avoidance_title_txt = wx.StaticText(self, wx.ID_ANY, u"接触回避", wx.DefaultPosition, wx.DefaultSize, 0) self.avoidance_title_txt.SetToolTip(avoidance_tooltip) self.avoidance_title_txt.Wrap(-1) self.avoidance_title_txt.SetFont( wx.Font(wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString)) self.avoidance_title_txt.Bind(wx.EVT_LEFT_DOWN, self.on_check_arm_process_avoidance) self.avoidance_title_sizer.Add(self.arm_process_flg_avoidance, 0, wx.ALL, 5) self.avoidance_title_sizer.Add(self.avoidance_title_txt, 0, wx.ALL, 5) self.sizer.Add(self.avoidance_title_sizer, 0, wx.ALL, 5) # 剛体接触回避説明文 self.avoidance_description_txt = wx.StaticText(self, wx.ID_ANY, avoidance_tooltip, wx.DefaultPosition, wx.DefaultSize, 0) self.sizer.Add(self.avoidance_description_txt, 0, wx.ALL, 5) self.avoidance_target_sizer = wx.BoxSizer(wx.HORIZONTAL) # 剛体名指定 self.avoidance_target_txt_ctrl = wx.TextCtrl( self, wx.ID_ANY, "", wx.DefaultPosition, (450, 80), wx.HSCROLL | wx.VSCROLL | wx.TE_MULTILINE | wx.TE_READONLY) self.avoidance_target_txt_ctrl.SetBackgroundColour( wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DLIGHT)) self.avoidance_target_txt_ctrl.Bind( wx.EVT_TEXT, self.on_check_arm_process_avoidance) self.avoidance_target_sizer.Add(self.avoidance_target_txt_ctrl, 1, wx.EXPAND | wx.ALL, 5) self.avoidance_target_btn_ctrl = wx.Button(self, wx.ID_ANY, u"剛体選択", wx.DefaultPosition, wx.DefaultSize, 0) self.avoidance_target_btn_ctrl.SetToolTip(u"変換先モデルにあるボーン追従剛体を選択できます") self.avoidance_target_btn_ctrl.Bind(wx.EVT_BUTTON, self.on_click_avoidance_target) self.avoidance_target_sizer.Add(self.avoidance_target_btn_ctrl, 0, wx.ALIGN_BOTTOM | wx.ALL, 5) self.sizer.Add(self.avoidance_target_sizer, 0, wx.ALL, 0) self.static_line03 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) self.sizer.Add(self.static_line03, 0, wx.EXPAND | wx.ALL, 5) # 手首位置合わせ -------------------- self.alignment_title_sizer = wx.BoxSizer(wx.HORIZONTAL) # 手首位置合わせタイトルラジオ self.alignment_title_txt = wx.StaticText(self, wx.ID_ANY, u"位置合わせ", wx.DefaultPosition, wx.DefaultSize, 0) self.alignment_title_txt.SetToolTip("両手を合わせたり、床に手をついたりするモーションを、変換先モデルの手首位置に合わせて調整します。\n" + \ "それぞれの距離を調整することで、位置合わせの適用範囲を調整することができます。") self.alignment_title_txt.Wrap(-1) self.alignment_title_txt.SetFont( wx.Font(wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString)) self.alignment_title_txt.Bind(wx.EVT_LEFT_DOWN, self.on_check_arm_process_alignment) self.alignment_title_sizer.Add(self.arm_process_flg_alignment, 0, wx.ALL, 5) self.alignment_title_sizer.Add(self.alignment_title_txt, 0, wx.ALL, 5) self.sizer.Add(self.alignment_title_sizer, 0, wx.ALL, 5) # 手首位置合わせ説明文 self.alignment_description_txt = wx.StaticText(self, wx.ID_ANY, alignment_tooltip, wx.DefaultPosition, wx.DefaultSize, 0) self.sizer.Add(self.alignment_description_txt, 0, wx.ALL, 5) # オプションサイザー self.alignment_option_sizer = wx.BoxSizer(wx.HORIZONTAL) # 指位置合わせ self.arm_alignment_finger_flg_ctrl = wx.CheckBox( self, wx.ID_ANY, u"指の位置で位置合わせを行う", wx.DefaultPosition, wx.DefaultSize, 0) self.arm_alignment_finger_flg_ctrl.SetToolTip(u"チェックを入れると、フィンガータットモーション等、指間の距離を基準に手首位置を調整できます。" \ + "複数人数モーションではOFFのままの方が綺麗になります。") self.arm_alignment_finger_flg_ctrl.Bind( wx.EVT_CHECKBOX, self.on_check_arm_process_alignment) self.alignment_option_sizer.Add(self.arm_alignment_finger_flg_ctrl, 0, wx.ALL, 5) # 床位置合わせ self.arm_alignment_floor_flg_ctrl = wx.CheckBox( self, wx.ID_ANY, u"床との位置合わせも一緒に行う", wx.DefaultPosition, wx.DefaultSize, 0) self.arm_alignment_floor_flg_ctrl.SetToolTip( u"チェックを入れると、手首が床に沈み込んだり浮いてたりする場合に、元モデルに合わせて手首の位置を調整できます。\nセンター位置も一緒に調整します。" ) self.arm_alignment_floor_flg_ctrl.Bind( wx.EVT_CHECKBOX, self.on_check_arm_process_alignment) self.alignment_option_sizer.Add(self.arm_alignment_floor_flg_ctrl, 0, wx.ALL, 5) self.sizer.Add(self.alignment_option_sizer, 0, wx.ALL, 5) # 手首位置スライダー self.alignment_distance_wrist_sizer = wx.BoxSizer(wx.HORIZONTAL) self.alignment_distance_wrist_txt = wx.StaticText( self, wx.ID_ANY, u"手首間の距離 ", wx.DefaultPosition, wx.DefaultSize, 0) self.alignment_distance_wrist_txt.SetToolTip(u"どのくらい手首が近付いた場合に、手首位置合わせを実行するか指定してください。\n値が小さいほど、手首が近付いた時だけ手首位置合わせを行います。\n距離の単位は、元モデルの手のひらの大きさです。" \ + "\nサイジング実行時、手首間の距離がメッセージ欄に出てますので、参考にしてください。\nスライダーを最大に設定すると、常に手首位置合わせを行います。(両手剣等に便利です)") self.alignment_distance_wrist_txt.Wrap(-1) self.alignment_distance_wrist_sizer.Add( self.alignment_distance_wrist_txt, 0, wx.ALL, 5) self.alignment_distance_wrist_label = wx.StaticText( self, wx.ID_ANY, u"(1.7)", wx.DefaultPosition, wx.DefaultSize, 0) self.alignment_distance_wrist_label.SetToolTip( u"現在指定されている手首間の距離です。元モデルの両手首位置がこの範囲内である場合、手首間の位置合わせを行います。") self.alignment_distance_wrist_label.Wrap(-1) self.alignment_distance_wrist_sizer.Add( self.alignment_distance_wrist_label, 0, wx.ALL, 5) self.alignment_distance_wrist_slider = FloatSliderCtrl( self, wx.ID_ANY, 1.7, 0, 10, 0.1, self.alignment_distance_wrist_label, wx.DefaultPosition, wx.DefaultSize, wx.SL_HORIZONTAL) self.alignment_distance_wrist_slider.Bind( wx.EVT_SCROLL_CHANGED, self.on_check_arm_process_alignment) self.alignment_distance_wrist_sizer.Add( self.alignment_distance_wrist_slider, 1, wx.ALL | wx.EXPAND, 5) self.sizer.Add(self.alignment_distance_wrist_sizer, 0, wx.ALL | wx.EXPAND, 5) # 指位置スライダー self.alignment_distance_finger_sizer = wx.BoxSizer(wx.HORIZONTAL) self.alignment_distance_finger_txt = wx.StaticText( self, wx.ID_ANY, u"指間の距離 ", wx.DefaultPosition, wx.DefaultSize, 0) self.alignment_distance_finger_txt.SetToolTip(u"どのくらい指が近付いた場合に、指位置合わせを実行するか指定してください。\n値が小さいほど、指が近付いた時だけ指位置合わせを行います。\n距離の単位は、元モデルの手のひらの大きさです。\n" \ + "\nサイジング実行時、指間の距離がメッセージ欄に出てますので、参考にしてください。\nスライダーを最大に設定すると、常に指位置合わせを行います。") self.alignment_distance_finger_txt.Wrap(-1) self.alignment_distance_finger_sizer.Add( self.alignment_distance_finger_txt, 0, wx.ALL, 5) self.alignment_distance_finger_label = wx.StaticText( self, wx.ID_ANY, u"(1.4)", wx.DefaultPosition, wx.DefaultSize, 0) self.alignment_distance_finger_label.SetToolTip( u"現在指定されている指間の距離です。元モデルの両指位置がこの範囲内である場合、指間の位置合わせを行います。") self.alignment_distance_finger_label.Wrap(-1) self.alignment_distance_finger_sizer.Add( self.alignment_distance_finger_label, 0, wx.ALL, 5) self.alignment_distance_finger_slider = FloatSliderCtrl( self, wx.ID_ANY, 1.4, 0, 10, 0.1, self.alignment_distance_finger_label, wx.DefaultPosition, wx.DefaultSize, wx.SL_HORIZONTAL) self.alignment_distance_finger_slider.Bind( wx.EVT_SCROLL_CHANGED, self.on_check_arm_process_alignment) self.alignment_distance_finger_sizer.Add( self.alignment_distance_finger_slider, 1, wx.ALL | wx.EXPAND, 5) self.sizer.Add(self.alignment_distance_finger_sizer, 0, wx.ALL | wx.EXPAND, 5) # 手首と床との位置スライダー self.alignment_distance_floor_sizer = wx.BoxSizer(wx.HORIZONTAL) self.alignment_distance_floor_txt = wx.StaticText( self, wx.ID_ANY, u"手首と床との距離", wx.DefaultPosition, wx.DefaultSize, 0) self.alignment_distance_floor_txt.SetToolTip(u"どのくらい手首と床が近付いた場合に、手首と床との位置合わせを実行するか指定してください。\n値が小さいほど、手首と床が近付いた時だけ位置合わせを行います。\n距離の単位は、元モデルの手のひらの大きさです。" \ + "\nサイジング実行時、手首と床との間の距離がメッセージ欄に出てますので、参考にしてください。\nスライダーを最大に設定すると、常に手首と床との位置合わせを行います。") self.alignment_distance_floor_txt.Wrap(-1) self.alignment_distance_floor_sizer.Add( self.alignment_distance_floor_txt, 0, wx.ALL, 5) self.alignment_distance_floor_label = wx.StaticText( self, wx.ID_ANY, u"(1.2)", wx.DefaultPosition, wx.DefaultSize, 0) self.alignment_distance_floor_label.SetToolTip( u"現在指定されている手首と床との間の距離です。元モデルの両手首と床との距離がこの範囲内である場合、手首と床との位置合わせを行います。" ) self.alignment_distance_floor_label.Wrap(-1) self.alignment_distance_floor_sizer.Add( self.alignment_distance_floor_label, 0, wx.ALL, 5) self.alignment_distance_floor_slider = FloatSliderCtrl( self, wx.ID_ANY, 1.2, 0, 10, 0.1, self.alignment_distance_floor_label, wx.DefaultPosition, wx.DefaultSize, wx.SL_HORIZONTAL) self.alignment_distance_floor_slider.Bind( wx.EVT_SCROLL_CHANGED, self.on_check_arm_process_alignment) self.alignment_distance_floor_sizer.Add( self.alignment_distance_floor_slider, 1, wx.ALL | wx.EXPAND, 5) self.sizer.Add(self.alignment_distance_floor_sizer, 0, wx.ALL | wx.EXPAND, 5) self.static_line04 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) self.sizer.Add(self.static_line04, 0, wx.EXPAND | wx.ALL, 5) # 腕チェックスキップ -------------------- self.arm_check_skip_sizer = wx.BoxSizer(wx.VERTICAL) self.arm_check_skip_flg_ctrl = wx.CheckBox(self, wx.ID_ANY, u"腕~手首のサイジング可能チェックをスキップする", wx.DefaultPosition, wx.DefaultSize, 0) self.arm_check_skip_flg_ctrl.SetToolTip( u"サイジング可能チェック(腕IKがあると不可)をスキップして、必ず処理を行うようにします。") self.arm_check_skip_sizer.Add(self.arm_check_skip_flg_ctrl, 0, wx.ALL, 5) self.arm_check_skip_description = wx.StaticText(self, wx.ID_ANY, u"腕サイジング可能チェック(腕IKがあると不可)をスキップして、必ず腕関係処理を行うようにします。\n" \ + "※サイジング結果がおかしくなる可能性がありますが、サポート対象外です。", \ wx.DefaultPosition, wx.DefaultSize, 0) self.arm_check_skip_description.Wrap(-1) self.arm_check_skip_sizer.Add(self.arm_check_skip_description, 0, wx.ALL, 5) self.sizer.Add(self.arm_check_skip_sizer, 0, wx.ALL | wx.EXPAND, 5) self.fit() def get_avoidance_target(self): target = {} if self.arm_process_flg_avoidance.GetValue() == 0: return target # 選択された剛体リストを入力欄に設定 for set_no, set_data in self.avoidance_set_dict.items(): if set_data.rep_choices: target[set_no - 1] = [ set_data.rep_avoidance_names[n] for n in set_data.rep_choices.GetSelections() ] return target def on_click_avoidance_target(self, event: wx.Event): if self.avoidance_dialog.ShowModal() == wx.ID_CANCEL: return # the user changed their mind # 一旦クリア self.avoidance_target_txt_ctrl.SetValue("") # 選択された剛体リストを入力欄に設定 for set_no, set_data in self.avoidance_set_dict.items(): # 選択肢ごとの表示文言 if set_data.rep_choices: selections = [ set_data.rep_choices.GetString(n) for n in set_data.rep_choices.GetSelections() ] self.avoidance_target_txt_ctrl.WriteText( "【No.{0}】{1}\n".format(set_no, ', '.join(selections))) self.arm_process_flg_avoidance.SetValue(1) self.avoidance_dialog.Hide() def initialize(self, event: wx.Event): if 1 in self.avoidance_set_dict: # ファイルタブ用接触回避のファイルセットがある場合 if self.frame.file_panel_ctrl.file_set.is_loaded(): # 既にある場合、ハッシュチェック if self.avoidance_set_dict[1].equal_hashdigest( self.frame.file_panel_ctrl.file_set): # 同じである場合、スルー pass else: # 違う場合、ファイルセット読み直し self.add_set(1, self.frame.file_panel_ctrl.file_set, replace=True) else: # ファイルタブが読み込み失敗している場合、読み直し(クリア) self.add_set(1, self.frame.file_panel_ctrl.file_set, replace=True) else: # 空から作る場合、ファイルタブのファイルセット参照 self.add_set(1, self.frame.file_panel_ctrl.file_set, replace=False) # multiはあるだけ調べる for multi_file_set_idx, multi_file_set in enumerate( self.frame.multi_panel_ctrl.file_set_list): set_no = multi_file_set_idx + 2 if set_no in self.avoidance_set_dict: # 複数タブ用接触回避のファイルセットがある場合 if multi_file_set.is_loaded(): # 既にある場合、ハッシュチェック if self.avoidance_set_dict[set_no].equal_hashdigest( multi_file_set): # 同じである場合、スルー pass else: # 違う場合、ファイルセット読み直し self.add_set(set_no, multi_file_set, replace=True) # 複数件ある場合、手首間の距離デフォルト値変更 self.alignment_distance_wrist_slider.SetValue(2.5) self.alignment_distance_wrist_label.SetLabel("(2.5)") else: # 複数タブが読み込み失敗している場合、読み直し(クリア) self.add_set(set_no, multi_file_set, replace=True) # 複数件ある場合、手首間の距離デフォルト値変更 self.alignment_distance_wrist_slider.SetValue(2.5) self.alignment_distance_wrist_label.SetLabel("(2.5)") else: # 空から作る場合、複数タブのファイルセット参照 self.add_set(set_no, multi_file_set, replace=False) # 複数件ある場合、手首間の距離デフォルト値変更 self.alignment_distance_wrist_slider.SetValue(2.5) self.alignment_distance_wrist_label.SetLabel("(2.5)") # 腕系不可モデル名リスト disable_arm_model_names = [] if self.frame.file_panel_ctrl.file_set.is_loaded(): if not self.frame.file_panel_ctrl.file_set.org_model_file_ctrl.data.can_arm_sizing: # 腕不可の場合、リスト追加 disable_arm_model_names.append("【No.1】作成元モデル: {0}".format( self.frame.file_panel_ctrl.file_set.org_model_file_ctrl. data.name)) if not self.frame.file_panel_ctrl.file_set.rep_model_file_ctrl.data.can_arm_sizing: # 腕不可の場合、リスト追加 disable_arm_model_names.append("【No.1】変換先モデル: {0}".format( self.frame.file_panel_ctrl.file_set.rep_model_file_ctrl. data.name)) for multi_file_set_idx, multi_file_set in enumerate( self.frame.multi_panel_ctrl.file_set_list): set_no = multi_file_set_idx + 2 if multi_file_set.is_loaded(): if not multi_file_set.org_model_file_ctrl.data.can_arm_sizing: # 腕不可の場合、リスト追加 disable_arm_model_names.append( "【No.{0}】作成元モデル: {1}".format( set_no, multi_file_set.org_model_file_ctrl.data.name)) if not multi_file_set.rep_model_file_ctrl.data.can_arm_sizing: # 腕不可の場合、リスト追加 disable_arm_model_names.append( "【No.{0}】変換先モデル: {1}".format( set_no, multi_file_set.rep_model_file_ctrl.data.name)) if len(disable_arm_model_names) > 0: # 腕不可モデルがいる場合、ダイアログ表示 with wx.MessageDialog(self, "下記モデルに「腕IK」に類する文字列が含まれているため、該当ファイルセットの腕系処理\n(腕スタンス補正・捩り分散・接触回避・位置合わせ)がこのままではスルーされます。\n" \ + "腕チェックスキップFLGをONにすると、強制的に腕系処理が実行されます。\n※ただし、結果がおかしくなってもサポート対象外となります。\n" \ + "腕チェックスキップFLGをONにしますか? \n\n{0}".format('\n'.join(disable_arm_model_names)), style=wx.YES_NO | wx.ICON_WARNING) as dialog: if dialog.ShowModal() == wx.ID_NO: # 腕系チェックスキップOFF self.arm_check_skip_flg_ctrl.SetValue(0) else: # 腕系チェックスキップON self.arm_check_skip_flg_ctrl.SetValue(1) event.Skip() def add_set(self, set_idx: int, file_set: SizingFileSet, replace: bool): new_avoidance_set = AvoidanceSet(self.frame, self, self.avoidance_dialog.scrolled_window, set_idx, file_set) if replace: # 置き換え self.avoidance_dialog.set_list_sizer.Hide( self.avoidance_set_dict[set_idx].set_sizer, recursive=True) self.avoidance_dialog.set_list_sizer.Replace( self.avoidance_set_dict[set_idx].set_sizer, new_avoidance_set.set_sizer, recursive=True) # 置き換えの場合、剛体リストクリア self.avoidance_target_txt_ctrl.SetValue("") else: # 新規追加 self.avoidance_dialog.set_list_sizer.Add( new_avoidance_set.set_sizer, 0, wx.EXPAND | wx.ALL, 5) self.avoidance_set_dict[set_idx] = new_avoidance_set # スクロールバーの表示のためにサイズ調整 self.avoidance_dialog.set_list_sizer.Layout() self.avoidance_dialog.set_list_sizer.FitInside( self.avoidance_dialog.scrolled_window) # VMD出力ファイルパス生成 def set_output_vmd_path(self, event, is_force=False): # 念のため出力ファイルパス自動生成(空の場合設定) self.frame.file_panel_ctrl.file_set.set_output_vmd_path(event) # multiのも出力ファイルパス自動生成(空の場合設定) for file_set in self.frame.multi_panel_ctrl.file_set_list: file_set.set_output_vmd_path(event) # 処理対象:接触回避ON def on_check_arm_process_avoidance(self, event: wx.Event): # ラジオボタンかチェックボックスイベントがTrueの場合、切り替え if isinstance(event.GetEventObject(), wx.StaticText): if self.arm_process_flg_avoidance.GetValue() == 0: self.arm_process_flg_avoidance.SetValue(1) else: self.arm_process_flg_avoidance.SetValue(0) # パス再生成 self.set_output_vmd_path(event) event.Skip() # 処理対象:手首位置合わせON def on_check_arm_process_alignment(self, event: wx.Event): # ラジオボタンかチェックボックスイベントがTrueの場合、切り替え if isinstance(event.GetEventObject(), wx.StaticText): if self.arm_process_flg_alignment.GetValue() == 0: self.arm_process_flg_alignment.SetValue(1) else: self.arm_process_flg_alignment.SetValue(0) else: if self.arm_alignment_finger_flg_ctrl.GetValue( ) == 1 or self.arm_alignment_floor_flg_ctrl.GetValue() == 1: self.arm_process_flg_alignment.SetValue(1) if self.arm_alignment_finger_flg_ctrl.GetValue() and len( self.frame.multi_panel_ctrl.file_set_list) > 0: self.frame.on_popup_finger_warning(event) # パス再生成 self.set_output_vmd_path(event) event.Skip()
class CameraPanel(BasePanel): def __init__(self, frame: wx.Frame, parent: wx.Notebook, tab_idx: int): super().__init__(frame, parent, tab_idx) self.header_panel = CameraHeaderPanel(self.frame, self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL) self.header_sizer = wx.BoxSizer(wx.VERTICAL) self.description_txt = wx.StaticText(self.header_panel, wx.ID_ANY, u"指定されたカメラモーションのサイジングを、ボーンモーションのサイジングと同時に行えます。\n" \ + "全長オフセットYは、カメラに映す変換先モデルの全長を調整するオフセット値を指定できます。", wx.DefaultPosition, wx.DefaultSize, 0) self.header_sizer.Add(self.description_txt, 0, wx.ALL, 5) self.static_line01 = wx.StaticLine(self.header_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) self.header_sizer.Add(self.static_line01, 0, wx.EXPAND | wx.ALL, 5) camera_only_flg_spacer_ctrl = wx.StaticText(self.header_panel, wx.ID_ANY, u" ", wx.DefaultPosition, wx.DefaultSize, 0) # カメラサイジングのみ実行 self.camera_only_flg_ctrl = wx.CheckBox(self.header_panel, wx.ID_ANY, u"カメラサイジングのみ実行", wx.DefaultPosition, wx.DefaultSize, 0) self.camera_only_flg_ctrl.SetToolTip( u"ボーンサイジング済みファイルを出力ファイルに指定した上でチェックを入れると、\nそのサイジング済みVMDを元にカメラサイジングを実行します。" ) self.camera_only_flg_ctrl.Bind(wx.EVT_CHECKBOX, self.set_output_vmd_path) # カメラVMDファイルコントロール self.camera_vmd_file_ctrl = HistoryFilePickerCtrl(self.frame, self.header_panel, u"カメラモーションVMD", u"カメラモーションVMDファイルを開く", ("vmd"), wx.FLP_DEFAULT_STYLE, \ u"調整したいカメラモーションのVMDパスを指定してください。\nD&Dでの指定、開くボタンからの指定、履歴からの選択ができます。", \ file_model_spacer=0, title_parts_ctrl=camera_only_flg_spacer_ctrl, title_parts2_ctrl=self.camera_only_flg_ctrl, file_histories_key="camera_vmd", \ is_change_output=True, is_aster=False, is_save=False, set_no=1) self.header_sizer.Add(self.camera_vmd_file_ctrl.sizer, 1, wx.EXPAND, 0) # 出力先VMDファイルコントロール self.output_camera_vmd_file_ctrl = BaseFilePickerCtrl(frame, self.header_panel, u"出力カメラVMD", u"出力カメラVMDファイルを開く", ("vmd"), wx.FLP_OVERWRITE_PROMPT | wx.FLP_SAVE | wx.FLP_USE_TEXTCTRL, \ u"調整結果のカメラVMD出力パスを指定してください。\nカメラVMDファイル名に基づいて自動生成されますが、任意のパスに変更することも可能です。", \ is_aster=False, is_save=True, set_no=1) self.header_sizer.Add(self.output_camera_vmd_file_ctrl.sizer, 1, wx.EXPAND, 0) # カメラ距離調整スライダー self.camera_length_sizer = wx.BoxSizer(wx.HORIZONTAL) self.camera_length_txt = wx.StaticText(self.header_panel, wx.ID_ANY, u"距離可動範囲", wx.DefaultPosition, wx.DefaultSize, 0) self.camera_length_txt.SetToolTip(u"ステージの大きさなどにより、カメラの距離の調整範囲を限定したい場合に\n" \ + "カメラの距離可動範囲を限定することができます。\n" \ + "可動範囲は手動で調整する事も可能です。") self.camera_length_txt.Wrap(-1) self.camera_length_sizer.Add(self.camera_length_txt, 0, wx.ALL, 5) self.camera_length_type_ctrl = wx.Choice( self.header_panel, id=wx.ID_ANY, choices=["距離制限強", "距離制限弱", "距離制限なし"]) self.camera_length_type_ctrl.SetSelection(2) self.camera_length_type_ctrl.Bind(wx.EVT_CHOICE, self.on_camera_length_type) self.camera_length_type_ctrl.SetToolTip(u"「距離制限強」 … 小さめのステージ用。距離可動範囲を厳しめに制限します。\n" \ + "「距離制限弱」 … 中くらいのステージ用。距離可動範囲を多少制限します。\n" \ + "「距離制限なし」 … 距離可動範囲を無制限とし、元モデルと同じ映り具合になるよう、最大限調整します。") self.camera_length_sizer.Add(self.camera_length_type_ctrl, 0, wx.ALL, 5) self.camera_length_label = wx.StaticText(self.header_panel, wx.ID_ANY, u"(5)", wx.DefaultPosition, wx.DefaultSize, 0) self.camera_length_label.SetToolTip(u"現在指定されているカメラ距離の可動範囲です。") self.camera_length_label.Wrap(-1) self.camera_length_sizer.Add(self.camera_length_label, 0, wx.ALL, 5) self.camera_length_slider = FloatSliderCtrl(self.header_panel, wx.ID_ANY, 5, 1, 5, 0.01, self.camera_length_label, wx.DefaultPosition, wx.DefaultSize, wx.SL_HORIZONTAL) self.camera_length_slider.Bind(wx.EVT_SCROLL_CHANGED, self.set_output_vmd_path) self.camera_length_sizer.Add(self.camera_length_slider, 1, wx.ALL | wx.EXPAND, 5) self.header_sizer.Add(self.camera_length_sizer, 0, wx.ALL | wx.EXPAND, 5) self.header_panel.SetSizer(self.header_sizer) self.header_panel.Layout() self.sizer.Add(self.header_panel, 0, wx.EXPAND | wx.ALL, 5) # カメラセット(key: ファイルセット番号, value: カメラセット) self.camera_set_dict = {} # Bulk用カメラセット self.bulk_camera_set_dict = {} # カメラセット用基本Sizer self.set_list_sizer = wx.BoxSizer(wx.VERTICAL) self.scrolled_window = CameraScrolledWindow(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, \ wx.FULL_REPAINT_ON_RESIZE | wx.VSCROLL | wx.ALWAYS_SHOW_SB) self.scrolled_window.SetScrollRate(5, 5) # スクロールバーの表示のためにサイズ調整 self.scrolled_window.SetSizer(self.set_list_sizer) self.scrolled_window.Layout() self.sizer.Add(self.scrolled_window, 1, wx.ALL | wx.EXPAND | wx.FIXED_MINSIZE, 5) self.sizer.Layout() self.fit() def on_camera_length_type(self, event): if self.camera_length_type_ctrl.GetSelection() == 0: self.camera_length_slider.SetValue(1.05) elif self.camera_length_type_ctrl.GetSelection() == 1: self.camera_length_slider.SetValue(1.3) else: self.camera_length_slider.SetValue(5) self.set_output_vmd_path(event) def set_output_vmd_path(self, event, is_force=False): # カメラ出力パスを強制的に変更する self.header_panel.set_output_vmd_path(event, True) # カメラタブ初期化処理 def initialize(self, event: wx.Event): self.bulk_camera_set_dict = {} if 1 not in self.camera_set_dict: # 空から作る場合、ファイルタブのファイルセット参照 self.add_set(1, self.frame.file_panel_ctrl.file_set) else: # ある場合、モデル名だけ入替 self.camera_set_dict[1].model_name_txt.SetLabel("{0} → {1}".format(\ self.frame.file_panel_ctrl.file_set.org_model_file_ctrl.file_model_ctrl.txt_ctrl.GetValue()[1:-1], \ self.frame.file_panel_ctrl.file_set.rep_model_file_ctrl.file_model_ctrl.txt_ctrl.GetValue()[1:-1])) # multiはあるだけ調べる for multi_file_set_idx, multi_file_set in enumerate( self.frame.multi_panel_ctrl.file_set_list): set_no = multi_file_set_idx + 2 if set_no not in self.camera_set_dict: # 空から作る場合、複数タブのファイルセット参照 self.add_set(set_no, multi_file_set) else: # ある場合、モデル名だけ入替 self.camera_set_dict[set_no].model_name_txt.SetLabel("{0} → {1}".format(\ multi_file_set.org_model_file_ctrl.file_model_ctrl.txt_ctrl.GetValue()[1:-1], \ multi_file_set.rep_model_file_ctrl.file_model_ctrl.txt_ctrl.GetValue()[1:-1])) def add_set(self, set_idx: int, file_set: SizingFileSet): new_camera_set = CameraSet(self.frame, self, self.scrolled_window, set_idx, file_set) self.set_list_sizer.Add(new_camera_set.set_sizer, 0, wx.EXPAND | wx.ALL, 5) self.camera_set_dict[set_idx] = new_camera_set # スクロールバーの表示のためにサイズ調整 self.set_list_sizer.Layout() self.set_list_sizer.FitInside(self.scrolled_window) # フォーム無効化 def disable(self): self.file_set.disable() # フォーム無効化 def enable(self): self.file_set.enable() def save(self): self.camera_vmd_file_ctrl.save()