Esempio n. 1
0
    def save(self):
        # 履歴保持
        self.bulk_csv_file_ctrl.save()

        # JSON出力
        MFileUtils.save_history(self.frame.mydir_path,
                                self.frame.file_hitories)
Esempio n. 2
0
    def on_convert_smooth(self, event: wx.Event):
        # フォーム無効化
        self.disable()
        # タブ固定
        self.fix_tab()
        # コンソールクリア
        self.console_ctrl.Clear()
        # 出力先をスムージングパネルのコンソールに変更
        sys.stdout = self.console_ctrl

        wx.GetApp().Yield()

        self.smooth_vmd_file_ctrl.save()
        self.smooth_model_file_ctrl.save()

        # JSON出力
        MFileUtils.save_history(self.frame.mydir_path,
                                self.frame.file_hitories)

        self.elapsed_time = 0
        result = True
        result = self.smooth_vmd_file_ctrl.is_valid(
        ) and self.smooth_model_file_ctrl.is_valid() and result

        if not result:
            # 終了音
            self.frame.sound_finish()
            # タブ移動可
            self.release_tab()
            # フォーム有効化
            self.enable()
            # 出力先をデフォルトに戻す
            sys.stdout = self.frame.file_panel_ctrl.console_ctrl

            return result

        # スムージング変換開始
        if self.convert_smooth_worker:
            logger.error("まだ処理が実行中です。終了してから再度実行してください。",
                         decoration=MLogger.DECORATION_BOX)
        else:
            # 別スレッドで実行
            self.convert_smooth_worker = SmoothWorkerThread(
                self.frame, SmoothThreadEvent, self.frame.is_saving)
            self.convert_smooth_worker.start()

        return result

        event.Skip()
    def on_pick_file(self, event):

        if len(self.file_ctrl.GetPath()) == 0 and self.frame.file_hitories and self.file_histories_key in self.frame.file_hitories and len(self.frame.file_hitories[self.file_histories_key]) > 0:
            # パスが未指定である場合、直近のパスを設定してひらく
            self.file_ctrl.SetInitialDirectory(MFileUtils.get_dir_path(self.frame.file_hitories[self.file_histories_key][0]))

        event.Skip()
Esempio n. 4
0
    def parse(cls, version_name: str):
        parser = argparse.ArgumentParser()
        parser.add_argument('--motion_path',
                            dest='motion_path',
                            help='input vmd',
                            type=str)
        parser.add_argument('--model_path',
                            dest='model_path',
                            help='model_path',
                            type=str)
        parser.add_argument('--loop_cnt',
                            dest='loop_cnt',
                            help='loop_cnt',
                            type=int)
        parser.add_argument('--interpolation',
                            dest='interpolation',
                            help='interpolation',
                            type=int)
        parser.add_argument("--verbose", type=int, default=20)

        args = parser.parse_args()

        # ログディレクトリ作成
        os.makedirs("log", exist_ok=True)

        MLogger.initialize(level=args.verbose, is_file=True)

        try:
            motion = VmdReader(args.motion_path).read_data()
            model = PmxReader(args.model_path).read_data()

            # 出力ファイルパス
            output_vmd_path = MFileUtils.get_output_smooth_vmd_path(
                motion.path, model.path, "", args.interpolation, args.loop_cnt,
                True)

            options = MSmoothOptions(\
                version_name=version_name, \
                logging_level=args.verbose, \
                motion=motion, \
                model=model, \
                output_path=output_vmd_path, \
                loop_cnt=args.loop_cnt, \
                interpolation=args.interpolation, \
                monitor=sys.stdout, \
                is_file=True, \
                outout_datetime=logger.outout_datetime, \
                max_workers=1)

            return options
        except SizingException as se:
            logger.error("スムージング処理が処理できないデータで終了しました。\n\n%s",
                         se.message,
                         decoration=MLogger.DECORATION_BOX)
        except Exception as e:
            logger.critical("スムージング処理が意図せぬエラーで終了しました。",
                            e,
                            decoration=MLogger.DECORATION_BOX)
    def set_output_vmd_path(self, event, is_force=False):
        output_leg_fk2ik_vmd_path = MFileUtils.get_output_leg_fk2ik_vmd_path(
            self.leg_fk2ik_vmd_file_ctrl.file_ctrl.GetPath(),
            self.leg_fk2ik_model_file_ctrl.file_ctrl.GetPath(),
            self.output_leg_fk2ik_vmd_file_ctrl.file_ctrl.GetPath(), is_force)

        self.output_leg_fk2ik_vmd_file_ctrl.file_ctrl.SetPath(output_leg_fk2ik_vmd_path)

        if len(output_leg_fk2ik_vmd_path) >= 255 and os.name == "nt":
            logger.error("生成予定のファイルパスがWindowsの制限を超えています。\n生成予定パス: {0}".format(output_leg_fk2ik_vmd_path), decoration=MLogger.DECORATION_BOX)
    def on_export(self, event: wx.Event):
        org_choice_values = []
        rep_rx_choice_values = []
        rep_ry_choice_values = []
        rep_rz_choice_values = []
        rep_mx_choice_values = []
        rep_my_choice_values = []
        rep_mz_choice_values = []

        for m in self.get_bone_list():
            org_choice_values.append(m[0])
            rep_rx_choice_values.append(m[1])
            rep_ry_choice_values.append(m[2])
            rep_rz_choice_values.append(m[3])
            rep_mx_choice_values.append(m[4])
            rep_my_choice_values.append(m[5])
            rep_mz_choice_values.append(m[6])

        output_bone_path = MFileUtils.get_output_split_bone_path(
            self.panel.vmd_file_ctrl.file_ctrl.GetPath(),
            self.panel.model_file_ctrl.file_ctrl.GetPath())

        try:
            with open(output_bone_path, encoding='cp932', mode='w',
                      newline='') as f:
                cw = csv.writer(f,
                                delimiter=",",
                                quotechar='"',
                                quoting=csv.QUOTE_ALL)

                cw.writerow(org_choice_values)
                cw.writerow(rep_rx_choice_values)
                cw.writerow(rep_ry_choice_values)
                cw.writerow(rep_rz_choice_values)
                cw.writerow(rep_mx_choice_values)
                cw.writerow(rep_my_choice_values)
                cw.writerow(rep_mz_choice_values)

            logger.info("出力成功: %s" % output_bone_path)

            dialog = wx.MessageDialog(self.frame,
                                      "多段ボーンデータのエクスポートに成功しました \n'%s'" %
                                      (output_bone_path),
                                      style=wx.OK)
            dialog.ShowModal()
            dialog.Destroy()

        except Exception:
            dialog = wx.MessageDialog(
                self.frame,
                "多段ボーンデータのエクスポートに失敗しました \n'%s'\n\n%s." %
                (output_bone_path, traceback.format_exc()),
                style=wx.OK)
            dialog.ShowModal()
            dialog.Destroy()
Esempio n. 7
0
    def save(self):

        # 履歴保持
        self.frame.file_panel_ctrl.file_set.save()

        # multiのも全部保持
        for file_set in self.frame.multi_panel_ctrl.file_set_list:
            file_set.save()

        # カメラ履歴保持
        self.frame.camera_panel_ctrl.save()

        # カメラ元モデル保持
        for camera_set in self.frame.camera_panel_ctrl.camera_set_dict.values(
        ):
            camera_set.camera_model_file_ctrl.save()

        # JSON出力
        MFileUtils.save_history(self.frame.mydir_path,
                                self.frame.file_hitories)
Esempio n. 8
0
    def set_output_vmd_path(self, event, is_force=False):
        output_camera_vmd_path = MFileUtils.get_output_camera_vmd_path(
            self.parent.camera_vmd_file_ctrl.file_ctrl.GetPath(),
            self.frame.file_panel_ctrl.file_set.rep_model_file_ctrl.file_ctrl.
            GetPath(),
            self.parent.output_camera_vmd_file_ctrl.file_ctrl.GetPath(),
            self.parent.camera_length_slider.GetValue(), is_force)

        self.parent.output_camera_vmd_file_ctrl.file_ctrl.SetPath(
            output_camera_vmd_path)

        if len(output_camera_vmd_path) >= 255 and os.name == "nt":
            logger.error("生成予定のファイルパスがWindowsの制限を超えています。\n生成予定パス: {0}".format(
                output_camera_vmd_path),
                         decoration=MLogger.DECORATION_BOX)
Esempio n. 9
0
    def set_output_vmd_path(self, event, is_force=False):
        output_smooth_vmd_path = MFileUtils.get_output_smooth_vmd_path(
            self.smooth_vmd_file_ctrl.file_ctrl.GetPath(),
            self.smooth_model_file_ctrl.file_ctrl.GetPath(),
            self.output_smooth_vmd_file_ctrl.file_ctrl.GetPath(),
            self.interpolation_ctrl.GetSelection(),
            self.loop_cnt_ctrl.GetValue(), is_force)

        self.output_smooth_vmd_file_ctrl.file_ctrl.SetPath(
            output_smooth_vmd_path)

        if len(output_smooth_vmd_path) >= 255 and os.name == "nt":
            logger.error("生成予定のファイルパスがWindowsの制限を超えています。\n生成予定パス: {0}".format(
                output_smooth_vmd_path),
                         decoration=MLogger.DECORATION_BOX)
Esempio n. 10
0
    def on_export(self, event: wx.Event):
        org_morph_list = []
        rep_morph_list = []
        ratio_list = []
        for m in self.get_morph_list():
            org_morph_list.append(m[0])
            rep_morph_list.append(m[1])
            ratio_list.append(m[2])

        output_morph_path = MFileUtils.get_output_morph_path(
            self.file_set.motion_vmd_file_ctrl.file_ctrl.GetPath(),
            self.file_set.org_model_file_ctrl.file_ctrl.GetPath(),
            self.file_set.rep_model_file_ctrl.file_ctrl.GetPath())

        try:
            with open(output_morph_path,
                      encoding='cp932',
                      mode='w',
                      newline='') as f:
                cw = csv.writer(f,
                                delimiter=",",
                                quotechar='"',
                                quoting=csv.QUOTE_ALL)

                # 元モーフ行
                cw.writerow(org_morph_list)
                # 先モーフ行
                cw.writerow(rep_morph_list)
                # 大きさ
                cw.writerow(ratio_list)

            logger.info("出力成功: %s" % output_morph_path)

            dialog = wx.MessageDialog(self.frame,
                                      "モーフデータのエクスポートに成功しました \n'%s'" %
                                      (output_morph_path),
                                      style=wx.OK)
            dialog.ShowModal()
            dialog.Destroy()

        except Exception:
            dialog = wx.MessageDialog(
                self.frame,
                "モーフデータのエクスポートに失敗しました \n'%s'\n\n%s." %
                (output_morph_path, traceback.format_exc()),
                style=wx.OK)
            dialog.ShowModal()
            dialog.Destroy()
Esempio n. 11
0
    def set_output_vmd_path(self, event, is_force=False):
        output_vmd_path = MFileUtils.get_output_vmd_path(
            self.motion_vmd_file_ctrl.file_ctrl.GetPath(),
            self.rep_model_file_ctrl.file_ctrl.GetPath(),
            self.org_model_file_ctrl.title_parts_ctrl.GetValue(),
            self.rep_model_file_ctrl.title_parts_ctrl.GetValue(),
            self.frame.arm_panel_ctrl.arm_process_flg_avoidance.GetValue(),
            self.frame.arm_panel_ctrl.arm_process_flg_alignment.GetValue(),
            (self.set_no in self.frame.morph_panel_ctrl.morph_set_dict and self.frame.morph_panel_ctrl.morph_set_dict[self.set_no].is_set_morph()) \
            or (self.set_no in self.frame.morph_panel_ctrl.bulk_morph_set_dict and len(self.frame.morph_panel_ctrl.bulk_morph_set_dict[self.set_no]) > 0),
            self.output_vmd_file_ctrl.file_ctrl.GetPath(), is_force)

        self.output_vmd_file_ctrl.file_ctrl.SetPath(output_vmd_path)

        if len(output_vmd_path) >= 255 and os.name == "nt":
            logger.error("生成予定のファイルパスがWindowsの制限を超えています。\n生成予定パス: {0}".format(
                output_vmd_path),
                         decoration=MLogger.DECORATION_BOX)
    def on_show_history(self, event):

        # 入力行を伸ばす
        hs = copy.deepcopy(self.frame.file_hitories[self.file_histories_key])
        hs.extend(["" for x in range(self.frame.file_hitories["max"] + 1)])

        with wx.SingleChoiceDialog(self.parent, "ファイルを選んでダブルクリック、またはOKボタンをクリックしてください。", caption="ファイル履歴選択",
                                   choices=hs[:(self.frame.file_hitories["max"] + 1)],
                                   style=wx.CAPTION | wx.CLOSE_BOX | wx.SYSTEM_MENU | wx.OK | wx.CANCEL | wx.CENTRE) as choiceDialog:

            if choiceDialog.ShowModal() == wx.ID_CANCEL:
                return     # the user changed their mind

            # ファイルピッカーに選択したパスを設定
            self.file_ctrl.SetPath(choiceDialog.GetStringSelection())
            self.file_ctrl.UpdatePickerFromTextCtrl()
            self.file_ctrl.SetInitialDirectory(MFileUtils.get_dir_path(choiceDialog.GetStringSelection()))

            # ファイル変更処理
            self.on_change_file(wx.FileDirPickerEvent())
Esempio n. 13
0
    def convert_csv(self):
        # モーションVMDディレクトリパス
        motion_vmd_dir_path = MFileUtils.get_dir_path(self.options.motion.path)
        # モーションVMDファイル名・拡張子
        motion_vmd_file_name, motion_vmd_ext = os.path.splitext(
            os.path.basename(self.options.motion.path))

        dt_now = datetime.now()

        if self.options.motion.motion_cnt == self.options.motion.morph_cnt == self.options.motion.camera_cnt == 0:
            logger.warning("出力可能なモーションデータ(ボーン・モーフ・カメラ)がありません",
                           decoration=MLogger.DECORATION_BOX)

        if self.options.motion.motion_cnt > 0:
            # ボーンモーションがある場合、ボーンモーション出力

            bone_fpath = "{0}\\{1}_bone_{2:%Y%m%d_%H%M%S}.csv".format(
                motion_vmd_dir_path, motion_vmd_file_name, dt_now)

            # Excel等で読めるよう、cp932限定
            with open(bone_fpath, encoding='cp932', mode='w') as f:

                s = "ボーン名,フレーム,位置X,位置Y,位置Z,回転X,回転Y,回転Z,【X_x1】,Y_x1,Z_x1,R_x1,【X_y1】,Y_y1,Z_y1,R_y1,【X_x2】,Y_x2,Z_x2,R_x2,【X_y2】,Y_y2,Z_y2,R_y2," + \
                    "【Y_x1】,Z_x1,R_x1,X_y1,【Y_y1】,Z_y1,R_y1,X_x2,【Y_x2】,Z_x2,R_x2,X_y2,【Y_y2】,Z_y2,R_y2,1,【Z_x1】,R_x1,X_y1,Y_y1,【Z_y1】,R_y1,X_x2,Y_x2,【Z_x2】" + \
                    ",R_x2,X_y2,Y_y2,【Z_y2】,R_y2,1,0,【R_x1】,X_y1,Y_y1,Z_y1,【R_y1】,X_x2,Y_x2,Z_x2,【R_x2】,X_y2,Y_y2,Z_y2,【R_y2】,01,00,00"
                f.write(s)
                f.write("\n")

                for bone_name in self.options.motion.bones:
                    for fno in self.options.motion.get_bone_fnos(bone_name):
                        bf = self.options.motion.bones[bone_name][fno]
                        s = "{0},{1},{2},{3},{4},{5},{6},{7},{8}".format(bf.name, bf.fno, \
                                                                         bf.position.x(), bf.position.y(), bf.position.z(), bf.rotation.toEulerAngles4MMD().x(), \
                                                                         bf.rotation.toEulerAngles4MMD().y(), bf.rotation.toEulerAngles4MMD().z(), ','.join([str(i) for i in bf.interpolation]))
                        f.write(s)
                        f.write("\n")

            logger.info("ボーンモーションCSV: %s",
                        bone_fpath,
                        decoration=MLogger.DECORATION_BOX)

        if self.options.motion.morph_cnt > 0:
            # モーフ出力
            morph_fpath = "{0}\\{1}_morph_{2:%Y%m%d_%H%M%S}.csv".format(
                motion_vmd_dir_path, motion_vmd_file_name, dt_now)

            # Excel等で読めるよう、cp932限定
            with open(morph_fpath, encoding='cp932', mode='w') as f:

                s = "モーフ名,フレーム,大きさ"
                f.write(s)
                f.write("\n")

                for morph_name in self.options.motion.morphs:
                    for fno in self.options.motion.get_morph_fnos(morph_name):
                        mf = self.options.motion.morphs[morph_name][fno]
                        s = "{0},{1},{2}".format(mf.name, mf.fno, mf.ratio)
                        f.write(s)
                        f.write("\n")

            logger.info("モーフモーションCSV: %s",
                        morph_fpath,
                        decoration=MLogger.DECORATION_BOX)

        if self.options.motion.camera_cnt > 0:
            # カメラ出力
            camera_fpath = "{0}\\{1}_camera_{2:%Y%m%d_%H%M%S}.csv".format(
                motion_vmd_dir_path, motion_vmd_file_name, dt_now)

            # Excel等で読めるよう、cp932限定
            with open(camera_fpath, encoding='cp932', mode='w') as f:

                s = "フレーム,位置X,位置Y,位置Z,回転X,回転Y,回転Z,距離,視野角,パース,X_x1,Y_x1,Z_x1,R_x1,L_x1,VA_x1," + \
                    "X_y1,Y_y1,Z_y1,R_y1,L_y1,VA_y1,X_x2,Y_x2,Z_x2,R_x2,L_x2,VA_x2, X_y2,Y_y2,Z_y2,R_y2,L_y2,VA_y2"
                f.write(s)
                f.write("\n")

                for fno in self.options.motion.get_camera_fnos():
                    cf = self.options.motion.cameras[fno]
                    s = "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10}" \
                        .format(cf.fno, cf.position.x(), cf.position.y(), cf.position.z(), -math.degrees(cf.euler.x()), math.degrees(cf.euler.y()), math.degrees(cf.euler.z()), \
                                -cf.length, cf.angle, cf.perspective, ','.join([str(i) for i in cf.interpolation]))
                    f.write(s)
                    f.write("\n")

            logger.info("カメラモーションCSV: %s",
                        camera_fpath,
                        decoration=MLogger.DECORATION_BOX)

        return True
Esempio n. 14
0
    def __init__(self, parent, mydir_path: str, version_name: str,
                 logging_level: int, is_saving: bool, is_out_log: bool):
        self.version_name = version_name
        self.logging_level = logging_level
        self.is_out_log = is_out_log
        self.is_saving = is_saving
        self.mydir_path = mydir_path
        self.elapsed_time = 0
        self.popuped_finger_warning = False

        self.worker = None
        self.load_worker = None

        wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=u"VMDサイジング ローカル版 {0}".format(self.version_name), \
                          pos=wx.DefaultPosition, size=wx.Size(600, 650), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)

        # ファイル履歴読み込み
        self.file_hitories = MFileUtils.read_history(self.mydir_path)

        # ---------------------------------------------

        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        bSizer1 = wx.BoxSizer(wx.VERTICAL)

        self.note_ctrl = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition,
                                     wx.DefaultSize, 0)
        if self.logging_level == MLogger.FULL or self.logging_level == MLogger.DEBUG_FULL:
            # フルデータの場合
            self.note_ctrl.SetBackgroundColour("RED")
        elif self.logging_level == MLogger.DEBUG:
            # テスト(デバッグ版)の場合
            self.note_ctrl.SetBackgroundColour("CORAL")
        elif self.logging_level == MLogger.TIMER:
            # 時間計測の場合
            self.note_ctrl.SetBackgroundColour("YELLOW")
        elif not is_saving:
            # ログありの場合、色変え
            self.note_ctrl.SetBackgroundColour("BLUE")
        elif is_out_log:
            # ログありの場合、色変え
            self.note_ctrl.SetBackgroundColour("AQUAMARINE")
        else:
            self.note_ctrl.SetBackgroundColour(
                wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW))

        # ---------------------------------------------

        # ファイルタブ
        self.file_panel_ctrl = FilePanel(self, self.note_ctrl, 0,
                                         self.file_hitories)
        self.note_ctrl.AddPage(self.file_panel_ctrl, u"ファイル", True)

        # 複数タブ
        self.multi_panel_ctrl = MultiPanel(self, self.note_ctrl, 1,
                                           self.file_hitories)
        self.note_ctrl.AddPage(self.multi_panel_ctrl, u"複数", False)

        # モーフタブ
        self.morph_panel_ctrl = MorphPanel(self, self.note_ctrl, 2)
        self.note_ctrl.AddPage(self.morph_panel_ctrl, u"モーフ", False)

        # 腕タブ
        self.arm_panel_ctrl = ArmPanel(self, self.note_ctrl, 3)
        self.note_ctrl.AddPage(self.arm_panel_ctrl, u"腕", False)

        # カメラタブ
        self.camera_panel_ctrl = CameraPanel(self, self.note_ctrl, 4)
        self.note_ctrl.AddPage(self.camera_panel_ctrl, u"カメラ", False)

        # 一括タブ
        self.bulk_panel_ctrl = BulkPanel(self, self.note_ctrl, 5)
        self.note_ctrl.AddPage(self.bulk_panel_ctrl, u"一括", False)

        # CSVタブ
        self.csv_panel_ctrl = CsvPanel(self, self.note_ctrl, 6)
        self.note_ctrl.AddPage(self.csv_panel_ctrl, u"CSV", False)

        # VMDタブ
        self.vmd_panel_ctrl = VmdPanel(self, self.note_ctrl, 7)
        self.note_ctrl.AddPage(self.vmd_panel_ctrl, u"VMD", False)

        # ---------------------------------------------

        # タブ押下時の処理
        self.note_ctrl.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_tab_change)

        # ---------------------------------------------

        bSizer1.Add(self.note_ctrl, 1, wx.EXPAND, 5)

        # デフォルトの出力先はファイルタブのコンソール
        sys.stdout = self.file_panel_ctrl.console_ctrl

        # イベントバインド
        self.Bind(EVT_SIZING_THREAD, self.on_exec_result)
        self.Bind(EVT_LOAD_THREAD, self.on_load_result)

        self.SetSizer(bSizer1)
        self.Layout()

        self.Centre(wx.BOTH)
Esempio n. 15
0
    def convert_vmd(self):
        dt_now = datetime.now()

        bone_fpath = None
        bone_motion = VmdMotion()

        if self.options.bone_csv_path and os.path.exists(self.options.bone_csv_path):
            # ボーンモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(self.options.bone_csv_path)
            # ボーンモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(os.path.basename(self.options.bone_csv_path))

            bone_fpath = "{0}\\{1}_bone_{2:%Y%m%d_%H%M%S}.vmd".format(motion_csv_dir_path, motion_csv_file_name, dt_now)

            # ボーンCSV読み込み
            with open(self.options.bone_csv_path, encoding='cp932', mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for row in reader:
                    bf = VmdBoneFrame()

                    # ボーン名
                    bf.set_name(row[0])

                    # フレーム
                    bf.fno = int(float(row[1]))

                    # 位置
                    bf.position = MVector3D(float(row[2]), float(row[3]), float(row[4]))

                    # 回転
                    bf.rotation = MQuaternion.fromEulerAngles(float(row[5]), float(row[6]) * -1, float(row[7]) * -1)

                    # 補間曲線
                    # 補間曲線(一旦floatで読み込んで指数等も読み込んだ後、intに変換)
                    bf.interpolation = [int(float(row[8])), int(float(row[9])), int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), \
                                        int(float(row[14])), int(float(row[15])), int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), \
                                        int(float(row[20])), int(float(row[21])), int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), \
                                        int(float(row[26])), int(float(row[27])), int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), \
                                        int(float(row[32])), int(float(row[33])), int(float(row[34])), int(float(row[35])), int(float(row[36])), int(float(row[37])), \
                                        int(float(row[38])), int(float(row[39])), int(float(row[40])), int(float(row[41])), int(float(row[42])), int(float(row[43])), \
                                        int(float(row[44])), int(float(row[45])), int(float(row[46])), int(float(row[47])), int(float(row[48])), int(float(row[49])), \
                                        int(float(row[50])), int(float(row[51])), int(float(row[52])), int(float(row[53])), int(float(row[54])), int(float(row[55])), \
                                        int(float(row[56])), int(float(row[57])), int(float(row[58])), int(float(row[59])), int(float(row[60])), int(float(row[61])), \
                                        int(float(row[62])), int(float(row[63])), int(float(row[64])), int(float(row[65])), int(float(row[66])), int(float(row[67])), \
                                        int(float(row[68])), int(float(row[69])), int(float(row[70])), int(float(row[71]))]
                    
                    bf.read = True
                    bf.key = True

                    if bf.name not in bone_motion.bones:
                        bone_motion.bones[bf.name] = {}

                    bone_motion.bones[bf.name][bf.fno] = bf

                    cnt += 1

                    if cnt % 10000 == 0:
                        logger.info("[ボーン] %sキー目:終了", cnt)

        if self.options.morph_csv_path and os.path.exists(self.options.morph_csv_path):
            # モーフモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(self.options.morph_csv_path)
            # モーフモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(os.path.basename(self.options.morph_csv_path))

            if not bone_fpath:
                bone_fpath = "{0}\\{1}_morph_{2:%Y%m%d_%H%M%S}.vmd".format(motion_csv_dir_path, motion_csv_file_name, dt_now)

            # モーフCSV読み込み
            with open(self.options.morph_csv_path, encoding='cp932', mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for row in reader:
                    mf = VmdMorphFrame()

                    # ボーン名
                    mf.set_name(row[0])

                    # フレーム
                    mf.fno = int(float(row[1]))

                    # 位置
                    mf.ratio = float(row[2])

                    if mf.name not in bone_motion.morphs:
                        bone_motion.morphs[mf.name] = {}

                    bone_motion.morphs[mf.name][mf.fno] = mf

                    cnt += 1

                    if cnt % 1000 == 0:
                        logger.info("[モーフ] %sキー目:終了", cnt)

        if len(bone_motion.bones.keys()) > 0 or len(bone_motion.morphs.keys()) > 0:
            # ボーンかモーフのキーがある場合、まとめて出力

            model = PmxModel()
            model.name = "CSV Convert Model"
            data_set = MOptionsDataSet(bone_motion, None, model, bone_fpath, False, False, [], None, None, [])

            VmdWriter(data_set).write()

            logger.info("ボーン・モーフモーションVMD: %s", bone_fpath, decoration=MLogger.DECORATION_BOX)

        if self.options.camera_csv_path and os.path.exists(self.options.camera_csv_path):
            # カメラモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(self.options.camera_csv_path)
            # カメラモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(os.path.basename(self.options.camera_csv_path))

            camera_fpath = "{0}\\{1}_camera_{2:%Y%m%d_%H%M%S}.vmd".format(motion_csv_dir_path, motion_csv_file_name, dt_now)
            camera_motion = VmdMotion()

            # カメラCSV読み込み
            with open(self.options.camera_csv_path, encoding='cp932', mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for row in reader:
                    cf = VmdCameraFrame()

                    # フレーム
                    cf.fno = int(row[0])

                    # 位置
                    cf.position = MVector3D(float(row[1]), float(row[2]), float(row[3]))

                    # 回転(オイラー角)
                    cf.euler = MVector3D(float(row[4]), float(row[5]), float(row[6]))

                    # 距離
                    cf.length = -(float(row[7]))

                    # 視野角
                    cf.angle = int(row[8])

                    # パース
                    cf.perspective = int(row[9])

                    # 補間曲線
                    cf.interpolation = [int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), int(float(row[14])), int(float(row[15])), \
                                        int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), int(float(row[20])), int(float(row[21])), \
                                        int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), int(float(row[26])), int(float(row[27])), \
                                        int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), int(float(row[32])), int(float(row[33]))]

                    camera_motion.cameras[cf.fno] = cf

                    cnt += 1

                    if cnt % 500 == 0:
                        logger.info("[カメラ] %sキー目:終了", cnt)

            if len(camera_motion.cameras) > 0:
                # ボーンかモーフのキーがある場合、まとめて出力

                model = PmxModel()
                model.name = "カメラ・照明"
                data_set = MOptionsDataSet(camera_motion, None, model, camera_fpath, False, False, [], None, None, [])

                VmdWriter(data_set).write()

                logger.info("カメラモーションVMD: %s", camera_fpath, decoration=MLogger.DECORATION_BOX)

        return True
    def on_import(self, event: wx.Event):
        input_bone_path = MFileUtils.get_output_split_bone_path(
            self.panel.vmd_file_ctrl.file_ctrl.GetPath(),
            self.panel.model_file_ctrl.file_ctrl.GetPath())

        with wx.FileDialog(
                self.frame,
                "ボーン組み合わせCSVを読み込む",
                wildcard=u"CSVファイル (*.csv)|*.csv|すべてのファイル (*.*)|*.*",
                defaultDir=os.path.dirname(input_bone_path),
                style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Proceed loading the file chosen by the user
            target_bone_path = fileDialog.GetPath()
            try:
                with open(target_bone_path, 'r') as f:
                    cr = csv.reader(f, delimiter=",", quotechar='"')
                    bone_lines = [row for row in cr]

                    if len(bone_lines) == 0:
                        return

                    if not bone_lines[0]:
                        raise Exception("処理対象ボーン名指定なし")

                    org_choice_values = bone_lines[0]
                    if len(bone_lines) >= 4:
                        rep_rx_choice_values = bone_lines[1]
                        rep_ry_choice_values = bone_lines[2]
                        rep_rz_choice_values = bone_lines[3]
                    else:
                        rep_rx_choice_values = [""]
                        rep_ry_choice_values = [""]
                        rep_rz_choice_values = [""]

                    if len(bone_lines) >= 7:
                        rep_mx_choice_values = bone_lines[4]
                        rep_my_choice_values = bone_lines[5]
                        rep_mz_choice_values = bone_lines[6]
                    else:
                        rep_mx_choice_values = [""]
                        rep_my_choice_values = [""]
                        rep_mz_choice_values = [""]

                    for (ov, rmxv, rmyv, rmzv, rrxv, rryv, rrzv) in zip(org_choice_values, rep_mx_choice_values, rep_my_choice_values, rep_mz_choice_values, \
                                                                        rep_rx_choice_values, rep_ry_choice_values, rep_rz_choice_values):
                        oc = self.org_choices[-1]
                        rrxc = self.rep_rx_choices[-1]
                        rryc = self.rep_ry_choices[-1]
                        rrzc = self.rep_rz_choices[-1]
                        rmxc = self.rep_mx_choices[-1]
                        rmyc = self.rep_my_choices[-1]
                        rmzc = self.rep_mz_choices[-1]

                        is_seted = False
                        for v, c in [(ov, oc), (rmxv, rmxc), (rmyv, rmyc),
                                     (rmzv, rmzc), (rrxv, rrxc), (rryv, rryc),
                                     (rrzv, rrzc)]:
                            logger.debug("v: %s, c: %s", v, c)
                            for n in range(c.GetCount()):
                                if c.GetString(n).strip() == v:
                                    c.SetSelection(n)
                                    is_seted = True

                        if is_seted:
                            # 行追加
                            self.add_line()
                        else:
                            # ひとつも追加がなかった場合、終了
                            break

                # パス変更
                self.panel.set_output_vmd_path(event)

            except Exception:
                dialog = wx.MessageDialog(
                    self.frame,
                    "CSVファイルが読み込めませんでした '%s'\n\n%s." %
                    (target_bone_path, traceback.format_exc()),
                    style=wx.OK)
                dialog.ShowModal()
                dialog.Destroy()
Esempio n. 17
0
from module.MOptions import MOptions
from utils.MLogger import MLogger
from utils import MFileUtils
from service.SizingService import SizingService
from utils.MException import SizingException

VERSION_NAME = "ver5.00"

# 指数表記なし、有効小数点桁数6、30を超えると省略あり、一行の文字数200
np.set_printoptions(suppress=True, precision=6, threshold=30, linewidth=200)

# Windowsマルチプロセス対策
multiprocessing.freeze_support()

if __name__ == '__main__':
    mydir_path = MFileUtils.get_mydir_path(sys.argv[0])

    if len(sys.argv) > 3 and "--motion_path" in sys.argv:
        if os.name == "nt":
            import winsound  # Windows版のみインポート

        # 引数指定がある場合、コマンドライン実行
        try:
            SizingService(MOptions.parse(VERSION_NAME)).execute()
        except SizingException as se:
            print("サイジング処理が処理できないデータで終了しました。\n\n%s", se.message)
        except Exception:
            print("サイジング処理が意図せぬエラーで終了しました。")
            print(traceback.format_exc())
        finally:
            logging.shutdown()
Esempio n. 18
0
    def parse(cls, version_name: str):
        parser = argparse.ArgumentParser()
        parser.add_argument("--motion_path",
                            required=True,
                            type=(lambda x: list(map(str, x.split(';')))))
        parser.add_argument("--org_model_path",
                            required=True,
                            type=(lambda x: list(map(str, x.split(';')))))
        parser.add_argument("--rep_model_path",
                            required=True,
                            type=(lambda x: list(map(str, x.split(';')))))
        parser.add_argument("--detail_stance_flg",
                            required=True,
                            type=(lambda x: list(map(int, x.split(';')))))
        parser.add_argument("--twist_flg",
                            required=True,
                            type=(lambda x: list(map(int, x.split(';')))))
        parser.add_argument("--arm_process_flg_avoidance", type=int, default=0)
        parser.add_argument("--avoidance_target_list",
                            default=[],
                            type=(lambda x: list(map(str, x.split(';')))))
        parser.add_argument("--arm_process_flg_alignment", type=int, default=0)
        parser.add_argument("--alignment_finger_flg", type=int, default=0)
        parser.add_argument("--alignment_floor_flg", type=int, default=0)
        parser.add_argument("--alignment_distance_wrist",
                            type=float,
                            default=1.7)
        parser.add_argument("--alignment_distance_finger",
                            type=float,
                            default=1.4)
        parser.add_argument("--alignment_distance_floor",
                            type=float,
                            default=1.8)
        parser.add_argument("--arm_check_skip_flg", type=int, default=0)
        parser.add_argument("--camera_motion_path", type=str, default="")
        parser.add_argument("--camera_org_model_path",
                            default=[],
                            type=(lambda x: list(map(str, x.split(';')))))
        parser.add_argument("--camera_offset_y",
                            default=[],
                            type=(lambda x: list(map(str, x.split(';')))))
        parser.add_argument("--verbose", type=int, default=20)

        args = parser.parse_args()

        # ログディレクトリ作成
        os.makedirs("log", exist_ok=True)

        MLogger.initialize(level=args.verbose, is_file=True)

        try:
            arm_process_flg_avoidance = True if args.arm_process_flg_avoidance == 1 else False
            arm_process_flg_alignment = True if args.arm_process_flg_alignment == 1 else False
            alignment_finger_flg = True if args.alignment_finger_flg == 1 else False
            alignment_floor_flg = True if args.alignment_floor_flg == 1 else False
            arm_check_skip_flg = True if args.arm_check_skip_flg == 1 else False

            arm_options = MArmProcessOptions(
                arm_process_flg_avoidance, \
                {0: [(a.strip() if len(a.strip()) > 0 else "") for a in args.avoidance_target_list]}, \
                arm_process_flg_alignment, \
                alignment_finger_flg, \
                alignment_floor_flg, \
                args.alignment_distance_wrist, \
                args.alignment_distance_finger, \
                args.alignment_distance_floor, \
                arm_check_skip_flg
            )

            # 元モデルが未指定の場合、空で処理する
            if not args.camera_org_model_path or (
                    len(args.camera_org_model_path) == 1
                    and len(args.camera_org_model_path[0]) == 0):
                args.camera_org_model_path = []
                for org_path in args.org_model_path:
                    args.camera_org_model_path.append("")

            # オフセットYが未指定の場合、0で処理する
            if not args.camera_offset_y or (len(args.camera_offset_y) == 1 and
                                            len(args.camera_offset_y[0]) == 0):
                args.camera_offset_y = []
                for org_path in args.org_model_path:
                    args.camera_offset_y.append(0)

            data_set_list = []
            for set_no, (motion_path, org_model_path, rep_model_path, detail_stance_flg_val, twist_flg_val, camera_org_model_path, camera_offset_y) in enumerate( \
                zip(args.motion_path, args.org_model_path, args.rep_model_path, args.detail_stance_flg, args.twist_flg, args.camera_org_model_path, \
                    args.camera_offset_y)): # noqa

                display_set_no = "【No.{0}】".format(set_no + 1)

                # モーションパス --------
                logger.info("%s 調整対象モーションVMD/VPDファイル 読み込み開始", display_set_no)

                file_name, input_ext = os.path.splitext(
                    os.path.basename(motion_path))
                if input_ext.lower() == ".vmd":
                    motion_reader = VmdReader(motion_path)
                elif input_ext.lower() == ".vpd":
                    motion_reader = VpdReader(motion_path)
                else:
                    raise SizingException(
                        "{0}.motion_path 読み込み失敗(拡張子不正): {1}".format(
                            display_set_no, os.path.basename(motion_path)))

                motion = motion_reader.read_data()

                logger.info("%s 調整対象モーションVMD/VPDファイル 読み込み成功 %s",
                            display_set_no, os.path.basename(motion_path))

                # 元モデル ----------
                logger.info("%s モーション作成元モデルPMXファイル 読み込み開始", display_set_no)

                file_name, input_ext = os.path.splitext(
                    os.path.basename(org_model_path))
                if input_ext.lower() == ".pmx":
                    org_model_reader = PmxReader(org_model_path)
                else:
                    raise SizingException(
                        "{0}.org_model_path 読み込み失敗(拡張子不正): {1}".format(
                            display_set_no, os.path.basename(org_model_path)))

                org_model = org_model_reader.read_data()

                logger.info("%s モーション作成元モデルPMXファイル 読み込み成功 %s", display_set_no,
                            os.path.basename(org_model_path))

                # 先モデル ----------
                logger.info("%s モーション変換先モデルPMXファイル 読み込み開始", display_set_no)

                file_name, input_ext = os.path.splitext(
                    os.path.basename(rep_model_path))
                if input_ext.lower() == ".pmx":
                    rep_model_reader = PmxReader(rep_model_path)
                else:
                    raise SizingException(
                        "{0}.rep_model_path 読み込み失敗(拡張子不正): {1}".format(
                            display_set_no, os.path.basename(rep_model_path)))

                rep_model = rep_model_reader.read_data()

                logger.info("%s モーション変換先モデルPMXファイル 読み込み成功 %s", display_set_no,
                            os.path.basename(rep_model_path))

                # 元モデル ----------
                if len(camera_org_model_path) > 0:
                    logger.info("%s カメラ作成元モデルPMXファイル 読み込み開始", display_set_no)

                    file_name, input_ext = os.path.splitext(
                        os.path.basename(camera_org_model_path))
                    if input_ext.lower() == ".pmx":
                        camera_org_model_reader = PmxReader(
                            camera_org_model_path)
                    else:
                        raise SizingException(
                            "{0}.camera_org_model_path 読み込み失敗(拡張子不正): {1}".
                            format(display_set_no,
                                   os.path.basename(camera_org_model_path)))

                    camera_org_model = camera_org_model_reader.read_data()

                    logger.info("%s カメラ作成元モデルPMXファイル 読み込み成功 %s",
                                display_set_no,
                                os.path.basename(camera_org_model_path))
                else:
                    # カメラ元モデルが未指定の場合、作成元モデルをそのまま流用
                    camera_org_model = org_model

                detail_stance_flg = True if detail_stance_flg_val == 1 else False
                twist_flg = True if twist_flg_val == 1 else False

                # 出力ファイルパス
                output_vmd_path = MFileUtils.get_output_vmd_path(
                    motion_path, rep_model_path, detail_stance_flg, twist_flg,
                    arm_process_flg_avoidance, arm_process_flg_alignment,
                    False, "", True)

                data_set = MOptionsDataSet(
                    motion, org_model, rep_model, output_vmd_path,
                    detail_stance_flg, twist_flg, [], camera_org_model,
                    camera_offset_y, [
                        "センターXZ補正", "上半身補正", "下半身補正", "足IK補正", "つま先IK補正",
                        "つま先補正", "肩補正", "センターY補正"
                    ])

                data_set_list.append(data_set)

            if len(args.camera_motion_path) != 0:
                # カメラパス --------
                logger.info("調整対象カメラVMDファイル 読み込み開始")

                file_name, input_ext = os.path.splitext(
                    os.path.basename(args.camera_motion_path))
                if input_ext.lower() == ".vmd":
                    camera_motion_reader = VmdReader(args.camera_motion_path)
                else:
                    raise SizingException(
                        "camera_motion_path 読み込み失敗(拡張子不正): %s",
                        os.path.basename(args.camera_motion_path))

                camera_motion = camera_motion_reader.read_data()
                camera_output_vmd_path = MFileUtils.get_output_camera_vmd_path(
                    args.camera_motion_path, data_set_list[0].rep_model.path,
                    "")

                logger.info("調整対象カメラVMD/VPDファイル 読み込み成功 %s",
                            os.path.basename(args.camera_motion_path))
            else:
                camera_motion = None
                camera_output_vmd_path = None

            options = MOptions(\
                version_name=version_name, \
                logging_level=args.verbose, \
                data_set_list=data_set_list, \
                arm_options=arm_options, \
                camera_motion=camera_motion, \
                camera_output_vmd_path=camera_output_vmd_path, \
                monitor=sys.stdout, \
                is_file=True, \
                outout_datetime=logger.outout_datetime, \
                max_workers=1)

            return options
        except SizingException as se:
            logger.error("サイジング処理が処理できないデータで終了しました。\n\n%s",
                         se.message,
                         decoration=MLogger.DECORATION_BOX)
        except Exception as e:
            logger.critical("サイジング処理が意図せぬエラーで終了しました。",
                            e,
                            decoration=MLogger.DECORATION_BOX)
Esempio n. 19
0
    def is_valid(self):
        if self.set_no == 0:
            # CSVとかのファイルは番号出力なし
            display_set_no = ""
        else:
            display_set_no = "{0}番目の".format(self.set_no)

        if self.is_aster and self.set_no <= 1:
            base_file_path = self.file_ctrl.GetPath()

            if os.path.exists(base_file_path):
                file_path_list = [base_file_path]
            else:
                file_path_list = [p for p in glob.glob(base_file_path) if os.path.isfile(p)]

            if len(file_path_list) == 0:
                logger.error("{0}{1}の条件に合致するファイルが見つかりませんでした。\n入力パス: {2}".format(
                    display_set_no, self.title, self.file_ctrl.GetPath()), decoration=MLogger.DECORATION_BOX)
                return False

            file_path = file_path_list[0]
        else:
            file_path = self.file_ctrl.GetPath()
        
        if not self.is_save and not os.path.exists(file_path):
            if self.required:
                logger.error("{0}{1}が見つかりませんでした。\n入力パス: {2}".format(
                    display_set_no, self.title, self.file_ctrl.GetPath()), decoration=MLogger.DECORATION_BOX)
                return False
            else:
                # 任意の場合、ファイルパスがなければスルー
                return True

        if not self.is_save and not os.path.isfile(file_path):
            logger.error("{0}{1}が正常なファイルとして見つかりませんでした。\n入力パス: {2}".format(
                display_set_no, self.title, self.file_ctrl.GetPath()), decoration=MLogger.DECORATION_BOX)
            return False

        # 拡張子
        _, ext = os.path.splitext(os.path.basename(file_path))

        if ext[1:].lower() not in self.file_type:
            logger.error("{0}{1}の拡張子が正しくありません。\n入力パス: {2}\n設定可能拡張子: {3}".format(
                display_set_no, self.title, self.file_ctrl.GetPath(), self.file_type), decoration=MLogger.DECORATION_BOX)
            return False
        
        # 親ディレクトリ取得
        if self.is_save:
            # 書き込みはそのまま親
            dir_path = os.path.dirname(self.file_ctrl.GetPath())
        else:
            # 読み取りは解析する
            dir_path = MFileUtils.get_dir_path(self.file_ctrl.GetPath())

        if not os.path.exists(dir_path):
            logger.error("{0}{1}の親フォルダが見つかりませんでした。\n入力パス: {2}".format(
                display_set_no, self.title, dir_path), decoration=MLogger.DECORATION_BOX)
            return False

        if not os.path.isdir(dir_path):
            logger.error("{0}{1}の親フォルダが正常なフォルダとして見つかりませんでした。\n入力パス: {2}".format(
                display_set_no, self.title, dir_path), decoration=MLogger.DECORATION_BOX)
            return False

        if not os.access(dir_path, os.W_OK):
            logger.error("{0}{1}の親フォルダに書き込み権限がありません。\n入力パス: {2}".format(
                display_set_no, self.title, dir_path), decoration=MLogger.DECORATION_BOX)
            return False

        # 出力系の場合、自身のファイル上書き用の書き込み権限
        if self.is_save and os.path.isfile(self.file_ctrl.GetPath()) and not os.access(self.file_ctrl.GetPath(), os.W_OK):
            logger.error("{0}{1}に書き込み権限がありません。\n入力パス: {2}".format(
                display_set_no, self.title, self.file_ctrl.GetPath()), decoration=MLogger.DECORATION_BOX)
            return False

        return True
Esempio n. 20
0
    def on_import(self, event: wx.Event):
        input_morph_path = MFileUtils.get_output_morph_path(
            self.file_set.motion_vmd_file_ctrl.file_ctrl.GetPath(),
            self.file_set.org_model_file_ctrl.file_ctrl.GetPath(),
            self.file_set.rep_model_file_ctrl.file_ctrl.GetPath())

        with wx.FileDialog(
                self.frame,
                "モーフ組み合わせCSVを読み込む",
                wildcard=u"CSVファイル (*.csv)|*.csv|すべてのファイル (*.*)|*.*",
                defaultDir=os.path.dirname(input_morph_path),
                style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Proceed loading the file chosen by the user
            target_morph_path = fileDialog.GetPath()
            try:
                with open(target_morph_path, 'r') as f:
                    cr = csv.reader(f, delimiter=",", quotechar='"')
                    morph_lines = [row for row in cr]

                    if len(morph_lines) == 0:
                        return

                    org_choice_values = morph_lines[0]
                    rep_choice_values = morph_lines[1]
                    rep_rate_values = morph_lines[2]

                    logger.debug("org_choice_values: %s", org_choice_values)
                    logger.debug("rep_choice_values: %s", rep_choice_values)
                    logger.debug("rep_rate_values: %s", rep_rate_values)

                    if len(org_choice_values) == 0 or len(
                            rep_choice_values) == 0 or len(
                                rep_rate_values) == 0:
                        return

                    for vcv, rcv, rrv in zip(org_choice_values,
                                             rep_choice_values,
                                             rep_rate_values):
                        vc = self.org_choices[-1]
                        rc = self.rep_choices[-1]
                        rr = self.ratios[-1]
                        # 全件なめる
                        for v, c in [(vcv, vc), (rcv, rc)]:
                            logger.debug("v: %s, c: %s", v, c)
                            is_seted = False
                            for n in range(c.GetCount()):
                                for p in ["目", "眉", "口", "他", "?"]:
                                    for s in ["", "○", "●", "▲"]:
                                        # パネル情報を含める
                                        txt = "{0}{1}:{2}".format(p, s, v[:10])
                                        # if v == vcv:
                                        # 	logger.debug("txt: %s, c.GetString(n): %s", txt, c.GetString(n))
                                        if c.GetString(n).strip() == txt:
                                            logger.debug(
                                                "[HIT] txt: %s, c.GetString(n): %s, n: %s",
                                                txt, c.GetString(n), n)
                                            # パネルとモーフ名で一致している場合、採用
                                            c.SetSelection(n)
                                            is_seted = True
                                            break
                                    if is_seted:
                                        break
                        # 大きさ補正を設定する
                        try:
                            rr.SetValue(float(rrv))
                        except Exception:
                            pass

                        # 行追加
                        self.add_line()

                # パス変更
                self.file_set.set_output_vmd_path(event)

            except Exception:
                dialog = wx.MessageDialog(
                    self.frame,
                    "CSVファイルが読み込めませんでした '%s'\n\n%s." %
                    (target_morph_path, traceback.format_exc()),
                    style=wx.OK)
                dialog.ShowModal()
                dialog.Destroy()
Esempio n. 21
0
    def on_convert(self, event: wx.Event):
        self.timer.Stop()
        self.Unbind(wx.EVT_TIMER, id=TIMER_ID)
        # フォーム無効化
        self.disable()
        # タブ固定
        self.fix_tab()
        # コンソールクリア
        self.console_ctrl.Clear()
        # 出力先をスムージングパネルのコンソールに変更
        sys.stdout = self.console_ctrl

        wx.GetApp().Yield()

        self.smooth_vmd_file_ctrl.save()
        self.smooth_model_file_ctrl.save()

        # JSON出力
        MFileUtils.save_history(self.frame.mydir_path,
                                self.frame.file_hitories)

        self.elapsed_time = 0
        result = True
        result = self.smooth_vmd_file_ctrl.is_valid(
        ) and self.smooth_model_file_ctrl.is_valid() and result

        # スムージング変換開始
        if self.smooth_btn_ctrl.GetLabel(
        ) == "スムージング停止" and self.convert_smooth_worker:
            # フォーム無効化
            self.disable()
            # 停止状態でボタン押下時、停止
            self.convert_smooth_worker.stop()

            # タブ移動可
            self.frame.release_tab()
            # フォーム有効化
            self.frame.enable()
            # ワーカー終了
            self.convert_smooth_worker = None
            # プログレス非表示
            self.gauge_ctrl.SetValue(0)

            logger.warning("スムージングを中断します。", decoration=MLogger.DECORATION_BOX)
            self.smooth_btn_ctrl.SetLabel("スムージング実行")

            event.Skip(False)
        elif not self.convert_smooth_worker:
            # フォーム無効化
            self.disable()
            # タブ固定
            self.fix_tab()
            # コンソールクリア
            self.console_ctrl.Clear()
            # ラベル変更
            self.smooth_btn_ctrl.SetLabel("スムージング停止")
            self.smooth_btn_ctrl.Enable()

            self.convert_smooth_worker = SmoothWorkerThread(
                self.frame, SmoothThreadEvent, self.frame.is_saving,
                self.frame.is_out_log)
            self.convert_smooth_worker.start()

            event.Skip()
        else:
            logger.error("まだ処理が実行中です。終了してから再度実行してください。",
                         decoration=MLogger.DECORATION_BOX)
            event.Skip(False)

        return result
Esempio n. 22
0
    def __init__(self, parent, mydir_path: str, version_name: str,
                 logging_level: int, is_saving: bool, is_out_log: bool):
        self.version_name = version_name
        self.logging_level = logging_level
        self.is_out_log = is_out_log
        self.is_saving = is_saving
        self.mydir_path = mydir_path
        self.elapsed_time = 0
        self.popuped_finger_warning = False

        self.worker = None
        self.load_worker = None

        wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=u"モーションサポーター ローカル版 {0}".format(self.version_name), \
                          pos=wx.DefaultPosition, size=wx.Size(600, 650), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)

        # ファイル履歴読み込み
        self.file_hitories = MFileUtils.read_history(self.mydir_path)

        # ---------------------------------------------

        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        bSizer1 = wx.BoxSizer(wx.VERTICAL)

        self.note_ctrl = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition,
                                     wx.DefaultSize, 0)
        if self.logging_level == MLogger.FULL or self.logging_level == MLogger.DEBUG_FULL:
            # フルデータの場合
            self.note_ctrl.SetBackgroundColour("RED")
        elif self.logging_level == MLogger.DEBUG:
            # テスト(デバッグ版)の場合
            self.note_ctrl.SetBackgroundColour("CORAL")
        elif self.logging_level == MLogger.TIMER:
            # 時間計測の場合
            self.note_ctrl.SetBackgroundColour("YELLOW")
        elif not is_saving:
            # ログありの場合、色変え
            self.note_ctrl.SetBackgroundColour("BLUE")
        elif is_out_log:
            # ログありの場合、色変え
            self.note_ctrl.SetBackgroundColour("AQUAMARINE")
        else:
            self.note_ctrl.SetBackgroundColour(
                wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW))

        # ---------------------------------------------

        # 全親タブ
        self.parent_panel_ctrl = ParentPanel(self, self.note_ctrl, 9)
        self.note_ctrl.AddPage(self.parent_panel_ctrl, u"全親移植", False)

        # ゆらぎタブ
        self.noise_panel_ctrl = NoisePanel(self, self.note_ctrl, 9)
        self.note_ctrl.AddPage(self.noise_panel_ctrl, u"ゆらぎ複製", False)

        # 多段分割タブ
        self.multi_split_panel_ctrl = MultiSplitPanel(self, self.note_ctrl, 9)
        self.note_ctrl.AddPage(self.multi_split_panel_ctrl, u"多段分割", False)

        # 多段統合タブ
        self.multi_join_panel_ctrl = MultiJoinPanel(self, self.note_ctrl, 9)
        self.note_ctrl.AddPage(self.multi_join_panel_ctrl, u"多段統合", False)

        # 足FK2FKタブ
        self.leg_fk2ik_panel_ctrl = LegFKtoIKPanel(self, self.note_ctrl, 9)
        self.note_ctrl.AddPage(self.leg_fk2ik_panel_ctrl, u"足FKtoIK", False)

        # スムーズタブ
        self.smooth_panel_ctrl = SmoothPanel(self, self.note_ctrl, 5)
        self.note_ctrl.AddPage(self.smooth_panel_ctrl, u"スムーズ", False)

        # ブレンドタブ
        self.blend_panel_ctrl = BlendPanel(self, self.note_ctrl, 6)
        self.note_ctrl.AddPage(self.blend_panel_ctrl, u"ブレンド", False)

        # 補間タブ
        self.bezier_panel_ctrl = BezierPanel(self, self.note_ctrl, 9)
        self.note_ctrl.AddPage(self.bezier_panel_ctrl, u"補間", False)

        # # 腕IKtoFKタブ
        # self.arm_ik2fk_panel_ctrl = ArmIKtoFKPanel(self, self.note_ctrl, 9)
        # self.note_ctrl.AddPage(self.arm_ik2fk_panel_ctrl, u"腕IKtoFK", False)

        # ---------------------------------------------

        # タブ押下時の処理
        self.note_ctrl.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_tab_change)

        # ---------------------------------------------

        bSizer1.Add(self.note_ctrl, 1, wx.EXPAND, 5)

        # デフォルトの出力先はファイルタブのコンソール
        sys.stdout = self.parent_panel_ctrl.console_ctrl

        self.SetSizer(bSizer1)
        self.Layout()

        self.Centre(wx.BOTH)
Esempio n. 23
0
    def blend_morph(self):
        # モーションVMDディレクトリパス
        pmx_dir_path = MFileUtils.get_dir_path(self.options.model.path)
        # モーションVMDファイル名・拡張子
        pmx_file_name, pmx_ext = os.path.splitext(
            os.path.basename(self.options.model.path))

        dt_now = datetime.now()

        blend_fpath = "{0}\\{1}_blend_{2:%Y%m%d_%H%M%S}.vmd".format(
            pmx_dir_path, pmx_file_name, dt_now)

        bone_motion = VmdMotion()

        # 処理対象モーフ名(文字列)
        target_morphs = self.options.eye_list + self.options.eyebrow_list + self.options.lip_list + self.options.other_list

        # 処理対象モーフデータ
        all_morphs = []
        for mk, mv in self.options.model.morphs.items():
            if mv.display and mv.name in target_morphs:
                all_morphs.append(mv)
                bone_motion.morphs[mk] = {}

        # 変化量(少ない方のの割合を多くする)
        ratio_values = [self.options.inc_value * x for x in range(math.ceil(self.options.min_value / self.options.inc_value), \
                        math.ceil(self.options.max_value / self.options.inc_value) + 1) if self.options.min_value <= self.options.inc_value * x <= self.options.max_value]
        ratio_lower_values = [self.options.inc_value * x for x in range(math.ceil(self.options.min_value / self.options.inc_value), \
                              math.ceil(self.options.max_value / self.options.inc_value / 2) + 1) if self.options.min_value <= self.options.inc_value * x <= self.options.max_value]
        ratio_zero_values = [0 for x in range(len(all_morphs))]

        # 全体の比率増減量
        ratio_total_values = copy.deepcopy(ratio_values)
        ratio_total_values.extend(ratio_lower_values)
        ratio_total_values.extend(ratio_lower_values)
        ratio_total_values.extend(ratio_zero_values)

        # モーフの組合せ数
        morph_comb_cnt = 1
        # 変化量の組合せ数
        ratio_product_cnt = 1
        for n in range(len(all_morphs), 0, -1):
            morph_comb_cnt *= n
            ratio_product_cnt *= len(ratio_values)

        morph_total_cnt = 0

        if morph_comb_cnt * ratio_product_cnt <= 1000:
            # モーフの組合せ
            morph_comb = list(
                itertools.combinations(all_morphs, len(all_morphs)))
            logger.debug("morph_comb: %s", len(morph_comb))

            # 変化量の直積(同じ値を許容する)
            ratio_product = list(
                itertools.product(ratio_values, repeat=len(all_morphs)))
            logger.debug("ratio_product: %s", len(ratio_product))

            # 組合せが1000以下なら組合せをそのまま出力
            brend_mr_pairs_list = list(
                itertools.product(morph_comb, ratio_product))
            logger.debug("brend_mr_pairs_list: %s", len(brend_mr_pairs_list))

            for mframe, (morphs, ratios) in enumerate(brend_mr_pairs_list):
                # 上限までしか登録しない
                if morph_total_cnt > 19000:
                    break

                for morph, ratio in zip(morphs, ratios):
                    vmd_morph = VmdMorphFrame()
                    vmd_morph.fno = mframe
                    vmd_morph.set_name(morph.name)
                    vmd_morph.ratio = ratio
                    vmd_morph.key = True

                    bone_motion.morphs[morph.name][mframe] = vmd_morph
                    logger.test(vmd_morph)

                    morph_total_cnt += 1

        else:
            # 組合せが1000より多い場合、ランダム
            for mframe in range(1000):
                # 上限までしか登録しない
                if morph_total_cnt > 19000:
                    break

                for morph in all_morphs:
                    ratio = ratio_total_values[random.randint(
                        0,
                        len(ratio_values) - 1)]

                    vmd_morph = VmdMorphFrame()
                    vmd_morph.fno = mframe
                    vmd_morph.set_name(morph.name)
                    vmd_morph.ratio = ratio
                    vmd_morph.key = True

                    bone_motion.morphs[morph.name][mframe] = vmd_morph
                    logger.test(vmd_morph)

                    morph_total_cnt += 1

        data_set = MOptionsDataSet(bone_motion, self.options.model,
                                   self.options.model, blend_fpath, False,
                                   False, [], None, 0, [])

        VmdWriter(data_set).write()

        logger.info("モーフブレンドVMD: %s",
                    blend_fpath,
                    decoration=MLogger.DECORATION_BOX)

        return True
Esempio n. 24
0
from form.MainFrame import MainFrame
from utils.MLogger import MLogger
from utils import MFileUtils
from utils.MException import SizingException

VERSION_NAME = "1.02"

# 指数表記なし、有効小数点桁数6、30を超えると省略あり、一行の文字数200
np.set_printoptions(suppress=True, precision=6, threshold=30, linewidth=200)

# Windowsマルチプロセス対策
multiprocessing.freeze_support()

if __name__ == '__main__':
    mydir_path = MFileUtils.get_mydir_path(sys.argv[0])

    if len(sys.argv) > 3 and "--motion_path" in sys.argv:
        if os.name == "nt":
            import winsound  # Windows版のみインポート

        # 引数指定がある場合、コマンドライン実行
        # try:
        #     SizingService(MOptions.parse(VERSION_NAME)).execute()
        # except SizingException as se:
        #     print("サポーター処理が処理できないデータで終了しました。\n\n%s", se.message)
        # except Exception:
        #     print("サポーター処理が意図せぬエラーで終了しました。")
        #     print(traceback.format_exc())
        # finally:
        #     logging.shutdown()
Esempio n. 25
0
    def on_convert(self, event: wx.Event):
        self.timer.Stop()
        self.Unbind(wx.EVT_TIMER, id=TIMER_ID)
        # フォーム無効化
        self.disable()
        # タブ固定
        self.fix_tab()
        # コンソールクリア
        self.console_ctrl.Clear()
        # 出力先を多段統合パネルのコンソールに変更
        sys.stdout = self.console_ctrl

        self.vmd_file_ctrl.save()
        self.model_file_ctrl.save()

        # JSON出力
        MFileUtils.save_history(self.frame.mydir_path,
                                self.frame.file_hitories)

        self.elapsed_time = 0
        result = True
        result = self.vmd_file_ctrl.is_valid() and result
        result = self.model_file_ctrl.is_valid() and result

        if len(self.bone_target_txt_ctrl.GetValue()) == 0:
            logger.error("統合対象ボーンが指定されていません。",
                         decoration=MLogger.DECORATION_BOX)
            result = False

        if not result:
            # 終了音
            self.frame.sound_finish()
            # タブ移動可
            self.release_tab()
            # フォーム有効化
            self.enable()

            return result

        # 多段統合変換開始
        if self.multi_join_btn_ctrl.GetLabel(
        ) == "多段統合停止" and self.convert_multi_join_worker:
            # フォーム無効化
            self.disable()
            # 停止状態でボタン押下時、停止
            self.convert_multi_join_worker.stop()

            # タブ移動可
            self.frame.release_tab()
            # フォーム有効化
            self.frame.enable()
            # ワーカー終了
            self.convert_multi_join_worker = None
            # プログレス非表示
            self.gauge_ctrl.SetValue(0)

            logger.warning("多段統合を中断します。", decoration=MLogger.DECORATION_BOX)
            self.multi_join_btn_ctrl.SetLabel("多段統合")

            event.Skip(False)
        elif not self.convert_multi_join_worker:
            # フォーム無効化
            self.disable()
            # タブ固定
            self.fix_tab()
            # コンソールクリア
            self.console_ctrl.Clear()
            # ラベル変更
            self.multi_join_btn_ctrl.SetLabel("多段統合停止")
            self.multi_join_btn_ctrl.Enable()

            self.convert_multi_join_worker = MultiJoinWorkerThread(
                self.frame, MultiJoinThreadEvent, self.frame.is_saving,
                self.frame.is_out_log)
            self.convert_multi_join_worker.start()

            event.Skip()
        else:
            logger.error("まだ処理が実行中です。終了してから再度実行してください。",
                         decoration=MLogger.DECORATION_BOX)
            event.Skip(False)

        return result
Esempio n. 26
0
    def convert_vmd(self):
        dt_now = datetime.now()

        bone_fpath = None
        bone_motion = VmdMotion()

        if self.options.bone_csv_path and os.path.exists(
                self.options.bone_csv_path):
            # ボーンモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(
                self.options.bone_csv_path)
            # ボーンモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(
                os.path.basename(self.options.bone_csv_path))

            bone_fpath = "{0}\\{1}_bone_{2:%Y%m%d_%H%M%S}.vmd".format(
                motion_csv_dir_path, motion_csv_file_name, dt_now)

            # ボーンCSV読み込み
            with open(self.options.bone_csv_path, encoding='cp932',
                      mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for ridx, row in enumerate(reader):
                    bf = VmdBoneFrame()
                    rno = ridx + 1

                    try:
                        if len(row) < 0 or not row[0]:
                            logger.error("[ボーン] %s行目のボーン名(1列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # ボーン名
                        bf.set_name(row[0])
                    except Exception as e:
                        logger.error("[ボーン] %s行目のボーン名の読み取りに失敗しました\n%s",
                                     rno,
                                     e,
                                     decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 1 or not row[1]:
                            logger.error("[ボーン] %s行目のフレーム番号(2列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # フレーム
                        bf.fno = int(float(row[1]))

                        if bf.fno < 0:
                            logger.error("[ボーン] %s行目のフレーム番号(2列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目のフレーム番号の読み取りに失敗しました\nフレーム番号は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 4 or not row[2] or not row[3] or not row[4]:
                            logger.error("[ボーン] %s行目の位置(3-5列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 位置
                        bf.position = MVector3D(float(row[2]), float(row[3]),
                                                float(row[4]))
                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目の位置の読み取りに失敗しました\n位置は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 7 or not row[5] or not row[6] or not row[7]:
                            logger.error("[ボーン] %s行目の回転(6-8列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 回転
                        bf.rotation = MQuaternion.fromEulerAngles(
                            float(row[5]),
                            float(row[6]) * -1,
                            float(row[7]) * -1)
                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目の回転の読み取りに失敗しました\n位置は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 71:
                            logger.error(
                                "[ボーン] %s行目の補間曲線(9-72列目)のいずれかが設定されていません",
                                rno,
                                decoration=MLogger.DECORATION_BOX)
                            return False

                        for cidx in range(8, 72):
                            if not row[cidx]:
                                logger.error("[ボーン] %s行目の補間曲線の%s番目が設定されていません",
                                             rno,
                                             cidx - 7,
                                             decoration=MLogger.DECORATION_BOX)
                                return False

                        # 補間曲線(一旦floatで読み込んで指数等も読み込んだ後、intに変換)
                        bf.interpolation = [int(float(row[8])), int(float(row[9])), int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), \
                                            int(float(row[14])), int(float(row[15])), int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), \
                                            int(float(row[20])), int(float(row[21])), int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), \
                                            int(float(row[26])), int(float(row[27])), int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), \
                                            int(float(row[32])), int(float(row[33])), int(float(row[34])), int(float(row[35])), int(float(row[36])), int(float(row[37])), \
                                            int(float(row[38])), int(float(row[39])), int(float(row[40])), int(float(row[41])), int(float(row[42])), int(float(row[43])), \
                                            int(float(row[44])), int(float(row[45])), int(float(row[46])), int(float(row[47])), int(float(row[48])), int(float(row[49])), \
                                            int(float(row[50])), int(float(row[51])), int(float(row[52])), int(float(row[53])), int(float(row[54])), int(float(row[55])), \
                                            int(float(row[56])), int(float(row[57])), int(float(row[58])), int(float(row[59])), int(float(row[60])), int(float(row[61])), \
                                            int(float(row[62])), int(float(row[63])), int(float(row[64])), int(float(row[65])), int(float(row[66])), int(float(row[67])), \
                                            int(float(row[68])), int(float(row[69])), int(float(row[70])), int(float(row[71]))]

                        for bidx, bi in enumerate(bf.interpolation):
                            if 0 > bi:
                                logger.error(
                                    "[ボーン] %s行目の補間曲線(%s列目)に負数が設定されています",
                                    rno,
                                    bidx + 9,
                                    decoration=MLogger.DECORATION_BOX)
                                return False

                    except Exception as e:
                        logger.error(
                            "[ボーン] %s行目の補間曲線の読み取りに失敗しました\n位置は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    bf.read = True
                    bf.key = True

                    if bf.name not in bone_motion.bones:
                        bone_motion.bones[bf.name] = {}

                    bone_motion.bones[bf.name][bf.fno] = bf

                    cnt += 1

                    if cnt % 10000 == 0:
                        logger.info("[ボーン] %sキー目:終了", cnt)

        if self.options.morph_csv_path and os.path.exists(
                self.options.morph_csv_path):
            # モーフモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(
                self.options.morph_csv_path)
            # モーフモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(
                os.path.basename(self.options.morph_csv_path))

            if not bone_fpath:
                bone_fpath = "{0}\\{1}_morph_{2:%Y%m%d_%H%M%S}.vmd".format(
                    motion_csv_dir_path, motion_csv_file_name, dt_now)

            # モーフCSV読み込み
            with open(self.options.morph_csv_path, encoding='cp932',
                      mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for ridx, row in enumerate(reader):
                    mf = VmdMorphFrame()
                    rno = ridx + 1

                    try:
                        if len(row) < 0 or not row[0]:
                            logger.error("[モーフ] %s行目のモーフ名(1列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # ボーン名
                        mf.set_name(row[0])
                    except Exception as e:
                        logger.error("[モーフ] %s行目のモーフ名の読み取りに失敗しました\n%s",
                                     rno,
                                     e,
                                     decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 1 or not row[1]:
                            logger.error("[モーフ] %s行目のフレーム番号(2列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # フレーム
                        mf.fno = int(float(row[1]))

                        if mf.fno < 0:
                            logger.error("[モーフ] %s行目のフレーム番号(2列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False
                    except Exception as e:
                        logger.error(
                            "[モーフ] %s行目のフレーム番号の読み取りに失敗しました\nフレーム番号は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 2 or not row[2]:
                            logger.error("[モーフ] %s行目の大きさ(3列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 値
                        mf.ratio = float(row[2])
                    except Exception as e:
                        logger.error(
                            "[モーフ] %s行目の大きさの読み取りに失敗しました\n大きさは半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    if mf.name not in bone_motion.morphs:
                        bone_motion.morphs[mf.name] = {}

                    bone_motion.morphs[mf.name][mf.fno] = mf

                    cnt += 1

                    if cnt % 1000 == 0:
                        logger.info("[モーフ] %sキー目:終了", cnt)

        if len(bone_motion.bones.keys()) > 0 or len(
                bone_motion.morphs.keys()) > 0:
            # ボーンかモーフのキーがある場合、まとめて出力

            model = PmxModel()
            model.name = "CSV Convert Model"
            data_set = MOptionsDataSet(bone_motion, model, model, bone_fpath,
                                       False, False, [], None, 0, [])

            VmdWriter(data_set).write()

            logger.info("ボーン・モーフモーションVMD: %s",
                        bone_fpath,
                        decoration=MLogger.DECORATION_BOX)

        if self.options.camera_csv_path and os.path.exists(
                self.options.camera_csv_path):
            # カメラモーションCSVディレクトリパス
            motion_csv_dir_path = MFileUtils.get_dir_path(
                self.options.camera_csv_path)
            # カメラモーションCSVファイル名・拡張子
            motion_csv_file_name, _ = os.path.splitext(
                os.path.basename(self.options.camera_csv_path))

            camera_fpath = "{0}\\{1}_camera_{2:%Y%m%d_%H%M%S}.vmd".format(
                motion_csv_dir_path, motion_csv_file_name, dt_now)
            camera_motion = VmdMotion()

            # カメラCSV読み込み
            with open(self.options.camera_csv_path, encoding='cp932',
                      mode='r') as f:
                reader = csv.reader(f)
                next(reader)  # ヘッダーを読み飛ばす

                cnt = 0
                for ridx, row in enumerate(reader):
                    cf = VmdCameraFrame()
                    rno = ridx + 1

                    try:
                        if len(row) < 1 or not row[0]:
                            logger.error("[カメラ] %s行目のフレーム番号(1列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # フレーム
                        cf.fno = int(row[0])

                        if cf.fno < 0:
                            logger.error("[カメラ] %s行目のフレーム番号(1列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目のフレーム番号の読み取りに失敗しました\nフレーム番号は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 3 or not row[1] or not row[2] or not row[3]:
                            logger.error("[カメラ] %s行目の位置(2-4列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 位置
                        cf.position = MVector3D(float(row[1]), float(row[2]),
                                                float(row[3]))
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の位置の読み取りに失敗しました\n位置は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row
                               ) < 6 or not row[4] or not row[5] or not row[6]:
                            logger.error("[カメラ] %s行目の回転(5-7列目)のいずれかが設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 回転(オイラー角)
                        cf.euler = MVector3D(float(row[4]), float(row[5]),
                                             float(row[6]))
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の回転の読み取りに失敗しました\n回転は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 7 or not row[7]:
                            logger.error("[カメラ] %s行目の距離(8列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 距離
                        cf.length = -(float(row[7]))
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の距離の読み取りに失敗しました\n距離は半角数字・符号・小数点のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 8 or not row[8]:
                            logger.error("[カメラ] %s行目の視野角(9列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # 視野角
                        cf.angle = int(row[8])

                        if cf.angle < 0:
                            logger.error("[カメラ] %s行目の視野角(9列目)に負数が設定されています",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の視野角の読み取りに失敗しました\n視野角は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 8 or not row[9]:
                            logger.error("[カメラ] %s行目のパース(10列目)が設定されていません",
                                         rno,
                                         decoration=MLogger.DECORATION_BOX)
                            return False

                        # パース
                        cf.perspective = int(row[9])

                        if cf.perspective not in [0, 1]:
                            logger.error(
                                "[カメラ] %s行目のパース(10列目)に0, 1以外の値が設定されています",
                                rno,
                                decoration=MLogger.DECORATION_BOX)
                            return False
                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目のパースの読み取りに失敗しました\nパースは0, 1のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    try:
                        if len(row) < 33:
                            logger.error(
                                "[カメラ] %s行目の補間曲線(11-34列目)のいずれかが設定されていません",
                                rno,
                                decoration=MLogger.DECORATION_BOX)
                            return False

                        for cidx in range(10, 34):
                            if not row[cidx]:
                                logger.error("[カメラ] %s行目の補間曲線の%s番目が設定されていません",
                                             rno,
                                             cidx - 9,
                                             decoration=MLogger.DECORATION_BOX)
                                return False

                        # 補間曲線(一旦floatで読み込んで指数等も読み込んだ後、intに変換)
                        cf.interpolation = [int(float(row[10])), int(float(row[11])), int(float(row[12])), int(float(row[13])), int(float(row[14])), int(float(row[15])), \
                                            int(float(row[16])), int(float(row[17])), int(float(row[18])), int(float(row[19])), int(float(row[20])), int(float(row[21])), \
                                            int(float(row[22])), int(float(row[23])), int(float(row[24])), int(float(row[25])), int(float(row[26])), int(float(row[27])), \
                                            int(float(row[28])), int(float(row[29])), int(float(row[30])), int(float(row[31])), int(float(row[32])), int(float(row[33]))]

                        for cidx, ci in enumerate(cf.interpolation):
                            if 0 > ci:
                                logger.error(
                                    "[カメラ] %s行目の補間曲線(%s列目)に負数が設定されています",
                                    rno,
                                    cidx + 11,
                                    decoration=MLogger.DECORATION_BOX)
                                return False

                    except Exception as e:
                        logger.error(
                            "[カメラ] %s行目の補間曲線の読み取りに失敗しました\n位置は半角数字のみ入力可能です。\n%s",
                            rno,
                            e,
                            decoration=MLogger.DECORATION_BOX)
                        return False

                    camera_motion.cameras[cf.fno] = cf

                    cnt += 1

                    if cnt % 500 == 0:
                        logger.info("[カメラ] %sキー目:終了", cnt)

            if len(camera_motion.cameras) > 0:
                # ボーンかモーフのキーがある場合、まとめて出力

                model = PmxModel()
                model.name = "カメラ・照明"
                data_set = MOptionsDataSet(camera_motion, model, model,
                                           camera_fpath, False, False, [],
                                           None, 0, [])

                VmdWriter(data_set).write()

                logger.info("カメラモーションVMD: %s",
                            camera_fpath,
                            decoration=MLogger.DECORATION_BOX)

        return True