/******************************************************************************* * Point (Point3D : Point) * * 極々ありがちなポイントクラス。外積、内積、角度、長さ、正規化、スカラーとの演 * 算、行列との演算など一通りサポート。 *******************************************************************************/ #if !defined ATS_POINT_H #define ATS_POINT_H #include #include #include // inlineについて // VC++ではvirtualでもできるところはinlineにしてくれるらしい? // virtualについて // 演算子ってvirtualにして良かったっけ? // 0による除算対策 // numeric_limit::epsilon() // 例外や無視ではなく最小単位の数とみなし、計算する。 // 整数型を入れたときなどはepsilon()に依存する。 // 注意 // Point型同士だけでなく、Point型 + テンプレート型もあります。 // うっかり足してしまわないように。 // ==演算子は誤差を考慮する。 // 誤差の範囲はGet or Set RangeOfError()関数で定義する。 // ただし、スタティック変数・関数であるため他のインスタンスも // それに従う。範囲は // top > value < underで、topとunderはvalueに誤差を加差したもので // top = value + epsilon(); under = value - epsilon()となる。 // 誤差の初期値 // numeric_limits::epsilon() * 5。 // 掛け算はデフォルトで外積になります。 namespace ats { // 循環参照解決 template class Matrix3D; inline double clamp(double a, double l, double h) { return ((a) < (l) ? (l) : (a) > (h) ? (h) : (a)); } template class Point { //friend Point operator*(const Point& a, const Matrix3D& b); private: T m_x, m_y, m_z; // 誤差の範囲 static T m_range_of_error; public: inline explicit Point(const T x=0, const T y=0, const T z=0) : m_x(x), m_y(y), m_z(z) {} inline explicit Point(const Point& a) : m_x(a.m_x), m_y(a.m_y), m_z(a.m_z) {} inline ~Point() {} inline T X() const { return m_x; } inline T Y() const { return m_y; } inline T Z() const { return m_z; } inline void X(const T a) { m_x = a; } inline void Y(const T a) { m_y = a; } inline void Z(const T a) { m_z = a; } inline void SetXYZ(const T x, const T y, const T z){ m_x = x; m_y = y; m_z = z; } inline T Length() const { return sqrt(m_x*m_x + m_y*m_y + m_z*m_z); } inline Point& Normalize() { return *this /= Length(); } inline Point GetNormal() const { return *this / Length(); } inline T Dot(const Point& a) const { return (m_x * a.m_x + m_y * a.m_y + m_z * a.m_z); } T Angle(const Point& a) const; static T GetRangeOfError(); static void SetRangeOfError(const T a); bool operator==(const Point& a) const; /* 意味ないから消そうかな */ bool operator> (const Point& a) const; bool operator>=(const Point& a) const; bool operator< (const Point& a) const; bool operator<=(const Point& a) const; Point& operator= (const Point&); Point& operator+=(const Point&); Point& operator-=(const Point&); Point& operator*=(const Point&); Point& operator/=(const Point&); inline Point operator+(const Point& a) const { return Point(m_x + a.m_x, m_y + a.m_y, m_z + a.m_z); } inline Point operator-(const Point& a) const { return Point(m_x - a.m_x, m_y - a.m_y, m_z - a.m_z); } Point operator*(const Point&) const; Point operator/(const Point&) const; Point& operator+=(const T a); Point& operator-=(const T a); Point& operator*=(const T a); Point& operator/=(const T a); Point operator+(const T a) const; Point operator-(const T a) const; Point operator*(const T a) const; Point operator/(const T a) const; inline Point operator*(const Matrix3D& a) { return Point3D( m_x * a(0,0) + m_y * a(0,1) + m_z * a(0,2) + a(0,3), m_x * a(1,0) + m_y * a(1,1) + m_z * a(1,2) + a(1,3), m_x * a(2,0) + m_y * a(2,1) + m_z * a(2,2) + a(2,3) ); } inline Point& operator*=(const Matrix3D& a) { return (*this = *this * a); } inline Point operator*(const T a[4][4]) { return Point3D( m_x * a[0][0] + m_y * a[0][1] + m_z * a[0][2] + a[0][3], m_x * a[1][0] + m_y * a[1][1] + m_z * a[1][2] + a[1][3], m_x * a[2][0] + m_y * a[2][1] + m_z * a[2][2] + a[2][3] ); } inline Point& operator*=(const T a[4][4]) { return (*this = *this * a); } }; //#include "ats_Point.cpp" // 静的変数 -------------------------------------------------------- template T Point::m_range_of_error = std::numeric_limits::epsilon() * 5; template T Point::Angle(const Point& a) const { // a・b = |a||b|cosθ // (a・b) / |a||b| = cosθ // acos((a・b) / |a||b|) = θ // // a = 60(* pi / 180) // cos(a) = b; // acos(b) = c; // (a == c) is true //return acos(clamp(Dot(a) / (Length()*a.Length()), -1.0, 1.0)); return acos(Dot(a) / (Length()*a.Length())); // clampはよくわからん } // 比較演算子 ------------------------------------------------------ template bool Point::operator==(const Point& a) const { Point range_top(*this + m_range_of_error); Point range_under(*this - m_range_of_error); return (range_top > a && range_under > a); } template bool Point::operator>(const Point& a) const { return (m_x > a.m_x && m_y > a.m_y && m_z > a.m_z); } template bool Point::operator>=(const Point& a) const { return (m_x >= a.m_x && m_y >= a.m_y && m_z >= a.m_z); } template bool Point::operator<(const Point& a) const { return (m_x < a.m_x && m_y < a.m_y && m_z < a.m_z); } template bool Point::operator<=(const Point& a) const { return (m_x <= a.m_x && m_y <= a.m_y && m_z <= a.m_z); } // 誤差 ------------------------------------------------------------ template T Point::GetRangeOfError() { return m_range_of_error; } template void Point::SetRangeOfError(const T a) { m_range_of_error = a; } // 代入演算子 -------------------------------------------------------- template Point& Point::operator=(const Point& a) { m_x = a.m_x; m_y = a.m_y; m_z = a.m_z; return *this; } template Point& Point::operator+=(const Point& a) { m_x += a.m_x; m_y += a.m_y; m_z += a.m_z; return *this; } template Point& Point::operator-=(const Point& a) { m_x -= a.m_x; m_y -= a.m_y; m_z -= a.m_z; return *this; } template Point& Point::operator*=(const Point& a) { *this = Point( m_y * a.m_z - m_z * a.m_y, m_z * a.m_x - m_x * a.m_z, m_x * a.m_y - m_y * a.m_x ); return *this; } template Point& Point::operator/=(const Point& a) { T x, y, z; // 0による除算対策 : 0の場合は最も小さな数とする if(0 == a.m_x){ x = std::numeric_limits::epsilon(); } else { x = a.m_x; } if(0 == a.m_y){ y = std::numeric_limits::epsilon(); } else { y = a.m_y; } if(0 == a.m_z){ z = std::numeric_limits::epsilon(); } else { z = a.m_z; } m_x /= x; m_y /= y; m_z /= z; return *this; } // 代入演算子 対 テンプレート型 --------------------------------------------------- template Point& Point::operator+=(const T a) { m_x += a; m_y += a; m_z += a; return *this; } template Point& Point::operator-=(const T a) { m_x -= a; m_y -= a; m_z -= a; return *this; } template Point& Point::operator*=(const T a) { m_x *= a; m_y *= a; m_z *= a; return *this; } template Point& Point::operator/=(const T a) { T tmp; if(0 == a){ tmp = std::numeric_limits::epsilon(); } else { tmp = a; } m_x /= tmp; m_y /= tmp; m_z /= tmp; return *this; } // 四則演算子 --------------------------------------------------------- template Point Point::operator*(const Point& a) const { return Point(m_y * a.m_z - m_z * a.m_y, m_z * a.m_x - m_x * a.m_z, m_x * a.m_y - m_y * a.m_x); } template Point Point::operator/(const Point& a) const { T x, y, z; // 0による除算対策 : 0の場合は最も小さな数とする if(0 == a.m_x){ x = std::numeric_limits::epsilon(); } else { x = a.m_x; } if(0 == a.m_y){ y = std::numeric_limits::epsilon(); } else { y = a.m_y; } if(0 == a.m_z){ z = std::numeric_limits::epsilon(); } else { z = a.m_z; } return Point(m_x/x, m_y/y, m_z/z); } // 四則演算子 対 テンプレート型 ---------------------------------------- template Point Point::operator+(const T a) const { return Point(m_x + a, m_y + a, m_z + a); } template Point Point::operator-(const T a) const { return Point(m_x - a, m_y - a, m_z - a); } template Point Point::operator*(const T a) const { return Point(m_x * a, m_y * a, m_z * a); } template Point Point::operator/(const T a) const { T tmp; // 0による除算対策 : 0の場合は最も小さな数とする if(0 == a){ tmp = std::numeric_limits::epsilon(); } else { tmp = a; } return Point(m_x/tmp, m_y/tmp, m_z/tmp); } template std::ostream& operator<<(std::ostream& out, const Point& a) { out << a.X() << " : " << a.Y() << " : " << a.Z() << endl; return out; } typedef Point Point3D; template Point operator-(const Point& a) { return a * -1; } } #endif // #if !defined ATS_POINT_H