Shape.cpp

#include "StdAfx.h"
#include "Shape.h"

#include "XFile.h"


using namespace Core;
using namespace Robotics;

using namespace Microsoft;

using namespace System;
using namespace System::Diagnostics;


/// [ Constructor ]
Shape::Shape( Robotics::Size size, Robotics::PositionVector^ relativePosition ) :
    m_size( size ),
    m_relativePosition( relativePosition )
{
}

/// XMLから生成する [ Constructor ]
Shape::Shape( System::Xml::XmlElement^ element ) :
    m_size( 0.0, 0.0, 0.0 )
{
    if( element == nullptr )
    {
        // 要素が存在しないならば、相対位置をゼロで初期化する
        m_relativePosition = gcnew PositionVector( 0.0, 0.0, 0.0 );
    }
    else
    {
        m_size = Robotics::Size( element );                     // 大きさ
        m_relativePosition = gcnew PositionVector( element );   // 相対位置
    }
}

/// [ Finalizer ]
Shape::!Shape()
{
    delete m_simpleFigure;
}


/// 生成する
Shape^ Shape::Create( System::Xml::XmlElement^ element )
{
    // 要素を取得する
    Xml::XmlElement^ node = element[ "shape" ];

    // ... 生成して返す
    return gcnew Shape( node );
}


/// 頂点の相対位置を取得する [ Property ]
PositionVectors^ Shape::RelativePositionOfVertices::get()
{
    PositionVectors^ result = gcnew PositionVectors( VertexSum );

    // 形状の半分の大きさを定義する
    Robotics::Size size = m_size / 2.0;

    // 下面の4点を生成する
    result[ 0 ] = gcnew PositionVector( -size.X, -size.Y, -size.Z );
    result[ 1 ] = gcnew PositionVector( -size.X, +size.Y, -size.Z );
    result[ 2 ] = gcnew PositionVector( +size.X, +size.Y, -size.Z );
    result[ 3 ] = gcnew PositionVector( +size.X, -size.Y, -size.Z );

    // 上面の4点を生成する
    result[ 4 ] = gcnew PositionVector( -size.X, -size.Y, +size.Z );
    result[ 5 ] = gcnew PositionVector( -size.X, +size.Y, +size.Z );
    result[ 6 ] = gcnew PositionVector( +size.X, +size.Y, +size.Z );
    result[ 7 ] = gcnew PositionVector( +size.X, -size.Y, +size.Z );


    // ... 相対位置に補正する
    for each( PositionVector^ positionVector in result )
    {
        positionVector += m_relativePosition;
    }
    return result;
}


/// 頂点の絶対位置を取得する
PositionVectors^ Shape::GetAbsolutePositionOfVertices( Robotics::Vector^ position, Robotics::RotationMatrix^ posture )
{
    PositionVectors^ result = gcnew PositionVectors( VertexSum );
    PositionVectors^ relativePositionOfVertices = RelativePositionOfVertices;   // 頂点の相対位置

    for( int i = 0; i < result->Length; i++ )
    {
        // 指定された位置に、姿勢と頂点の相対位置の積から求めた位置を加算する
        result[ i ] = position + ( posture * relativePositionOfVertices[ i ] );
    }
    return result;
}


/// インスタンスの説明を文字列で返す
System::String^ Shape::ToString()
{
    return m_size.ToString();
}


/// 図形を生成する
void Shape::CreateFigure( Microsoft::DirectX::Direct3D::Device^ device )
{
    if( !m_size.IsZero() )
    {
        // 大きさを持つならば、標準メッシュから図形を生成する
        m_simpleFigure = DirectX::Direct3D::Mesh::Box(
            device,
            safe_cast< float >( m_size.X ),
            safe_cast< float >( m_size.Y ),
            safe_cast< float >( m_size.Z )
            );
    }


    // 名称と同じファイル名を指定する
    String^ fileName = Name + ".x";

    // @note 作業フォルダから読み込む。

    if( IO::File::Exists( fileName ) )
    {
        // ファイルが存在するならば、Xファイルから読み込む
        m_realFigure = gcnew XFile( device, fileName );
    }
}


/// シンプルな形状を描画する
void Shape::RenderSimpleFigure( Microsoft::DirectX::Direct3D::Device^ device )
{
    // サイズがあることを確認する
    if( !m_size.IsZero() )
    {
        Debug::Assert( Figure == m_simpleFigure, "識別の図形に設定されている" );

        // マテリアルを設定する
        SetupMaterial( device );

        // ワールド座標を保存する
        DirectX::Matrix worldMatrix = device->Transform->World;


        // 相対位置に移動する
        WorldTransformOfFigure
            = DirectX::Matrix::Translation(
                safe_cast< float >( m_relativePosition->X ),
                safe_cast< float >( m_relativePosition->Y ),
                safe_cast< float >( m_relativePosition->Z )
                )
            * worldMatrix;

        // ... それをワールド座標に設定する
        device->Transform->World = WorldTransformOfFigure;

        // レンダリングする
        m_simpleFigure->DrawSubset( 0 );


        // ワールド座標を元に戻す
        device->Transform->World = worldMatrix;
    }
}

/// リアルな形状を描画する
void Shape::RenderRealFigure( Microsoft::DirectX::Direct3D::Device^ device )
{
    if( m_realFigure != nullptr )
    {
        Debug::Assert( Figure == m_realFigure->Mesh, "識別の図形に設定されている" );


        // ワールド座標を保存する
        WorldTransformOfFigure = device->Transform->World;

        // ... 描画する
        m_realFigure->Render( device );
    }
}


/// 表示モードを設定する
void Shape::SetExpressionMode( ExpressionModel expressionModel )
{
    // ピッキングによる認識を有効にするために、識別の図形に設定する
    switch( expressionModel )
    {
        case ExpressionModel::MechanismModel:   // 機構モデル

            // シンプルな形状を設定する
            Figure = m_simpleFigure;
            break;

        case ExpressionModel::RealModel:        // リアル モデル

            // リアルな形状を設定する
            Figure = ( m_realFigure != nullptr )? m_realFigure->Mesh : nullptr;
            break;

        default:
            Debug::Fail( "無効な表示モードが指定された" );
    }
}