Vector.cpp
#include "Vector.h"
#include "Matrix.h"
using namespace Robotics;
using namespace System;
using namespace System::Diagnostics;
/// 指定された次元で生成し 零ベクトルで初期化する [ Constructor ]
Vector::Vector( int dimension )
{
// 領域を確保する
SecureDomain( dimension );
Debug::Assert( Dimension == dimension, "次元は指定値に設定されている" );
#ifdef _DEBUG
for( int i=0; i<Dimension; i++ )
{
Debug::Assert( m_components[ i ] == 0.0, "零ベクトルに初期化されている" );
}
/// @note
/// 零ベクトルの判定を行う関数は、比較用に零ベクトルを作成するとき
/// このコンストラクタを呼び出す。よって、ここでその関数を呼び出すと
/// 再帰してしまう。
#endif
}
/// 指定された次元で生成し 引数の配列で初期化する [ Constructor ]
Vector::Vector( const double* val, int dimension )
{
// 領域を確保する
SecureDomain( dimension );
for( int i=0; i<Dimension; i++ )
{
m_components[ i ] = val[ i ];
}
Debug::Assert( Dimension == dimension, "次元は指定値に設定されている" );
}
/// コピー元と同次元で生成し それの成分で初期化する [ Copy constructor ]
Vector::Vector( Vector^ other )
{
// 領域を確保する
SecureDomain( other->Dimension );
for( int i=0; i<Dimension; i++ )
{
m_components[ i ] = other->m_components[ i ];
}
Debug::Assert( Dimension == other->Dimension, "次元はコピー元と同じに設定されている" );
}
/// 指定された次元で領域を確保する
void Vector::SecureDomain( int dimension )
{
Debug::Assert( 1 <= dimension, "次元は自然数である" );
// メモリ領域を確保する
m_components = gcnew array< double >( dimension );
}
/// Indexer [ Property ]
double Vector::default::get( int index )
{
Debug::Assert( IsRangeOfDimension( index ), "添え字は次元の範囲内である" );
// 添え字が1からとなるように、補正して指定する
return m_components[ index - 1 ];
}
/// Indexer [ Property ]
void Vector::default::set( int index, double value )
{
Debug::Assert( IsRangeOfDimension( index ), "添え字は次元の範囲内である" );
// 添え字1からとなるように、補正して指定する
m_components[ index - 1 ] = value;
}
/// 次元を設定する [ Property ]
void Vector::Dimension::set( int value )
{
Debug::Assert( value != Dimension, "次元は変更される" );
// 領域を解放する
delete[] m_components;
// ... 指定された次元で領域を確保する
SecureDomain( value );
Debug::Assert( Dimension == value, "次元は指定値に設定されている" );
}
/// 逆ベクトルを返す [ Operator Overloading ]
Vector^ Vector::operator-()
{
return gcnew Vector( -1.0 * this );
}
/// 和 += [ Operator Overloading ]
Vector^ Vector::operator+=( Vector^ obj )
{
Debug::Assert( Dimension == obj->Dimension, "引数のベクトルと次元は等しい" );
for( int i=0; i<Dimension; i++ )
{
m_components[ i ] += obj->m_components[ i ];
}
return this;
}
/// 差 -= [ Operator Overloading ]
Vector^ Vector::operator-=( Vector^ obj )
{
Debug::Assert( Dimension == obj->Dimension, "引数のベクトルと次元は等しい" );
for( int i=0; i<Dimension; i++ )
{
m_components[ i ] -= obj->m_components[ i ];
}
return this;
}
/// 積 *= [ Operator Overloading ]
Vector^ Vector::operator*=( double val )
{
for( int i=0; i<Dimension; i++ )
{
m_components[ i ] *= val;
}
return this;
}
/// 商 /= [ Operator Overloading ]
Vector^ Vector::operator/=( double val )
{
Debug::Assert( Double::Epsilon <= Math::Abs( val ), "引数はゼロではない (ゼロ除算の防止)" );
for( int i=0; i<Dimension; i++ )
{
m_components[ i ] /= val;
}
return this;
}
/// 等価演算子 == [ Operator Overloading ]
bool Vector::operator==( Vector^ left, Vector^ right )
{
// 精度を 計算機イプシロンとして比較する
return left->Equals( right, Double::Epsilon );
}
/// 不等価演算子 != [ Operator Overloading ]
bool Vector::operator!=( Vector^ left, Vector^ right )
{
// 値の等価の否定を返す
return !left->Equals( right, Double::Epsilon );
}
/// 値の等価を確認する
bool Vector::Equals( Vector^ obj )
{
// 精度を 計算機イプシロンとして比較する
return Equals( obj, Double::Epsilon );
}
/// 値の等価を確認する
bool Vector::Equals( Vector^ obj, double precision )
{
// NULLとは等価ではない
if( safe_cast< System::Object^ >( obj ) == nullptr ) return false;
Debug::Assert( Dimension == obj->Dimension, "引数のベクトルと次元は等しい" );
for( int i=0; i<Dimension; i++ )
{
// 各成分の差の絶対値を求める
double remainder = Math::Abs( m_components[ i ] - obj->m_components[ i ] );
// ... それを精度(誤差の有効範囲)と比較する
if( precision < remainder )
{
return false;
}
}
return true;
}
/// ベクトルの和 [ Operator Overloading ]
Vector^ Vector::operator+( Vector^ left, Vector^ right )
{
Vector^ result = gcnew Vector( left );
result += right;
return result;
}
/// ベクトルの差 [ Operator Overloading ]
Vector^ Vector::operator-( Vector^ left, Vector^ right )
{
Vector^ result = gcnew Vector( left );
result -= right;
return result;
}
/// スカラー倍 (実数 x ベクトル) [ Operator Overloading ]
Vector^ Vector::operator*( double scalar, Vector^ obj )
{
Vector^ result = gcnew Vector( obj );
result *= scalar;
return result;
}
/// スカラー倍 (ベクトル x 実数) [ Operator Overloading ]
Vector^ Vector::operator*( Vector^ obj, double scalar )
{
// 引数の順を入れ替えて、オーバーロードしている同一関数を呼び出す
return scalar * obj;
}
/// スカラー商 (ベクトル / 実数) [ Operator Overloading ]
Vector^ Vector::operator/( Vector^ obj, double scalar )
{
Vector^ result = gcnew Vector( obj );
result /= scalar;
return result;
}
/// 内積を返す
double Vector::InnerProduct( Vector^ left, Vector^ right )
{
Debug::Assert(
left->Dimension == right->Dimension,
"引数の2つのベクトルの次元は等しい"
);
double result = 0.0;
// 全ての成分の積の和を求める
for( int i=1; i <= left->Dimension; i++ )
{
result += left[ i ] * right[ i ];
}
return result;
}
/// 外積を返す
Vector^ Vector::CrossProduct( Vector^ left, Vector^ right )
{
Debug::Assert(
( left->Dimension == 3 ) && ( right->Dimension == 3 ),
"2つのベクトルは3次元である"
);
Vector^ result = gcnew Vector( 3 );
result[ 1 ] = ( left[ 2 ] * right[ 3 ] ) - ( left[ 3 ] * right[ 2 ] );
result[ 2 ] = ( left[ 3 ] * right[ 1 ] ) - ( left[ 1 ] * right[ 3 ] );
result[ 3 ] = ( left[ 1 ] * right[ 2 ] ) - ( left[ 2 ] * right[ 1 ] );
return result;
// [ Reference ]「ヒューマノイドロボット」梶田秀司(オーム社) P29
// [ Reference ]「ロボット制御基礎論」吉川恒夫(コロナ社) P52
}
/// 2つのベクトルを結合する
Vector^ Vector::Combine( Vector^ left, Vector^ right )
{
// 2つのベクトルの次元の和を 生成するベクトルの次元とする
int dimension = left->Dimension + right->Dimension;
Vector^ result = gcnew Vector( dimension );
int index = 1;
// 左側のベクトルを代入する
for( int i=1; i <= left->Dimension; i++ )
{
result[ index++ ] = left[ i ];
}
// 右側のベクトルを代入する
for( int i=1; i <= right->Dimension; i++ )
{
result[ index++ ] = right[ i ];
}
return result;
}
/// 零ベクトルにする
void Vector::ZeroVector()
{
#ifdef _DEBUG
int counter;
for( counter=0; counter<Dimension; counter++ )
{
if( m_components[ counter ] != 0.0 ) break; }
// } cope with NCover
Debug::Assert(
counter <= Dimension,
"全ての成分はゼロではない(零ベクトルではない)。"
"無駄な初期化が行われているので、それを修正する"
);
#endif
for( int i=0; i<Dimension; i++ )
{
m_components[ i ] = 0.0;
}
}
/// ひずみ対称行列 (交代行列) を返す
Matrix^ Vector::SkewSymmetricMatrix()
{
Debug::Assert( Dimension == 3, "3次元である" );
Matrix^ result = gcnew Matrix( Dimension, Dimension );
result[ 1 ][ 1 ] = 0.0;
result[ 2 ][ 2 ] = 0.0;
result[ 3 ][ 3 ] = 0.0;
result[ 3 ][ 2 ] = this[ 1 ];
result[ 1 ][ 3 ] = this[ 2 ];
result[ 2 ][ 1 ] = this[ 3 ];
result[ 2 ][ 3 ] = -this[ 1 ];
result[ 3 ][ 1 ] = -this[ 2 ];
result[ 1 ][ 2 ] = -this[ 3 ];
return result;
// [ Reference ]「ヒューマノイドロボット」梶田秀司(オーム社) P32
// [ Reference ]「ロボット制御基礎論」吉川恒夫(コロナ社) P62
}
/// ノルム (ベクトル空間における長さ) を返す
double Vector::Norm()
{
double result = 0.0;
// 全ての成分の二乗和を求める
for( int i=0; i<Dimension; i++ )
{
result += m_components[ i ] * m_components[ i ];
}
// ... それの平方根を返す
return Math::Sqrt( result );
// [ Reference ]「工学を志す人の線形代数」長宗雄(東京教学社) P105
}
/// 単位ベクトルか?
bool Vector::IsUnitVector( double precision )
{
Debug::Assert( Dimension <= 3, "3次元までしか適用できない" );
double result = 0.0;
// 2乗和を求める
for( int i=0; i<Dimension; i++ )
{
result += m_components[ i ] * m_components[ i ];
}
// ... それの平方根の絶対値が、有効範囲(精度)内かどうかで判定する
return Math::Abs( Math::Sqrt( result ) - 1.0 ) < precision;
}
/// 零ベクトルか?
bool Vector::IsZeroVector()
{
// 比較用の零ベクトルを作成する (作成時に零ベクトルに初期化される)
Vector^ zeroVector = gcnew Vector( Dimension );
return ( this == zeroVector );
}
/// 誤差成分を除去する (微少成分の消去)
void Vector::RemoveErrorComponent()
{
double maxOfAbsoluteValue = 0.0;
// 絶対値が最大の成分を見つける
for( int i=0; i<Dimension; i++ )
{
double compare = Math::Abs( m_components[ i ] );
if( maxOfAbsoluteValue < compare )
{
maxOfAbsoluteValue = compare;
}
}
if( Double::Epsilon < maxOfAbsoluteValue )
{
// 最大の成分が 計算機イプシロンより大きければ修正する
for( int i=0; i<Dimension; i++ )
{
// 絶対値が最大の成分と比較して相対的に小さい値を ゼロとする
if( ( Math::Abs( m_components[ i ] ) / maxOfAbsoluteValue ) < Tolerance )
{
m_components[ i ] = 0.0;
}
}
}
// [ Reference ]「数値計算以前」Yamada.K ( http://www.asahi-net.or.jp/~uc3k-ymd/Lesson/Section03/section03_13.html )
}
/// 次元の範囲内か?
bool Vector::IsRangeOfDimension( int index )
{
const int baseNumberOfSuffix = 1; // 添え字の開始番号
return ( index >= baseNumberOfSuffix )
&& ( index <= baseNumberOfSuffix + Dimension );
}
/// インスタンスの説明を文字列で返す
System::String^ Vector::ToString()
{
String^ result;
// 全ての成分を 文字列として連結する
for each( double value in m_components )
{
result += value.ToString( "0.0000000" ) + " ";
}
return result;
}