AnalysisDialog.cpp

#include "StdAfx.h"
#include "AnalysisDialog.h"


#include "Motion.h"
#include "Pose.h"

#include "Model.h"
#include "Link.h"

#include "Torque.h"
#include "ListViewItemComparer.h"


using namespace Core;
using namespace Robotics;

using namespace System;
using namespace System::Diagnostics;


/// [ Constructor ]
AnalysisDialog::AnalysisDialog( void )
{
    // コンポーネントを初期化する
    InitializeComponent();
}

/// [ Destructor ]
AnalysisDialog::~AnalysisDialog()
{
    if( components != nullptr )
    {
        delete components;
    }
}


#pragma region Windows Form Designer generated code
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
void AnalysisDialog::InitializeComponent(void)
{
    this->m_listView = (gcnew System::Windows::Forms::ListView());
    this->m_nameHeader = (gcnew System::Windows::Forms::ColumnHeader());
    this->m_maximumTorqueHeader = (gcnew System::Windows::Forms::ColumnHeader());
    this->m_operationalAngleHeader = (gcnew System::Windows::Forms::ColumnHeader());
    this->m_maximumAngularVelocityHeader = (gcnew System::Windows::Forms::ColumnHeader());
    this->SuspendLayout();
    //
    // m_listView
    //
    this->m_listView->Columns->AddRange(gcnew cli::array< System::Windows::Forms::ColumnHeader^ >(4) {this->m_nameHeader, this->m_operationalAngleHeader,
        this->m_maximumAngularVelocityHeader, this->m_maximumTorqueHeader});
    this->m_listView->Dock = System::Windows::Forms::DockStyle::Fill;
    this->m_listView->Location = System::Drawing::Point(0, 0);
    this->m_listView->MultiSelect = false;
    this->m_listView->Name = L"m_listView";
    this->m_listView->Size = System::Drawing::Size(492, 472);
    this->m_listView->TabIndex = 1;
    this->m_listView->UseCompatibleStateImageBehavior = false;
    this->m_listView->View = System::Windows::Forms::View::Details;
    this->m_listView->ColumnClick += gcnew System::Windows::Forms::ColumnClickEventHandler(this, &AnalysisDialog::ListViewColumnClick);
    //
    // m_nameHeader
    //
    this->m_nameHeader->Text = L"名称";
    this->m_nameHeader->Width = 80;
    //
    // m_maximumTorqueHeader
    //
    this->m_maximumTorqueHeader->Text = L"最大トルク [Nm]";
    this->m_maximumTorqueHeader->TextAlign = System::Windows::Forms::HorizontalAlignment::Right;
    this->m_maximumTorqueHeader->Width = 120;
    //
    // m_operationalAngleHeader
    //
    this->m_operationalAngleHeader->Text = L"動作角度 [deg]";
    this->m_operationalAngleHeader->TextAlign = System::Windows::Forms::HorizontalAlignment::Right;
    this->m_operationalAngleHeader->Width = 120;
    //
    // m_maximumAngularVelocityHeader
    //
    this->m_maximumAngularVelocityHeader->Text = L"最大角速度 [deg/sec]";
    this->m_maximumAngularVelocityHeader->TextAlign = System::Windows::Forms::HorizontalAlignment::Right;
    this->m_maximumAngularVelocityHeader->Width = 140;
    //
    // AnalysisDialog
    //
    this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
    this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
    this->ClientSize = System::Drawing::Size(492, 472);
    this->Controls->Add(this->m_listView);
    this->MaximizeBox = false;
    this->MinimizeBox = false;
    this->Name = L"AnalysisDialog";
    this->ShowIcon = false;
    this->ShowInTaskbar = false;
    this->Text = L"分析";
    this->ResumeLayout(false);

}
#pragma endregion


/// 表示する
void AnalysisDialog::Show( Motion^ motion, Model^ model )
{
    Debug::Assert( model != nullptr, "モデルは生成されている" );


    // モデルから リンクを取得する
    Links^ links = model->Links;

    // ... 動作角度を取得する
    array< Robotics::AngleRange >^ operationalAngle = GetOperationalAngle( motion, links->Length );

    // ... 角速度の最大値を取得する
    array< double >^ maximumAngularVelocity = GetMaximumAngularVelocity( motion, links->Length );

    // トルクの最大値を取得する
    array< double >^ maximumTorque = GetMaximumTorque( motion, model );


    // 全てのリンクの リストの項目を生成する
    for( int i = 1; i < links->Length; i++ )
    {
        // リンクの名称を与えて リストの項目を生成する
        Windows::Forms::ListViewItem^ item = gcnew Windows::Forms::ListViewItem( links[ i ]->Name );
        Windows::Forms::ListViewItem::ListViewSubItemCollection^ subItem = item->SubItems;  // サブ項目


        // ... 動作角度を Degreeに変換して追加する
        subItem->Add( Angle::CalculateDegree( operationalAngle[ i ].Size ).ToString( "0.0" ) );

        // ... 角速度の最大値を Degreeに変換して追加する
        subItem->Add( Angle::CalculateDegree( maximumAngularVelocity[ i ] ).ToString( "0.0" ) );

        // ... トルクの最大値を追加する
        subItem->Add( maximumTorque[ i ].ToString( "0.000" ) );


        // 項目をリストビューに追加する
        m_listView->Items->Add( item );
    }


    // リストビュー アイテムの比較クラスを生成する
    m_listViewItemComparer = gcnew ListViewItemComparer();

    // ... それをリストビューの並べ替えの方法として指定する
    m_listView->ListViewItemSorter = m_listViewItemComparer;


    // フォームを表示する
    this->ShowDialog();
}

/// リストビューの列がクリックされた
System::Void AnalysisDialog::ListViewColumnClick( System::Object^, System::Windows::Forms::ColumnClickEventArgs^ e )
{
    // クリックされた列を 並べ替えの対象として設定する
    m_listViewItemComparer->Column = e->Column;

    // ... リストビューを並べ替える
    m_listView->Sort();
}


/// 動作角度を取得する
array< Robotics::AngleRange >^ AnalysisDialog::GetOperationalAngle( Motion^ motion, int linkSum )
{
    // 角度の範囲を格納する配列を リンク数だけ生成する
    array< Robotics::AngleRange >^ result = gcnew array< AngleRange >( linkSum );

    for( int i = 0; i < linkSum; i++ )
    {
        // 範囲を 下限を最も大きな値、上限を最も小さな値で初期化する
        result[ i ] = AngleRange( Double::MaxValue, Double::MinValue );
    }


    // 全てのポーズの 速度を取得する
    for( int k = 0; k < motion->PoseCount; k++ )
    {
        Angles^ angles = motion[ k ]->AngleOfJoints;    // 各関節の角度

        // 胴体以外の全てのリンクについて、現在の値と比較する
        for( int i = 1; i < linkSum; i++ )
        {
            result[ i ].ExpandRange( angles[ i ] );
        }
    }
    return result;
}

/// 角速度の最大値を取得する
array< double >^ AnalysisDialog::GetMaximumAngularVelocity( Motion^ motion, int linkSum )
{
    // トルクの最大値を格納する配列を リンク数だけ生成する
    array< double >^ result = gcnew array< double >( linkSum );


    // 全てのポーズの 角速度を取得する
    for( int k = 0; k < motion->PoseCount; k++ )
    {
        AngularVelocities^ angularVelocities = motion->GetAngularVelocities( k ); // 各関節の角速度

        // 胴体以外の全てのリンクについて、現在の値と比較する
        for( int i = 1; i < linkSum; i++ )
        {
            if( result[ i ] < angularVelocities[ i ] )
            {
                // 現在の値を越えるならば、その値に更新する
                result[ i ] = angularVelocities[ i ];
            }
        }
    }
    return result;
}

/// トルクの最大値を取得する
array< double >^ AnalysisDialog::GetMaximumTorque( Motion^ motion, Model^ model )
{
    // モデルから リンクを取得する
    Links^ links = model->Links;

    // ... トルクの最大値を格納する配列を リンク数だけ生成する
    array< double >^ result = gcnew array< double >( links->Length );


    // モデルに モーション中の全てのポーズをとらせる
    for( int k = 0; k < motion->PoseCount; k++ )
    {
        // モデルにポーズをとらせる
        motion[ k ]->PosedModel( model );

        // ... その状態におけるモデルの トルクを生成する
        Torque^ torque = gcnew Torque( model );


        // 胴体以外の 全てのリンクについて、現在の値と比較する
        for( int i = 1; i < links->Length; i++ )
        {
            // リンクの トルクの絶対値
            double linkTorque = Math::Abs( torque[ links[ i ] ] );

            if( result[ i ] < linkTorque )
            {
                // 現在の値を越えるならば、その値に更新する
                result[ i ] = linkTorque;
            }
        }
    }
    // モデルに 現在のポーズをとらせる
    motion->CurrentPose->PosedModel( model );

    return result;
}