c_cpp 矢量函数(openFrameworks的Vec2f / 3f / 4f端口)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 矢量函数(openFrameworks的Vec2f / 3f / 4f端口)相关的知识,希望对你有一定的参考价值。
#pragma once
#include <cstddef>
class Vec2f;
class Vec3f;
// #include "ofConstants.h"
class Vec4f {
public:
/// \cond INTERNAL
static const int DIM = 4;
/// \endcond
float x;
float y;
float z;
float w;
//---------------------
/// \name Construct a 4D vector
/// \{
Vec4f();
explicit Vec4f( float _scalar );
Vec4f( float _x, float _y, float _z, float _w );
Vec4f( const Vec2f& vec);
Vec4f( const Vec3f& vec);
/// \}
//---------------------
/// \name Access components
/// \{
float * getPtr() {
return (float*)&x;
}
const float * getPtr() const {
return (const float *)&x;
}
float& operator[]( int n ){
return getPtr()[n];
}
float operator[]( int n ) const {
return getPtr()[n];
}
void set( float _scalar );
void set( float _x, float _y, float _z, float _w );
void set( const Vec4f& vec );
/// \}
//---------------------
/// \name Comparison
/// \{
bool operator==( const Vec4f& vec ) const;
bool operator!=( const Vec4f& vec ) const;
bool match( const Vec4f& vec, float tolerance = 0.0001f) const;
/// \}
//---------------------
/// \name Operators
/// \{
Vec4f operator+( const Vec4f& vec ) const;
Vec4f operator+( const float f ) const;
Vec4f& operator+=( const Vec4f& vec );
Vec4f& operator+=( const float f );
Vec4f operator-( const float f ) const;
Vec4f operator-( const Vec4f& vec ) const;
Vec4f operator-() const;
Vec4f& operator-=( const float f );
Vec4f& operator-=( const Vec4f& vec );
Vec4f operator*( const Vec4f& vec ) const;
Vec4f operator*( const float f ) const;
Vec4f& operator*=( const Vec4f& vec );
Vec4f& operator*=( const float f );
Vec4f operator/( const Vec4f& vec ) const;
Vec4f operator/( const float f ) const;
Vec4f& operator/=( const Vec4f& vec );
Vec4f& operator/=( const float f );
/// \cond INTERNAL
// friend ostream& operator<<(ostream& os, const Vec4f& vec);
// friend istream& operator>>(istream& is, const Vec4f& vec);
/// \endcond
/// \}
//---------------------
/// \name Simple manipulations
/// \{
/// \brief Returns a new Vec4f that is the result of scaling this vector up or down so that it has the requested length.
///
/// \param length The desired length of the new Vec4f object.
/// \returns The result of scaling the this vector up or down.
Vec4f getScaled( const float length ) const;
/// \brief Scales this vector up or down so that it has the requested length.
///
/// \param length The desired length of the vector.
Vec4f& scale( const float length );
/// \}
//---------------------
/// \name Distance
/// \{
/// \brief Treats this vector and 'pnt' as points in 4D space and calculates the distance between them.
///
/// \param pnt The vector used in the distance calculation with the current vector.
/// \returns The distance between the two vectors in 4D space.
float distance( const Vec4f& pnt) const;
float squareDistance( const Vec4f& pnt ) const;
/// \}
//---------------------
/// \name Interpolation
/// \{
/// \brief Performs a linear interpolation of this vector towards 'pnt'.
///
/// \param pnt The vector the interpolation will be performed on.
/// \param p The amount to move towards 'pnt'; 'p' is normally between 0 and 1 and where 0 means stay the original position and 1 means move all the way to 'pnt', but you can also have 'p' greater than 1 overshoot 'pnt', or less than 0 to move backwards away from 'pnt'.
/// \returns The interpolation as an Vec4f.
Vec4f getInterpolated( const Vec4f& pnt, float p ) const;
/// \brief Performs a linear interpolation of this vector towards 'pnt'. This modifies the current vector to the interpolated value.
///
/// \param pnt The vector the interpolation will be performed on.
/// \param p The amount to move towards 'pnt'; 'p' is normally between 0 and 1 and where 0 means stay the original position and 1 means move all the way to 'pnt', but you can also have 'p' greater than 1 overshoot 'pnt', or less than 0 to move backwards away from 'pnt'.
Vec4f& interpolate( const Vec4f& pnt, float p );
/// \brief Calculates and returns the midpoint (as a vector) between this vector and 'pnt'.
///
/// \param pnt The vector used in the midpoint calculation with this vector.
/// \returns The midpoint between this vector and 'pnt' as an Vec4f.
Vec4f getMiddle( const Vec4f& pnt ) const;
/// \brief Calculates and returns the midpoint (as a vector) between this vector and 'pnt'. This modifies the current vector to the midpoint value.
///
/// \param pnt The vector used in the midpoint calculation with this vector.
/// \returns The midpoint between this vector and 'pnt' as an Vec4f.
Vec4f& middle( const Vec4f& pnt );
/// \brief Sets this vector to be the average (center of gravity or centroid) of a given array of 'Vec4f's.
///
/// \param points The array of 'Vec4f's used in the average calculation.
/// \param num The number of Vec4f objects in the array.
Vec4f& average( const Vec4f* points, int num );
/// \}
//---------------------
/// \name Limit
/// \{
/// \brief Returns a normalized copy of this vector.
///
/// Normalization means to scale the vector so that its length (magnitude) is exactly 1,
/// at which stage all that is left is the direction. A normalized vector is usually called
/// a unit vector, and can be used to represent a pure direction (heading).
///
/// \returns The normalized copy of the current vector.
Vec4f getNormalized() const;
/// \brief Normalizes the vector. This changes the current vector to its normalized value.
///
/// Normalization means to scale the vector so that its length (magnitude) is exactly 1,
/// at which stage all that is left is the direction. A normalized vector is usually called
/// a unit vector, and can be used to represent a pure direction (heading).
Vec4f& normalize();
/// \brief Returns a copy of this vector with its length (magnitude) restricted to a maximum of 'max' units by scaling down if necessary.
///
/// \param max The maximum length of the new vector.
/// \returns A copy of the current vector that is at most 'max' units long.
Vec4f getLimited(float max) const;
/// \brief Restrict the length (magnitude) of this vector to a maximum of 'max' units by scaling down if necessary.
///
/// \param max The maximum length of the current vector.
Vec4f& limit(float max);
/// \}
//---------------------
/// \name Measurement
/// \{
/// \brief Returns the length (magnitude) of this vector.
///
/// \returns The magnitude of the current vector.
float length() const;
float lengthSquared() const;
/// \}
//---------------------
/// \name Calculations
/// \{
/// \brief Calculates and returns the dot product of this vector with 'vec'.
///
/// Dot product (less commonly known as Euclidean inner product) expresses the angular
/// relationship between two vectors. In other words it is a measure of how parallel two vectors
/// are. If they are completely perpendicular the dot product is 0; if they are completely parallel
/// their dot product is either 1 if they are pointing in the same direction, or -1 if they are pointing
/// in opposite directions.
///
/// \param vec The vector used in the dot product calculation with this vector.
/// \returns The dot product of this vector with 'vec'.
float dot( const Vec4f& vec ) const;
/// \}
//---------------------------------------
// this methods are deprecated in 006 please use:
/// \cond INTERNAL
// // getScaled
// OF_DEPRECATED_MSG("Use member method getScaled() instead.", Vec4f rescaled( const float length ) const);
//
// // scale
// OF_DEPRECATED_MSG("Use member method scale() instead.", Vec4f& rescale( const float length ));
//
// // getNormalized
// OF_DEPRECATED_MSG("Use member method getNormalized() instead.", Vec4f normalized() const);
//
// // getLimited
// OF_DEPRECATED_MSG("Use member method getLimited() instead.", Vec4f limited(float max) const);
//
// // use squareDistance
// OF_DEPRECATED_MSG("Use member method squareDistance() instead.", float distanceSquared( const Vec4f& pnt ) const);
//
// // use getInterpolated
// OF_DEPRECATED_MSG("Use member method getInterpolated() instead.", Vec4f interpolated( const Vec4f& pnt, float p ) const);
//
// // use getMiddle
// OF_DEPRECATED_MSG("Use member method getMiddle() instead.", Vec4f middled( const Vec4f& pnt ) const);
// return all zero vector
static Vec4f zero() { return Vec4f(0, 0, 0, 0); }
// return all one vector
static Vec4f one() { return Vec4f(1, 1, 1, 1); }
/// \endcond
};
/// \cond INTERNAL
// Non-Member operators
//
//
Vec4f operator+( float f, const Vec4f& vec );
Vec4f operator-( float f, const Vec4f& vec );
Vec4f operator*( float f, const Vec4f& vec );
Vec4f operator/( float f, const Vec4f& vec );
/////////////////
// Implementation
/////////////////
inline Vec4f::Vec4f(): x(0), y(0), z(0), w(0) {}
inline Vec4f::Vec4f(float _s): x(_s), y(_s), z(_s), w(_s) {}
inline Vec4f::Vec4f( float _x,
float _y,
float _z,
float _w ):x(_x), y(_y), z(_z), w(_w) {}
// Getters and Setters.
//
//
inline void Vec4f::set( float _scalar) {
x = _scalar;
y = _scalar;
z = _scalar;
w = _scalar;
}
inline void Vec4f::set( float _x, float _y, float _z, float _w ) {
x = _x;
y = _y;
z = _z;
w = _w;
}
inline void Vec4f::set( const Vec4f& vec ) {
x = vec.x;
y = vec.y;
z = vec.z;
w = vec.w;
}
// Check similarity/equality.
//
//
inline bool Vec4f::operator==( const Vec4f& vec ) const {
return (x == vec.x) && (y == vec.y) && (z == vec.z) && (w == vec.w);
}
inline bool Vec4f::operator!=( const Vec4f& vec ) const {
return (x != vec.x) || (y != vec.y) || (z != vec.z) || (w != vec.w);
}
inline bool Vec4f::match( const Vec4f& vec, float tolerance) const {
return (fabs(x - vec.x) < tolerance)
&& (fabs(y - vec.y) < tolerance)
&& (fabs(z - vec.z) < tolerance)
&& (fabs(w - vec.w) < tolerance);
}
// Additions and Subtractions.
//
//
inline Vec4f Vec4f::operator+( const Vec4f& vec ) const {
return Vec4f( x+vec.x, y+vec.y, z+vec.z, w+vec.w);
}
inline Vec4f& Vec4f::operator+=( const Vec4f& vec ) {
x += vec.x;
y += vec.y;
z += vec.z;
w += vec.w;
return *this;
}
inline Vec4f Vec4f::operator-( const float f ) const {
return Vec4f( x-f, y-f, z-f, w-f );
}
inline Vec4f& Vec4f::operator-=( const float f ) {
x -= f;
y -= f;
z -= f;
w -= f;
return *this;
}
inline Vec4f Vec4f::operator-( const Vec4f& vec ) const {
return Vec4f( x-vec.x, y-vec.y, z-vec.z, w-vec.w );
}
inline Vec4f& Vec4f::operator-=( const Vec4f& vec ) {
x -= vec.x;
y -= vec.y;
z -= vec.z;
w -= vec.w;
return *this;
}
inline Vec4f Vec4f::operator+( const float f ) const {
return Vec4f( x+f, y+f, z+f, w+f );
}
inline Vec4f& Vec4f::operator+=( const float f ) {
x += f;
y += f;
z += f;
w += f;
return *this;
}
inline Vec4f Vec4f::operator-() const {
return Vec4f( -x, -y, -z, -w );
}
// Scalings
//
//
inline Vec4f Vec4f::operator*( const Vec4f& vec ) const {
return Vec4f( x*vec.x, y*vec.y, z*vec.z, w*vec.w );
}
inline Vec4f& Vec4f::operator*=( const Vec4f& vec ) {
x *= vec.x;
y *= vec.y;
z *= vec.z;
w *= vec.w;
return *this;
}
inline Vec4f Vec4f::operator*( const float f ) const {
return Vec4f( x*f, y*f, z*f, w*f );
}
inline Vec4f& Vec4f::operator*=( const float f ) {
x *= f;
y *= f;
z *= f;
w *= f;
return *this;
}
inline Vec4f Vec4f::operator/( const Vec4f& vec ) const {
return Vec4f( vec.x!=0 ? x/vec.x : x , vec.y!=0 ? y/vec.y : y, vec.z!=0 ? z/vec.z : z, vec.w!=0 ? w/vec.w : w );
}
inline Vec4f& Vec4f::operator/=( const Vec4f& vec ) {
vec.x!=0 ? x/=vec.x : x;
vec.y!=0 ? y/=vec.y : y;
vec.z!=0 ? z/=vec.z : z;
vec.w!=0 ? w/=vec.w : w;
return *this;
}
inline Vec4f Vec4f::operator/( const float f ) const {
if(f == 0) return Vec4f(x, y, z, w);
return Vec4f( x/f, y/f, z/f, w/f );
}
inline Vec4f& Vec4f::operator/=( const float f ) {
if(f == 0)return *this;
x /= f;
y /= f;
z /= f;
w /= f;
return *this;
}
// inline ostream& operator<<(ostream& os, const Vec4f& vec) {
// os << vec.x << ", " << vec.y << ", " << vec.z << ", " << vec.w;
// return os;
// }
//
// inline istream& operator>>(istream& is, Vec4f& vec) {
// is >> vec.x;
// is.ignore(2);
// is >> vec.y;
// is.ignore(2);
// is >> vec.z;
// is.ignore(2);
// is >> vec.w;
// return is;
// }
// inline Vec4f Vec4f::rescaled( const float length ) const {
// return getScaled(length);
// }
inline Vec4f Vec4f::getScaled( const float length ) const {
float l = (float)sqrt(x*x + y*y + z*z + w*w);
if( l > 0 )
return Vec4f( (x/l)*length, (y/l)*length,
(z/l)*length, (w/l)*length );
else
return Vec4f();
}
// inline Vec4f& Vec4f::rescale( const float length ) {
// return scale(length);
// }
inline Vec4f& Vec4f::scale( const float length ) {
float l = (float)sqrt(x*x + y*y + z*z + w*w);
if (l > 0) {
x = (x/l)*length;
y = (y/l)*length;
z = (z/l)*length;
w = (w/l)*length;
}
return *this;
}
// Distance between two points.
//
//
inline float Vec4f::distance( const Vec4f& pnt) const {
float vx = x-pnt.x;
float vy = y-pnt.y;
float vz = z-pnt.z;
float vw = w-pnt.w;
return (float)sqrt( vx*vx + vy*vy + vz*vz + vw*vw );
}
// inline float Vec4f::distanceSquared( const Vec4f& pnt ) const {
// return squareDistance(pnt);
// }
inline float Vec4f::squareDistance( const Vec4f& pnt ) const {
float vx = x-pnt.x;
float vy = y-pnt.y;
float vz = z-pnt.z;
float vw = w-pnt.w;
return vx*vx + vy*vy + vz*vz + vw*vw;
}
// Linear interpolation.
//
//
/**
* p==0.0 results in this point, p==0.5 results in the
* midpoint, and p==1.0 results in pnt being returned.
*/
// inline Vec4f Vec4f::interpolated( const Vec4f& pnt, float p ) const{
// return getInterpolated(pnt,p);
// }
inline Vec4f Vec4f::getInterpolated( const Vec4f& pnt, float p ) const {
return Vec4f( x*(1-p) + pnt.x*p,
y*(1-p) + pnt.y*p,
z*(1-p) + pnt.z*p,
w*(1-p) + pnt.w*p );
}
inline Vec4f& Vec4f::interpolate( const Vec4f& pnt, float p ) {
x = x*(1-p) + pnt.x*p;
y = y*(1-p) + pnt.y*p;
z = z*(1-p) + pnt.z*p;
w = w*(1-p) + pnt.w*p;
return *this;
}
// inline Vec4f Vec4f::middled( const Vec4f& pnt ) const {
// return getMiddle(pnt);
// }
inline Vec4f Vec4f::getMiddle( const Vec4f& pnt ) const {
return Vec4f( (x+pnt.x)/2.0f, (y+pnt.y)/2.0f,
(z+pnt.z)/2.0f, (w+pnt.w)/2.0f );
}
inline Vec4f& Vec4f::middle( const Vec4f& pnt ) {
x = (x+pnt.x)/2.0f;
y = (y+pnt.y)/2.0f;
z = (z+pnt.z)/2.0f;
w = (w+pnt.w)/2.0f;
return *this;
}
// Average (centroid) among points.
// (Addition is sometimes useful for calculating averages too)
//
//
inline Vec4f& Vec4f::average( const Vec4f* points, int num ) {
x = 0.f;
y = 0.f;
z = 0.f;
w = 0.f;
for( int i=0; i<num; i++) {
x += points[i].x;
y += points[i].y;
z += points[i].z;
w += points[i].w;
}
x /= num;
y /= num;
z /= num;
w /= num;
return *this;
}
// Normalization
//
//
// inline Vec4f Vec4f::normalized() const {
// return getNormalized();
// }
inline Vec4f Vec4f::getNormalized() const {
float length = (float)sqrt(x*x + y*y + z*z + w*w);
if( length > 0 ) {
return Vec4f( x/length, y/length, z/length, w/length );
} else {
return Vec4f();
}
}
inline Vec4f& Vec4f::normalize() {
float lenght = (float)sqrt(x*x + y*y + z*z + w*w);
if( lenght > 0 ) {
x /= lenght;
y /= lenght;
z /= lenght;
w /= lenght;
}
return *this;
}
// Limit length.
//
//
// inline Vec4f Vec4f::limited(float max) const {
// return getLimited(max);
// }
inline Vec4f Vec4f::getLimited(float max) const {
Vec4f limited;
float lengthSquared = (x*x + y*y + z*z + w*w);
if( lengthSquared > max*max && lengthSquared > 0 ) {
float ratio = max/(float)sqrt(lengthSquared);
limited.set( x*ratio, y*ratio, z*ratio, w*ratio );
} else {
limited.set(x,y,z,w);
}
return limited;
}
inline Vec4f& Vec4f::limit(float max) {
float lengthSquared = (x*x + y*y + z*z + w*w);
if( lengthSquared > max*max && lengthSquared > 0 ) {
float ratio = max/(float)sqrt(lengthSquared);
x *= ratio;
y *= ratio;
z *= ratio;
w *= ratio;
}
return *this;
}
// Length
//
//
inline float Vec4f::length() const {
return (float)sqrt( x*x + y*y + z*z + w*w );
}
inline float Vec4f::lengthSquared() const {
return (float)(x*x + y*y + z*z + w*w);
}
/**
* Dot Product.
*/
inline float Vec4f::dot( const Vec4f& vec ) const {
return x*vec.x + y*vec.y + z*vec.z + w*vec.w;
}
// Non-Member operators
//
//
inline Vec4f operator+( float f, const Vec4f& vec ) {
return Vec4f( f+vec.x, f+vec.y, f+vec.z, f+vec.w );
}
inline Vec4f operator-( float f, const Vec4f& vec ) {
return Vec4f( f-vec.x, f-vec.y, f-vec.z, f-vec.w );
}
inline Vec4f operator*( float f, const Vec4f& vec ) {
return Vec4f( f*vec.x, f*vec.y, f*vec.z, f*vec.w );
}
inline Vec4f operator/( float f, const Vec4f& vec ) {
return Vec4f( f/vec.x, f/vec.y, f/vec.z, f/vec.w);
}
/// \endcond
#include "Vec2f.h"
#include "Vec3f.h"
#include "Vec4f.h"
Vec4f::Vec4f(const Vec3f& vec) {
x = vec.x;
y = vec.y;
z = vec.z;
w = 0;
}
Vec4f::Vec4f(const Vec2f& vec) {
x = vec.x;
y = vec.y;
z = 0;
w = 0;
}
#pragma once
#include <cstddef>
#include "Vec2f.h"
#include "Vec4f.h"
// #include "ofConstants.h"
#include <cmath>
// #include <iostream>
/// \brief Vec3f is a class for storing a three dimensional vector.
///
/// Moving through space requires knowledge of where things are and where they are
/// going. Vector Maths is the class of mathematics that gives us control over
/// these things in space, allowing for elegant and intuitive descriptions of
/// complex structures and movement. Vectors are at the heart of animations,
/// particle systems, and 2D and 3D graphics.
///
/// Vectors in mathematics in general are entities with magnitude (also called
/// length) and direction. A vector whose magnitude is 1 (ie a vector that is
/// *normalized*) is called a *unit vector*. Unit vectors are very handy for
/// storing directions as they can be easily scaled up (or down) to represent
/// motion in a particular direction with a particular length.
///
/// *You will also see the term 'vector' used to describe an array of objects in
/// C++ (such as text strings). Don't let this confuse you, they are quite
/// different: one of them is a mathematical term for a fixed-length list of
/// numbers that you can do mathematical operations on, the other is a
/// C++-specific term that means 'dynamically sizeable array'.*
///
/// 'Vec3f has three member variables, x, y, and z, which allow to conveniently
/// 'store 3D properties of an object such as its position, velocity, or
/// 'acceleration.
///
/// ~~~~{.cpp}
/// Vec3f v1; // v1.x is 0, v1.y is 0, v1.z is 0
/// v1.set(10, 50, 80); // now v1.x is 10, v1.y is 50, v1.z is 80
/// ~~~~
///
/// Using 'Vec3f' greatly simplifies arithmetic operations in three dimensions.
/// For example if you have two vectors 'v1' and 'v2', both of which represent a
/// 3D change in position, you can find the total change of position of both of
/// them just by doing an addition 'v1 + v2':
///
/// ~~~~{.cpp}
/// Vec3f v1(5, 2, 1);
/// // so now v1 represents walking 5 steps forward then 2 steps
/// // sideways then 1 step upwards
/// Vec3f v2;
/// v2.set(1, 1, 1);
/// // so now v2 represents walking 1 step forward then 1 step
/// // sideways then 1 step upwards
///
/// // what happens if you do v1 followed by v2?
/// // to find out just add v1 and v2 together:
/// Vec3f result = v1 + v2;
/// // result is (6, 3, 1), or 6 steps forward then 3 steps sideways
/// // then 2 steps upwards
/// ~~~~
///
/// You can scale an 'Vec3f' by multiplying it with a float:
///
/// ~~~~{.cpp}
/// // walk 5 steps forward then 2 steps sideways then 1 step upwards
/// Vec3f v1(5, 2, 1);
/// // what happens if we do v1 three times?
/// Vec3f result = v1 * 3; // result is (15, 6, 3), or
/// // 15 steps forward, 6 steps sideways and 3 steps upwards
/// ~~~~
///
/// This also works for subtraction and division.
///
/// As you can see this really makes dealing with vectors as easy as dealing with
/// single 'float's or 'int's, and can reduce the number of lines of code you have
/// to write by half, at the same time making your code much easier to read and
/// understand!
/// \sa Vec2f for 2D vectors
/// \sa Vec4f for 4D vectors
class Vec3f {
public:
/// \cond INTERNAL
static const int DIM = 3;
/// \endcond
/// \brief Stores the `X` component of this vector.
float x;
/// \brief Stores the `Y` component of this vector.
float y;
/// \brief Stores the `Z` component of this vector.
float z;
//---------------------
/// \name Construct a 3D vector
/// \{
/// \brief Construct a 3D vector. Defaults to (0,0,0).
///
/// ~~~~{.cpp}
/// Vec3f v1;
/// // default: v1.x is 0, v1.y is 0, v1.z is 0
///
/// Vec3f v2 = Vec3f(40, 20, 10);
/// // v2.x is 40, v2.y is 20, v2.z is 10
///
/// Vec3f v3(0.1, 0.3, -1.5);
/// // v3.x is 0.1, v3.y is 0.3, v3.z is -1.5
/// ~~~~
Vec3f();
/// \brief Construt a 3D vector with `x`, `y` and `z` specified
Vec3f( float x, float y, float z=0 );
/// \brief Construct a 3D vector with `x`, `y` and `z` set to `scalar`
explicit Vec3f( float scalar );
Vec3f( const Vec2f& vec );
/// \brief Construct a new 3D vector from a 4D vector by
/// throwing away the 'w' component.
///
/// ~~~~{.cpp}
/// Vec3f mom = Vec4f(40, 20, 10, 100);
/// Vec3f v(mom); // v is (40, 20, 10)
/// ~~~~
Vec3f( const Vec4f& vec );
/// \}
//---------------------
/// \name Access components
/// \{
/// \brief Returns a pointer to the memory position of the first element of the vector
/// ('x'); the other elements ('y' and 'z') immediately follow it in memory.
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// float * v1Ptr = v1.getPtr();
/// float x = *(v1Ptr); // x is 40
/// float y = *(v1Ptr+1); // y is 20
/// float z = *(v1Ptr+2); // z is 10
/// ~~~~
///
/// This is very useful when using arrays of 'Vec3f's to store geometry
/// information, as it allows the vector to be treated as a simple C array of
/// 'float's that can be passed verbatim to OpenGL.
///
float * getPtr() {
return (float*)&x;
}
const float * getPtr() const {
return (const float *)&x;
}
/// \brief Allows to access the individual components of an 'Vec3f' as though it is an
/// array
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// float x = v1[0]; // x is 40
/// float y = v1[1]; // y is 20
/// float z = v1[2]; // z is 10
/// ~~~~
///
/// This function can be handy if you want to do the same operation to all 'x',
/// 'y' and 'z' components, as it means you can just make a 'for' loop that
/// repeats 3 times.
float& operator[]( int n ){
return getPtr()[n];
}
float operator[]( int n ) const {
return getPtr()[n];
}
/// \brief Set 'x', 'y' and 'z' components of this vector with just one function call.
/// 'z' is optional, it defaults to 0.
///
/// ~~~~{.cpp}
/// Vec3f v1;
/// v1.set(40, 20, 70);
/// ~~~~
void set( float x, float y, float z = 0 );
/// \brief Setting the values by using other 3 dimension vector Vec3f.
///
/// ~~~~{.cpp}
/// Vec3f v1;
/// Vec3f v2;
/// v1.set(40, 20, 70);
/// v2.set(v1);
/// ~~~~
void set( const Vec3f& vec );
void set( float _scalar );
/// \}
//---------------------
/// \name Comparison
/// \{
/// \brief Check for equality between two Vec3f
///
/// Returns 'true' if each component is the same as the corresponding component in
/// 'vec', ie if 'x == vec.x' and 'y == vec.y' and 'z == vec.z'; otherwise returns
/// 'false'. But you should probably be using ['match'](#match) instead.
///
/// ~~~~{.cpp}
/// Vec3f v1(40, 20, 10);
/// Vec3f v2(50, 30, 10);
/// Vec3f v3(40, 20, 10);
/// // ( v1 == v2 ) is false
/// // ( v1 == v3 ) is true
/// ~~~~
bool operator==( const Vec3f& vec ) const;
/// \brief Returns 'true' if any component is different to its corresponding component in
/// 'vec', ie if 'x != vec.x' or 'y != vec.y' or 'z != vec.z'; otherwise returns
/// 'false'.
///
/// ~~~~{.cpp}
/// Vec3f v1(40, 20, 10);
/// Vec3f v2(50, 20, 40);
/// Vec3f v3(40, 20, 10);
/// // ( v1 != v2 ) is true
/// // ( v1 != v3 ) is false
/// ~~~~
bool operator!=( const Vec3f& vec ) const;
/// \brief Let you check if two vectors are similar given a tolerance threshold
/// 'tolerance' (default = 0.0001).
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 70);
/// Vec3f v2 = Vec3f(40.01, 19.999, 70.05);
/// // v1.match(v2, 0.1) is true
/// // v1.match(v2, 0.01) is false (because (70.5-70) > 0.01)
/// ~~~~
///
bool match( const Vec3f& vec, float tolerance = 0.0001f ) const;
/**
* Checks if vectors look in the same direction.
*/
bool isAligned( const Vec3f& vec, float tolerance = 0.0001f ) const;
bool isAlignedRad( const Vec3f& vec, float tolerance = 0.0001f ) const;
/// \brief Returns 'true' if this vector is pointing in the same direction as
/// 'vec', with an angle error threshold 'tolerance' in degrees (default
/// 0.0001 degrees).
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 70);
/// Vec3f v2 = Vec3f(4, 2, 7);
/// // v1.align(v2, 0.0) is true
/// ~~~~
bool align( const Vec3f& vec, float tolerance = 0.0001f ) const;
/// \brief Returns 'true' if this vector is pointing in the same direction
/// as 'vec', with an angle error threshold 'tolerance' in radians
/// (default 0.0001).
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 70);
/// Vec3f v2 = Vec3f(4, 2, 7);
/// // v1.align(v2, 0.0) is true
/// ~~~~
bool alignRad( const Vec3f& vec, float tolerance = 0.0001f ) const;
/// \}
//---------------------
/// \name Operators
/// \{
/// Super easy vector addition. Returns a new vector
/// ('x'+'vec.x','y'+'vec.y','z'+'vec.z').
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(25, 50, 10);
/// Vec3f v3 = v1 + v2; // v3 is (65, 70, 20)
/// ~~~~
Vec3f operator+( const Vec3f& pnt ) const;
/// Returns a new vector with a float value 'f' added to 'x', 'y' and 'z'
/// members.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// Vec3f v2 = v1 + 10; // (12, 15, 11)
/// ~~~~
Vec3f operator+( const float f ) const;
/// Super easy addition assignment. Adds 'vec.x' to 'x', adds 'vec.y' to 'y' and
/// adds 'vec.z' to 'z'.
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(25, 50, 10);
/// v1 += v2; // v1 is (65, 70, 20)
/// ~~~~
Vec3f& operator+=( const Vec3f& pnt );
/// Adds a float value 'f' to 'x', 'y' and 'z' members.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// v1 += 10; // (12, 15, 11)
/// ~~~~
Vec3f& operator+=( const float f );
/// Super easy vector subtraction. Returns a new vector
/// ('x'-'vec.x','y'-'vec.y','z'-'vec.z').
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(25, 50, 10);
/// Vec3f v3 = v1 - v2; // v3 is (15, -30, 0)
/// ~~~~
Vec3f operator-( const Vec3f& vec ) const;
/// Returns a new vector with a float value 'f' subtracted from 'x', 'y' and 'z'
/// members.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// Vec3f v2 = v1 - 10; // (-8, -5, -9)
/// ~~~~
Vec3f operator-( const float f ) const;
/// Returns a new 'Vec3f' that is the inverted version (mirrored in X, Y and Z)
/// of this vector.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// Vec3f v2 = -v1; // (-2, -5, -1)
/// ~~~~
///
Vec3f operator-() const;
/// Super easy subtraction assignment. Subtracts 'vec.x' from 'x', subtracts
/// 'vec.y' from 'y' and subtracts 'vec.z' from 'z'.
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(25, 50, 10);
/// v1 -= v2; // v1 is (15, -30, 0)
/// ~~~~
Vec3f& operator-=( const Vec3f& vec );
/// Subtract a float value 'f' from 'x', 'y', and 'z' members.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// v1 -= 10; // (-8, -5, -9)
/// ~~~~
Vec3f& operator-=( const float f );
/// Returns a new vector ('x'*'vec.x','y'*'vec.y','z'*'vec.z').
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(2, 4, 10);
/// Vec3f v3 = v1 * v2; // (80, 80, 100)
/// ~~~~
///
/// Useful for scaling a 3D point by a non-uniform scale.
///
Vec3f operator*( const Vec3f& vec ) const;
/// Return a new 'Vec3f' that is this vector scaled by multiplying 'x', 'y', 'z'
/// members by 'f'.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// Vec3f v2 = v1 * 4; // (8, 20, 4)
/// ~~~~
Vec3f operator*( const float f ) const;
/// Multiplies 'x' by 'vec.x', and multiplies 'y' by 'vec.y', and multiplies 'z'
/// by 'vec.z'.
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(2, 4, 10);
/// v1 *= v2; // v1 is now (80, 80, 100)
/// ~~~~
///
/// Useful for scaling a 3D point by a non-uniform scale.
Vec3f& operator*=( const Vec3f& vec );
/// Scale this vector by multiplying 'x', 'y' and 'z' members by 'f'.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// v1 *= 4; // (8, 20, 4)
/// ~~~~
Vec3f& operator*=( const float f );
/// Returns a new vector ('x'/'vec.x','y'/'vec.y','z'/'vec.z').
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(2, 4, 10);
/// Vec3f v3 = v1 / v2; // (20, 5, 1)
/// ~~~~
///
/// Useful for scaling a 3D point by a non-uniform scale.
Vec3f operator/( const Vec3f& vec ) const;
/// Return a new 'Vec3f' that is this vector scaled by dividing 'x', 'y'
/// and 'z' members by 'f'.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// Vec3f v2 = v1 / 4; // (0.5, 1.25, 0.25)
/// ~~~~
Vec3f operator/( const float f ) const;
/// Divides 'x' by 'vec.x', divides 'y' by 'vec.y', and divides 'z' by 'vec.z'.
///
/// ~~~~{.cpp}
/// Vec3f v1 = Vec3f(40, 20, 10);
/// Vec3f v2 = Vec3f(2, 4, 10);
/// v1 *= v2; // v1 is now (20, 5, 1)
/// ~~~~
///
/// Useful for scaling a 3D point by a non-uniform scale.
Vec3f& operator/=( const Vec3f& vec );
/// Scale this vector by dividing 'x', 'y' and 'z' members by 'f'.
///
/// ~~~~{.cpp}
/// Vec3f v1(2, 5, 1);
/// v1 /= 4; // (0.5, 1.25, 0.25)
/// ~~~~
Vec3f& operator/=( const float f );
/// \cond INTERNAL
// friend ostream& operator<<(ostream& os, const Vec3f& vec);
// friend istream& operator>>(istream& is, Vec3f& vec);
/// \endcond
/// \}
//---------------------
/// \name Simple manipulations
/// \{
/// \brief Return a new 'Vec3f' that is the result of scaling this vector up or down so that it has
/// the requested length.
///
/// ~~~~{.cpp}
/// Vec3f v1(3, 4); // length is 5
/// Vec3f v2 = v1.getScaled(15); // v2 is (9, 12), which has length of 15
/// ~~~~
///
Vec3f getScaled( const float length ) const;
/// \brief Scales this vector up or down so that it has the requested length.
///
/// ~~~~{.cpp}
/// Vec3f v1(3, 4); // length is 5
/// v1.scale(15); // v1 is now (9, 12), which has length of 15
/// ~~~~
Vec3f& scale( const float length );
/// \brief Return a new 'Vec3f' that is the result of rotating this vector by 'angle'
/// degrees around the given axis.
///
/// ~~~~{.cpp}
/// Vec3f v1(1, 0, 0);
/// // rotate v1 around the z axis
/// Vec3f v2 = v1.getRotated(45, Vec3f(0, 0, 1)); // v2 is (√2, √2, 0)
/// // rotate v1 around the y axis
/// Vec3f v3 = v1.getRotated(45, Vec3f(0, 1, 0)); // v3 is (√2, 0, √2)
/// ~~~~
///
Vec3f getRotated( float angle, const Vec3f& axis ) const;
/// \brief Make a copy of this vector and perform an Euler rotation of the copy around
/// three axes: 'ax' degrees about the x axis, 'ay' about the y axis and 'az'
/// about the z axis. Return the copy.
///
/// ~~~~~{.cpp}
/// Vec3f v1( 1, 0, 0 );
/// Vec3f v2 = v1.getRotated( 0, 0, 90 ); // v is now (0, 1, 0)
/// Vec3f v3 = v1.getRotated( 45, 0, 0 ); // v is now (0, √2, √2)
/// ~~~~~
///
/// Watch out for gimbal lock when specifying multiple rotations in the same call.
///
Vec3f getRotated(float ax, float ay, float az) const;
/// \brief Return a new 'Vec3f' that is the result of rotating this vector by
/// 'angle' degrees around the axis specified by 'axis', using 'pivot' as
/// the origin of rotation.
Vec3f getRotated( float angle, const Vec3f& pivot, const Vec3f& axis ) const;
/// \brief Return a new 'Vec3f' that is the result of rotating this
/// vector by 'angle' radians around the given axis.
///
/// ~~~~{.cpp}
/// Vec3f v1(1, 0, 0);
/// // rotate v1 around the z axis
/// Vec3f v2 = v1.getRotated(PI/4, Vec3f(0, 0, 1)); // v2 is (√2, √2, 0)
/// // rotate v1 around the y axis
/// Vec3f v3 = v1.getRotated(PI/4, Vec3f(0, 1, 0)); // v3 is (√2, 0, √2)
/// ~~~~
Vec3f getRotatedRad( float angle, const Vec3f& axis ) const;
/// \brief Make a copy of this vector and perform an Euler rotation of the copy around
/// three axes: 'ax' radians about the x axis, 'ay' about the y axis and 'az'
/// about the z axis. Return the copy.
///
/// ~~~~~{.cpp}
/// Vec3f v1( 1, 0, 0 );
/// Vec3f v2 = v1.getRotatedRad( 0, 0, HALF_PI ); // v is now (0, 1, 0)
/// Vec3f v3 = v1.getRotatedRad( PI/4, 0, 0 ); // v is now (0, √2, √2)
/// ~~~~~
///
/// Watch out for gimbal lock when specifying multiple rotations in the same call.
///
Vec3f getRotatedRad(float ax, float ay, float az) const;
/// \brief Return a new 'Vec3f' that is the result of rotating this vector by 'angle' radians
/// around the axis specified by 'axis', using 'pivot' as the origin of rotation.
Vec3f getRotatedRad( float angle, const Vec3f& pivot, const Vec3f& axis ) const;
/// \brief Return a new 'Vec3f' that is the result of rotating this vector by
/// 'angle' degrees around the given axis.
///
/// ~~~~{.cpp}
/// Vec3f v1(1, 0, 0);
/// // rotate v1 around the z axis
/// v1.rotate(45, Vec3f(0, 0, 1)); // v2 is (√2, √2, 0)
///
/// v1.set(1, 0, 0);
/// // then rotate around the y axis
/// v1.rotate(45, Vec3f(0, 1, 0)); // v3 is (√2, 0, √2)
/// ~~~~
Vec3f& rotate( float angle, const Vec3f& axis );
/// \brief Perform an Euler rotation of this vector around three axes: 'ax' degrees about
/// the x axis, 'ay' about the y axis and 'az' about the z axis.
///
/// ~~~~~{.cpp}
/// Vec3f v( 1, 0, 0 );
/// v.rotate( 0, 0, 90 ); // v is now (0, 1, 0)
/// v.rotate( 45, 0, 0 ); // v is now (0, √2, √2)
/// ~~~~~
///
/// Watch out for gimbal lock when specifying multiple rotations in the same call.
///
Vec3f& rotate(float ax, float ay, float az);
/// \brief Rotate this vector by 'angle' degrees around the axis specified by 'axis',
/// using 'pivot' as the origin of rotation.
Vec3f& rotate( float angle, const Vec3f& pivot, const Vec3f& axis );
/// \brief Return a new 'Vec3f' that is the result of rotating this vector by 'angle'
/// degrees around the given axis.
///
/// ~~~~{.cpp}
/// Vec3f v1(1, 0, 0);
/// // rotate v1 around the z axis
/// v1.rotate(45, Vec3f(0, 0, 1)); // v2 is (√2, √2, 0)
///
/// v1.set(1, 0, 0);
/// // then rotate around the y axis
/// v1.rotate(45, Vec3f(0, 1, 0)); // v3 is (√2, 0, √2)
/// ~~~~
Vec3f& rotateRad( float angle, const Vec3f& axis );
/// \brief Perform an Euler rotation of this vector around three axes: 'ax' radians about
/// the x axis, 'ay' about the y axis and 'az' about the z axis.
///
/// ~~~~~{.cpp}
/// Vec3f v( 1, 0, 0 );
/// v.rotateRad( 0, 0, HALF_PI ); // v is now (0, 1, 0)
/// v.rotateRad( PI/4, 0, 0 ); // v is now (0, √2, √2)
/// ~~~~~
///
/// Watch out for gimbal lock when specifying multiple rotations in the same call.
Vec3f& rotateRad(float ax, float ay, float az);
/// \brief Rotate this vector by 'angle' radians around the axis specified by 'axis',
/// using 'pivot' as the origin of rotation.
Vec3f& rotateRad( float angle, const Vec3f& pivot, const Vec3f& axis );
/// \brief Return a new 'Vec3f' calculated by copying this vector and then mapping from
/// its default coordinate system -- origin (0,0,0), X direction (1,0,0), Y
/// direction (0,1,0), Z direction (0,0,1) -- to a new coordinate system defined
/// with origin at 'origin', X direction 'vx', and Y direction 'vy', and Z
/// direction 'vz'.
///
/// *In most cases you want 'vx', 'vy', and 'vz' to be perpendicular and of unit
/// length; if they are not perpendicular you will have shearing as part of the
/// mapping, and if they are not of unit length you will have scaling as part of
/// the mapping.*
///
Vec3f getMapped( const Vec3f& origin,
const Vec3f& vx,
const Vec3f& vy,
const Vec3f& vz ) const;
/// \brief Map this vector from its default coordinate system -- origin (0,0,0), X
/// direction (1,0,0), Y direction (0,1,0), Z direction (0,0,1) -- to a new
/// coordinate system defined with origin at 'origin', X direction 'vx', and Y
/// direction 'vy', and Z direction 'vz'.
///
/// *In most cases you want 'vx', 'vy', and 'vz' to be perpendicular and of
/// unit length; if they are not perpendicular you will have shearing as part
/// of the mapping, and if they are not of unit length you will have scaling
/// as part of the mapping.*
///
Vec3f& map( const Vec3f& origin,
const Vec3f& vx,
const Vec3f& vy,
const Vec3f& vz );
/// \}
//---------------------
/// \name Distance
/// \{
/// \brief Treats both this vector and 'pnt' as points in 3D space, and
/// calculates and returns the distance between them.
///
/// ~~~~{.cpp}
/// Vec3f p1(3, 4, 2);
/// Vec3f p2(6, 8, 5);
/// float distance = p1.distance( p2 ); // distance is 5.8310
/// ~~~~
///
/// 'distance' involves a square root calculation, which is one of the
/// slowest things you can do in programming. If you don't need an exact
/// number but rather just a rough idea of distance (for example when
/// finding the shortest distance of a bunch of points to a reference
/// point, where it doesn't matter exactly what the distances are, you
/// just want the shortest), you can use squareDistance() instead.
float distance( const Vec3f& pnt) const;
/// \brief Treats both this vector and 'pnt' as points in 3D space, and calculates and
/// returns the squared distance between them.
///
/// ~~~~{.cpp}
/// Vec3f p1(3, 4, 2);
/// Vec3f p2(6, 8, 5);
/// float distance = p1.distance( p2 ); // distance is 5.8310
/// ~~~~
///
/// Use as a much faster alternative to distance() if you don't need
/// to know an exact number but rather just a rough idea of distance (for example
/// when finding the shortest distance of a bunch of points to a reference point,
/// where it doesn't matter exactly what the distances are, you just want the
/// shortest). It avoids the square root calculation that is ordinarily required
/// to calculate a length.
///
float squareDistance( const Vec3f& pnt ) const;
/// \}
//---------------------
/// \name Interpolation
/// \{
/// \brief Perform a linear interpolation of this vector's position towards 'pnt'
/// and return the interpolated vector without altering the original. 'p'
/// controls the amount to move towards 'pnt'. 'p' is normally between 0
/// and 1 and where 0 means stay the original position and 1 means move
/// all the way to 'pnt', but you can also have 'p' greater than 1
/// overshoot 'pnt', or less than 0 to move backwards away from 'pnt'.
///
/// ~~~~{.cpp}
/// Vec3f v1(0, 5, 0);
/// Vec3f v2(10, 10, 20);
/// Vec3f v3 = v1.getInterpolated(p2, 0.5); // v3 is (5, 7.5, 10)
/// Vec3f v4 = v1.getInterpolated(p2, 0.8); // v4 is (8, 9, 16)
/// ~~~~
///
Vec3f getInterpolated( const Vec3f& pnt, float p ) const;
/// \brief Perform a linear interpolation of this vector's position towards
/// 'pnt'. 'p' controls the amount to move towards 'pnt'. 'p' is normally
/// between 0 and 1 and where 0 means stay the original position and 1
/// means move all the way to 'pnt', but you can also have 'p' greater
/// than 1 overshoot 'pnt', or less than 0 to move backwards away from
/// 'pnt'.
///
/// ~~~~{.cpp}
/// Vec3f v1( 0, 5, 0 );
/// Vec3f v2( 10, 10, 20 );
/// // go go gadget zeno
/// v1.interpolate( v2, 0.5 ); // v1 is now (5, 7.5, 10)
/// v1.interpolate( v2, 0.5 ); // v1 is now (7.5, 8.75, 15)
/// v1.interpolate( v2, 0.5 ); // v1 is now (8.75, 9.375, 17.5)
/// v1.interpolate( v2, 0.5 ); // v1 is now (9.375, 9.6875, 18.75)
/// ~~~~
Vec3f& interpolate( const Vec3f& pnt, float p );
/// \brief Calculate and return the midpoint between this vector and 'pnt'.
///
/// ~~~~{.cpp}
/// Vec3f v1(5, 0, 0);
/// Vec3f v2(10, 10, 20);
/// Vec3f mid = v1.getMiddle(v2); // mid gets (7.5, 5, 10)
/// ~~~~
Vec3f getMiddle( const Vec3f& pnt ) const;
/// Set this vector to the midpoint between itself and 'pnt'.
///
/// ~~~~{.cpp}
/// Vec3f v1( 0, 5, 0 );
/// Vec3f v2( 10, 10, 20);
/// // go go gadget zeno
/// v1.middle( v2 ); // v1 is now (5, 7.5, 10)
/// v1.middle( v2 ); // v1 is now (7.5, 8.75, 15)
/// v1.middle( v2 ); // v1 is now (8.75, 9.375, 17.5)
/// v1.middle( v2 ); // v1 is now (9.375, 9.6875, 18.75)
/// ~~~~
Vec3f& middle( const Vec3f& pnt );
/// \brief Sets this vector to be the average (*centre of gravity* or
/// *centroid*) of a given array of 'Vec3f's. 'points' is the array of
/// 'Vec3f's and 'num' specifies the number of 'Vec3f's in the array.
///
/// ~~~~{.cpp}
/// int numPoints = 10;
/// Vec3f points[numPoints];
/// for ( int i=0; i<numPoints; i++ ) {
/// points[i].set( ofRandom(0,100), ofRandom(0,100), ofRandom(0,100) );
/// }
/// Vec3f centroid;
/// centroid.average( points, numPoints );
/// // centroid now is the centre of gravity/average of all the random points
/// ~~~~
Vec3f& average( const Vec3f* points, int num );
/// \}
//---------------------
/// \name Limit
/// \{
/// \brief Return a normalized copy of this vector.
///
/// *Normalization* means to scale the vector so that its length
/// (magnitude) is exactly 1, at which stage all that is left is the
/// direction. A normalized vector is usually called a *unit vector*, and
/// can be used to represent a pure direction (heading).
///
/// ~~~~{.cpp}
/// Vec3f v1(5, 0, 0);
/// Vec3f v1Normalized = v1.getNormalized(); // (1, 0, 0)
/// Vec3f v2(5, 0, 5);
/// Vec3f v2Normalized = v2.getNormalized(); // (√2, 0, √2)
/// ~~~~
Vec3f getNormalized() const;
/// \brief Normalize the vector.
///
/// *Normalizing* means to scale the vector so that its length (magnitude)
/// is exactly 1, at which stage all that is left is the direction. A
/// normalized vector is usually called a *unit vector*, and can be used
/// to represent a pure direction (heading).
///
/// ~~~~{.cpp}
/// Vec3f v1(5, 0, 0);
/// v1.normalize(); // v2 is now (1, 0, 0)
/// Vec3f v2(5, 0, 5);
/// v2.normalize(); // v2 is now (√2, 0, √2)
/// ~~~~
///
Vec3f& normalize();
/// \brief Return a copy of this vector with its length (magnitude) restricted to a
/// maximum of 'max' units by scaling down if necessary.
///
/// ~~~~{.cpp}
/// Vec3f v1(5, 0, 1); // length is about 5.1
/// Vec3f v2(2, 0, 1); // length is about 2.2
/// Vec3f v1Limited = v1.getLimited(3);
/// // v1Limited is (2.9417, 0, 0.58835) which has length of 3 in the same direction as v1
/// Vec3f v2Limited = v2.getLimited(3);
/// // v2Limited is (2, 0, 1) (same as v2)
/// ~~~~
Vec3f getLimited(float max) const;
/// \brief Restrict the length (magnitude) of this vector to a maximum of 'max'
/// units by scaling down if necessary.
///
/// ~~~~{.cpp}
/// Vec3f v1(5, 0, 1); // length is about 5.1
/// Vec3f v2(2, 0, 1); // length is about 2.2
/// v1.limit(3);
/// // v1 is now (2.9417, 0, 0.58835) which has length of 3 in the same direction as at initialization
/// v2.limit(3);
/// // v2 is unchanged
/// ~~~~
Vec3f& limit(float max);
/// \}
//---------------------
/// \name Measurement
/// \{
/// Return the length (magnitude) of this vector.
///
/// ~~~~{.cpp}
/// Vec3f v(3, 4, 1);
/// float len = v.length(); // len is 5.0990
/// ~~~~
///
/// `length' involves a square root calculation, which is one of the
/// slowest things you can do in programming. If you don't need an exact
/// number but rather just a rough idea of a length (for example when
/// finding the shortest distance of a bunch of points to a reference
/// point, where it doesn't matter exactly what the lengths are, you just
/// want the shortest), you can use lengthSquared() instead.
///
float length() const;
/// \brief Return the squared length (squared magnitude) of this vector.
///
/// ~~~~{.cpp}
/// Vec3f v(3, 4, 1);
/// float len = v.length(); // len is 5.0990
/// ~~~~
///
/// Use as a much faster alternative to length() if you don't need
/// to know an accurate length but rather just a rough idea of a length (for
/// example when finding the shortest distance of a bunch of points to a
/// reference point, where it doesn't matter exactly what the lengths are, you
/// just want the shortest). It avoids the square root calculation that is
/// ordinarily required to calculate a length.
float lengthSquared() const;
/// \brief Calculate and return the coplanar angle in degrees between this vector
/// and 'vec'.
///
/// ~~~~{.cpp}
/// Vec3f v1(1,0,0);
/// Vec3f v2(0,1,0);
/// float angle = v1.angle(v2); // angle is 90
/// ~~~~
float angle( const Vec3f& vec ) const;
/// \brief Calculate and return the coplanar angle in radians between this
/// vector and 'vec'.
///
/// ~~~~{.cpp}
/// Vec3f v1(1,0,0);
/// Vec3f v2(0,1,0);
/// float angle = v1.angle(v2); // angle is 90
/// ~~~~
///
float angleRad( const Vec3f& vec ) const;
/// \}
//---------------------
/// \name Perpendicular
/// \{
/// \brief Construct a plane using this vector and 'vec' (by finding the plane that both
/// lectors lie on), and return the vector that is perpendicular to that plane
/// (the normal to that plane).
///
/// ~~~~{.cpp}
/// ofSetLogLevel(OF_LOG_NOTICE);
/// Vec3f v1(1,0,0);
/// Vec3f v2(0,1,0);
/// Vec3f p = v1.getPerpendicular(v2);
/// ofLog(OF_LOG_NOTICE, "%1.1f, %1.1f, %1.1f\n", p.x, p.y, p.z);
/// // prints "0.0, 0.0, 1.0"
/// ~~~~
///
/// This method is usually used to calculate a normal vector to a surface, which
/// can then be used to calculate lighting, collisions, and other 3D effects.
///
Vec3f getPerpendicular( const Vec3f& vec ) const;
/// \brief Construct a plane using this vector and 'vec' (by finding the plane that both
/// lie on), and set our 'x', 'y' and 'z' to be the vector that is perpendicular
/// to the constructed plane (the normal to the plane).
///
/// ~~~~{.cpp}
/// ofSetLogLevel(OF_LOG_NOTICE);
/// Vec3f v1(1,0,0);
/// Vec3f v2(0,1,0);
/// v1.perpendicular(v2);
/// ofLog(OF_LOG_NOTICE, "%1.1f, %1.1f, %1.1f\n", v1.x, v1.y, v1.z);
/// // prints "0.0, 0.0, 1.0'
/// ~~~~
///
/// This method is usually used to calculate a normal vector to a surface, which
/// can then be used to calculate lighting, collisions, and other 3D effects.
///
Vec3f& perpendicular( const Vec3f& vec );
/// \brief Returns the cross product (vector product) of this vector and 'vec'. This is a
/// binary operation on two vectors in three-dimensional space, which results in a
/// vector that is perpendicular to both of the vectors being multiplied, and
/// normal to the plane containing them. The name *cross product* is derived from
/// the cross symbol X that is often used to designate this operation; the
/// alternative name *vector product* emphasizes the vector (rather than scalar)
/// nature of the result.
///
/// ![CROSS](math/crossproduct.png)
/// Image courtesy of Wikipedia
Vec3f getCrossed( const Vec3f& vec ) const;
/// Set this vector to the cross product (vector product) of itself and
/// 'vec'. This is a binary operation on two vectors in three-dimensional
/// space, which results in a vector that is perpendicular to both of the
/// vectors being multiplied, and normal to the plane containing them. The
/// name *cross product* is derived from the cross symbol X that is often
/// used to designate this operation; the alternative name *vector
/// product* emphasizes the vector (rather than scalar) nature of the
/// result.
Vec3f& cross( const Vec3f& vec );
/// \brief Calculate and return the dot product of this vector with 'vec'.
///
/// *Dot product* (less commonly known as *Euclidean inner product*)
/// expresses the angular relationship between two vectors. In other
/// words it is a measure of how *parallel* two vectors are. If they are
/// completely perpendicular the dot product is 0; if they are completely
/// parallel their dot product is either 1 if they are pointing in the
/// same direction, or -1 if they are pointing in opposite directions.
///
/// ![DOT](math/dotproduct.png)
/// Image courtesy of Wikipedia
///
/// ~~~~{.cpp}
/// Vec3f a1(1, 0, 0);
/// Vec3f b1(0, 0, 1); // 90 degree angle to a1
/// dot = a1.dot(b1); // dot is 0, ie cos(90)
///
/// Vec3f a2(1, 0, 0);
/// Vec3f b2(1, 1, 0); // 45 degree angle to a2
/// b2.normalize(); // vectors should to be unit vectors (normalized)
/// float dot = a2.dot(b2); // dot is 0.707, ie cos(45)
///
/// Vec3f a3(0, 1, 0);
/// Vec3f b3(0, -1, 0); // 180 degree angle to a3
/// dot = a3.dot(b3); // dot is -1, ie cos(180)
/// ~~~~
///
float dot( const Vec3f& vec ) const;
/// \}
//-----------------------------------------------
// this methods are deprecated in 006 please use:
/// \cond INTERNAL
// getScaled
// OF_DEPRECATED_MSG("Use member method getScaled() instead.", Vec3f rescaled( const float length ) const);
//
// // scale
// OF_DEPRECATED_MSG("Use member method scale() instead.", Vec3f& rescale( const float length ));
//
// // getRotated
// OF_DEPRECATED_MSG("Use member method getRotated() instead.", Vec3f rotated( float angle, const Vec3f& axis ) const);
//
// // getRotated should this be const???
// OF_DEPRECATED_MSG("Use member method getRotated() instead.", Vec3f rotated(float ax, float ay, float az));
//
// // getNormalized
// OF_DEPRECATED_MSG("Use member method getNormalized() instead.", Vec3f normalized() const);
//
// // getLimited
// OF_DEPRECATED_MSG("Use member method getLimited() instead.", Vec3f limited(float max) const);
//
// // getCrossed
// OF_DEPRECATED_MSG("Use member method getCrossed() instead.", Vec3f crossed( const Vec3f& vec ) const);
//
// // getPerpendicular
// OF_DEPRECATED_MSG("Use member method getPerpendicular() instead.", Vec3f perpendiculared( const Vec3f& vec ) const);
//
// // use getMapped
// OF_DEPRECATED_MSG("Use member method getMapped() instead.", Vec3f mapped( const Vec3f& origin,
// const Vec3f& vx,
// const Vec3f& vy,
// const Vec3f& vz ) const);
//
// // use squareDistance
// OF_DEPRECATED_MSG("Use member method squareDistance() instead.", float distanceSquared( const Vec3f& pnt ) const);
//
// // use getInterpolated
// OF_DEPRECATED_MSG("Use member method getInterpolated() instead.", Vec3f interpolated( const Vec3f& pnt, float p ) const);
//
// // use getMiddle
// OF_DEPRECATED_MSG("Use member method getMiddle() instead.", Vec3f middled( const Vec3f& pnt ) const);
//
// // use getRotated
// OF_DEPRECATED_MSG("Use member method getRotated() instead.", Vec3f rotated( float angle,
// const Vec3f& pivot,
// const Vec3f& axis ) const);
// return all zero vector
static Vec3f zero() { return Vec3f(0, 0, 0); }
// return all one vector
static Vec3f one() { return Vec3f(1, 1, 1); }
/// \endcond
};
/// \cond INTERNAL
// Non-Member operators
//
//
Vec3f operator+( float f, const Vec3f& vec );
Vec3f operator-( float f, const Vec3f& vec );
Vec3f operator*( float f, const Vec3f& vec );
Vec3f operator/( float f, const Vec3f& vec );
/////////////////
// Implementation
/////////////////
inline Vec3f::Vec3f( const Vec2f& vec ):x(vec.x), y(vec.y), z(0) {}
inline Vec3f::Vec3f( const Vec4f& vec ):x(vec.x), y(vec.y), z(vec.z) {}
inline Vec3f::Vec3f(): x(0), y(0), z(0) {}
inline Vec3f::Vec3f( float _all ): x(_all), y(_all), z(_all) {}
inline Vec3f::Vec3f( float _x, float _y, float _z ):x(_x), y(_y), z(_z) {}
// Getters and Setters.
//
//
inline void Vec3f::set( float _scalar ) {
x = _scalar;
y = _scalar;
z = _scalar;
}
inline void Vec3f::set( float _x, float _y, float _z ) {
x = _x;
y = _y;
z = _z;
}
inline void Vec3f::set( const Vec3f& vec ) {
x = vec.x;
y = vec.y;
z = vec.z;
}
// Check similarity/equality.
//
//
inline bool Vec3f::operator==( const Vec3f& vec ) const {
return (x == vec.x) && (y == vec.y) && (z == vec.z);
}
inline bool Vec3f::operator!=( const Vec3f& vec ) const {
return (x != vec.x) || (y != vec.y) || (z != vec.z);
}
inline bool Vec3f::match( const Vec3f& vec, float tolerance ) const{
return (fabs(x - vec.x) < tolerance)
&& (fabs(y - vec.y) < tolerance)
&& (fabs(z - vec.z) < tolerance);
}
/**
* Checks if vectors look in the same direction.
*/
inline bool Vec3f::isAligned( const Vec3f& vec, float tolerance ) const {
float angle = this->angle( vec );
return angle < tolerance;
}
inline bool Vec3f::align( const Vec3f& vec, float tolerance ) const {
return isAligned( vec, tolerance );
}
inline bool Vec3f::isAlignedRad( const Vec3f& vec, float tolerance ) const {
float angle = this->angleRad( vec );
return angle < tolerance;
}
inline bool Vec3f::alignRad( const Vec3f& vec, float tolerance ) const {
return isAlignedRad( vec, tolerance );
}
// Operator overloading for Vec3f
//
//
// inline ostream& operator<<(ostream& os, const Vec3f& vec) {
// os << vec.x << ", " << vec.y << ", " << vec.z;
// return os;
// }
// inline istream& operator>>(istream& is, Vec3f& vec) {
// is >> vec.x;
// is.ignore(2);
// is >> vec.y;
// is.ignore(2);
// is >> vec.z;
// return is;
// }
inline Vec3f Vec3f::operator+( const Vec3f& pnt ) const {
return Vec3f( x+pnt.x, y+pnt.y, z+pnt.z );
}
inline Vec3f& Vec3f::operator+=( const Vec3f& pnt ) {
x+=pnt.x;
y+=pnt.y;
z+=pnt.z;
return *this;
}
inline Vec3f Vec3f::operator-( const Vec3f& vec ) const {
return Vec3f( x-vec.x, y-vec.y, z-vec.z );
}
inline Vec3f& Vec3f::operator-=( const Vec3f& vec ) {
x -= vec.x;
y -= vec.y;
z -= vec.z;
return *this;
}
inline Vec3f Vec3f::operator*( const Vec3f& vec ) const {
return Vec3f( x*vec.x, y*vec.y, z*vec.z );
}
inline Vec3f& Vec3f::operator*=( const Vec3f& vec ) {
x*=vec.x;
y*=vec.y;
z*=vec.z;
return *this;
}
inline Vec3f Vec3f::operator/( const Vec3f& vec ) const {
return Vec3f( vec.x!=0 ? x/vec.x : x , vec.y!=0 ? y/vec.y : y, vec.z!=0 ? z/vec.z : z );
}
inline Vec3f& Vec3f::operator/=( const Vec3f& vec ) {
vec.x!=0 ? x/=vec.x : x;
vec.y!=0 ? y/=vec.y : y;
vec.z!=0 ? z/=vec.z : z;
return *this;
}
inline Vec3f Vec3f::operator-() const {
return Vec3f( -x, -y, -z );
}
//operator overloading for float
//
//
//inline void Vec3f::operator=( const float f){
// x = f;
// y = f;
// z = f;
//}
inline Vec3f Vec3f::operator+( const float f ) const {
return Vec3f( x+f, y+f, z+f);
}
inline Vec3f& Vec3f::operator+=( const float f ) {
x += f;
y += f;
z += f;
return *this;
}
inline Vec3f Vec3f::operator-( const float f ) const {
return Vec3f( x-f, y-f, z-f);
}
inline Vec3f& Vec3f::operator-=( const float f ) {
x -= f;
y -= f;
z -= f;
return *this;
}
inline Vec3f Vec3f::operator*( const float f ) const {
return Vec3f( x*f, y*f, z*f );
}
inline Vec3f& Vec3f::operator*=( const float f ) {
x*=f;
y*=f;
z*=f;
return *this;
}
inline Vec3f Vec3f::operator/( const float f ) const {
if(f == 0) return Vec3f( x, y, z);
return Vec3f( x/f, y/f, z/f );
}
inline Vec3f& Vec3f::operator/=( const float f ) {
if(f == 0) return *this;
x/=f;
y/=f;
z/=f;
return *this;
}
//Scale
//
//
// inline Vec3f Vec3f::rescaled( const float length ) const {
// return getScaled(length);
// }
inline Vec3f Vec3f::getScaled( const float length ) const {
float l = (float)sqrt(x*x + y*y + z*z);
if( l > 0 )
return Vec3f( (x/l)*length, (y/l)*length, (z/l)*length );
else
return Vec3f();
}
// inline Vec3f& Vec3f::rescale( const float length ) {
// return scale(length);
// }
inline Vec3f& Vec3f::scale( const float length ) {
float l = (float)sqrt(x*x + y*y + z*z);
if (l > 0) {
x = (x/l)*length;
y = (y/l)*length;
z = (z/l)*length;
}
return *this;
}
// Rotation
//
//
// inline Vec3f Vec3f::rotated( float angle, const Vec3f& axis ) const {
// return getRotated(angle, axis);
// }
inline Vec3f Vec3f::getRotated( float angle, const Vec3f& axis ) const {
Vec3f ax = axis.getNormalized();
float a = (float)(angle*DEG_TO_RAD);
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
return Vec3f( x*(ax.x*ax.x*cosb + cosa)
+ y*(ax.x*ax.y*cosb - ax.z*sina)
+ z*(ax.x*ax.z*cosb + ax.y*sina),
x*(ax.y*ax.x*cosb + ax.z*sina)
+ y*(ax.y*ax.y*cosb + cosa)
+ z*(ax.y*ax.z*cosb - ax.x*sina),
x*(ax.z*ax.x*cosb - ax.y*sina)
+ y*(ax.z*ax.y*cosb + ax.x*sina)
+ z*(ax.z*ax.z*cosb + cosa) );
}
inline Vec3f Vec3f::getRotatedRad( float angle, const Vec3f& axis ) const {
Vec3f ax = axis.getNormalized();
float a = angle;
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
return Vec3f( x*(ax.x*ax.x*cosb + cosa)
+ y*(ax.x*ax.y*cosb - ax.z*sina)
+ z*(ax.x*ax.z*cosb + ax.y*sina),
x*(ax.y*ax.x*cosb + ax.z*sina)
+ y*(ax.y*ax.y*cosb + cosa)
+ z*(ax.y*ax.z*cosb - ax.x*sina),
x*(ax.z*ax.x*cosb - ax.y*sina)
+ y*(ax.z*ax.y*cosb + ax.x*sina)
+ z*(ax.z*ax.z*cosb + cosa) );
}
inline Vec3f& Vec3f::rotate( float angle, const Vec3f& axis ) {
Vec3f ax = axis.getNormalized();
float a = (float)(angle*DEG_TO_RAD);
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
float nx = x*(ax.x*ax.x*cosb + cosa)
+ y*(ax.x*ax.y*cosb - ax.z*sina)
+ z*(ax.x*ax.z*cosb + ax.y*sina);
float ny = x*(ax.y*ax.x*cosb + ax.z*sina)
+ y*(ax.y*ax.y*cosb + cosa)
+ z*(ax.y*ax.z*cosb - ax.x*sina);
float nz = x*(ax.z*ax.x*cosb - ax.y*sina)
+ y*(ax.z*ax.y*cosb + ax.x*sina)
+ z*(ax.z*ax.z*cosb + cosa);
x = nx; y = ny; z = nz;
return *this;
}
inline Vec3f& Vec3f::rotateRad(float angle, const Vec3f& axis ) {
Vec3f ax = axis.getNormalized();
float a = angle;
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
float nx = x*(ax.x*ax.x*cosb + cosa)
+ y*(ax.x*ax.y*cosb - ax.z*sina)
+ z*(ax.x*ax.z*cosb + ax.y*sina);
float ny = x*(ax.y*ax.x*cosb + ax.z*sina)
+ y*(ax.y*ax.y*cosb + cosa)
+ z*(ax.y*ax.z*cosb - ax.x*sina);
float nz = x*(ax.z*ax.x*cosb - ax.y*sina)
+ y*(ax.z*ax.y*cosb + ax.x*sina)
+ z*(ax.z*ax.z*cosb + cosa);
x = nx; y = ny; z = nz;
return *this;
}
// const???
// inline Vec3f Vec3f::rotated(float ax, float ay, float az) {
// return getRotated(ax,ay,az);
// }
inline Vec3f Vec3f::getRotated(float ax, float ay, float az) const {
float a = (float)cos(DEG_TO_RAD*(ax));
float b = (float)sin(DEG_TO_RAD*(ax));
float c = (float)cos(DEG_TO_RAD*(ay));
float d = (float)sin(DEG_TO_RAD*(ay));
float e = (float)cos(DEG_TO_RAD*(az));
float f = (float)sin(DEG_TO_RAD*(az));
float nx = c * e * x - c * f * y + d * z;
float ny = (a * f + b * d * e) * x + (a * e - b * d * f) * y - b * c * z;
float nz = (b * f - a * d * e) * x + (a * d * f + b * e) * y + a * c * z;
return Vec3f( nx, ny, nz );
}
inline Vec3f Vec3f::getRotatedRad(float ax, float ay, float az) const {
float a = cos(ax);
float b = sin(ax);
float c = cos(ay);
float d = sin(ay);
float e = cos(az);
float f = sin(az);
float nx = c * e * x - c * f * y + d * z;
float ny = (a * f + b * d * e) * x + (a * e - b * d * f) * y - b * c * z;
float nz = (b * f - a * d * e) * x + (a * d * f + b * e) * y + a * c * z;
return Vec3f( nx, ny, nz );
}
inline Vec3f& Vec3f::rotate(float ax, float ay, float az) {
float a = (float)cos(DEG_TO_RAD*(ax));
float b = (float)sin(DEG_TO_RAD*(ax));
float c = (float)cos(DEG_TO_RAD*(ay));
float d = (float)sin(DEG_TO_RAD*(ay));
float e = (float)cos(DEG_TO_RAD*(az));
float f = (float)sin(DEG_TO_RAD*(az));
float nx = c * e * x - c * f * y + d * z;
float ny = (a * f + b * d * e) * x + (a * e - b * d * f) * y - b * c * z;
float nz = (b * f - a * d * e) * x + (a * d * f + b * e) * y + a * c * z;
x = nx; y = ny; z = nz;
return *this;
}
inline Vec3f& Vec3f::rotateRad(float ax, float ay, float az) {
float a = cos(ax);
float b = sin(ax);
float c = cos(ay);
float d = sin(ay);
float e = cos(az);
float f = sin(az);
float nx = c * e * x - c * f * y + d * z;
float ny = (a * f + b * d * e) * x + (a * e - b * d * f) * y - b * c * z;
float nz = (b * f - a * d * e) * x + (a * d * f + b * e) * y + a * c * z;
x = nx; y = ny; z = nz;
return *this;
}
// Rotate point by angle (deg) around line defined by pivot and axis.
//
//
// inline Vec3f Vec3f::rotated( float angle,
// const Vec3f& pivot,
// const Vec3f& axis ) const{
// return getRotated(angle, pivot, axis);
// }
inline Vec3f Vec3f::getRotated( float angle,
const Vec3f& pivot,
const Vec3f& axis ) const
{
Vec3f ax = axis.getNormalized();
float tx = x - pivot.x;
float ty = y - pivot.y;
float tz = z - pivot.z;
float a = (float)(angle*DEG_TO_RAD);
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
float xrot = tx*(ax.x*ax.x*cosb + cosa)
+ ty*(ax.x*ax.y*cosb - ax.z*sina)
+ tz*(ax.x*ax.z*cosb + ax.y*sina);
float yrot = tx*(ax.y*ax.x*cosb + ax.z*sina)
+ ty*(ax.y*ax.y*cosb + cosa)
+ tz*(ax.y*ax.z*cosb - ax.x*sina);
float zrot = tx*(ax.z*ax.x*cosb - ax.y*sina)
+ ty*(ax.z*ax.y*cosb + ax.x*sina)
+ tz*(ax.z*ax.z*cosb + cosa);
return Vec3f( xrot+pivot.x, yrot+pivot.y, zrot+pivot.z );
}
inline Vec3f Vec3f::getRotatedRad( float angle,
const Vec3f& pivot,
const Vec3f& axis ) const
{
Vec3f ax = axis.getNormalized();
float tx = x - pivot.x;
float ty = y - pivot.y;
float tz = z - pivot.z;
float a = angle;
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
float xrot = tx*(ax.x*ax.x*cosb + cosa)
+ ty*(ax.x*ax.y*cosb - ax.z*sina)
+ tz*(ax.x*ax.z*cosb + ax.y*sina);
float yrot = tx*(ax.y*ax.x*cosb + ax.z*sina)
+ ty*(ax.y*ax.y*cosb + cosa)
+ tz*(ax.y*ax.z*cosb - ax.x*sina);
float zrot = tx*(ax.z*ax.x*cosb - ax.y*sina)
+ ty*(ax.z*ax.y*cosb + ax.x*sina)
+ tz*(ax.z*ax.z*cosb + cosa);
return Vec3f( xrot+pivot.x, yrot+pivot.y, zrot+pivot.z );
}
inline Vec3f& Vec3f::rotate( float angle,
const Vec3f& pivot,
const Vec3f& axis )
{
Vec3f ax = axis.getNormalized();
x -= pivot.x;
y -= pivot.y;
z -= pivot.z;
float a = (float)(angle*DEG_TO_RAD);
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
float xrot = x*(ax.x*ax.x*cosb + cosa)
+ y*(ax.x*ax.y*cosb - ax.z*sina)
+ z*(ax.x*ax.z*cosb + ax.y*sina);
float yrot = x*(ax.y*ax.x*cosb + ax.z*sina)
+ y*(ax.y*ax.y*cosb + cosa)
+ z*(ax.y*ax.z*cosb - ax.x*sina);
float zrot = x*(ax.z*ax.x*cosb - ax.y*sina)
+ y*(ax.z*ax.y*cosb + ax.x*sina)
+ z*(ax.z*ax.z*cosb + cosa);
x = xrot + pivot.x;
y = yrot + pivot.y;
z = zrot + pivot.z;
return *this;
}
inline Vec3f& Vec3f::rotateRad( float angle,
const Vec3f& pivot,
const Vec3f& axis )
{
Vec3f ax = axis.getNormalized();
x -= pivot.x;
y -= pivot.y;
z -= pivot.z;
float a = angle;
float sina = sin( a );
float cosa = cos( a );
float cosb = 1.0f - cosa;
float xrot = x*(ax.x*ax.x*cosb + cosa)
+ y*(ax.x*ax.y*cosb - ax.z*sina)
+ z*(ax.x*ax.z*cosb + ax.y*sina);
float yrot = x*(ax.y*ax.x*cosb + ax.z*sina)
+ y*(ax.y*ax.y*cosb + cosa)
+ z*(ax.y*ax.z*cosb - ax.x*sina);
float zrot = x*(ax.z*ax.x*cosb - ax.y*sina)
+ y*(ax.z*ax.y*cosb + ax.x*sina)
+ z*(ax.z*ax.z*cosb + cosa);
x = xrot + pivot.x;
y = yrot + pivot.y;
z = zrot + pivot.z;
return *this;
}
// Map point to coordinate system defined by origin, vx, vy, and vz.
//
//
// inline Vec3f Vec3f::mapped( const Vec3f& origin,
// const Vec3f& vx,
// const Vec3f& vy,
// const Vec3f& vz ) const{
// return getMapped(origin, vx, vy, vz);
// }
inline Vec3f Vec3f::getMapped( const Vec3f& origin,
const Vec3f& vx,
const Vec3f& vy,
const Vec3f& vz ) const
{
return Vec3f( origin.x + x*vx.x + y*vy.x + z*vz.x,
origin.y + x*vx.y + y*vy.y + z*vz.y,
origin.z + x*vx.z + y*vy.z + z*vz.z );
}
inline Vec3f& Vec3f::map( const Vec3f& origin,
const Vec3f& vx,
const Vec3f& vy,
const Vec3f& vz )
{
float xmap = origin.x + x*vx.x + y*vy.x + z*vz.x;
float ymap = origin.y + x*vx.y + y*vy.y + z*vz.y;
z = origin.z + x*vx.z + y*vy.z + z*vz.z;
x = xmap;
y = ymap;
return *this;
}
// Distance between two points.
//
//
inline float Vec3f::distance( const Vec3f& pnt) const {
float vx = x-pnt.x;
float vy = y-pnt.y;
float vz = z-pnt.z;
return (float)sqrt(vx*vx + vy*vy + vz*vz);
}
// inline float Vec3f::distanceSquared( const Vec3f& pnt ) const{
// return squareDistance(pnt);
// }
inline float Vec3f::squareDistance( const Vec3f& pnt ) const {
float vx = x-pnt.x;
float vy = y-pnt.y;
float vz = z-pnt.z;
return vx*vx + vy*vy + vz*vz;
}
// Linear interpolation.
//
//
/**
* p==0.0 results in this point, p==0.5 results in the
* midpoint, and p==1.0 results in pnt being returned.
*/
// inline Vec3f Vec3f::interpolated( const Vec3f& pnt, float p ) const {
// return getInterpolated(pnt,p);
// }
inline Vec3f Vec3f::getInterpolated( const Vec3f& pnt, float p ) const {
return Vec3f( x*(1-p) + pnt.x*p,
y*(1-p) + pnt.y*p,
z*(1-p) + pnt.z*p );
}
inline Vec3f& Vec3f::interpolate( const Vec3f& pnt, float p ) {
x = x*(1-p) + pnt.x*p;
y = y*(1-p) + pnt.y*p;
z = z*(1-p) + pnt.z*p;
return *this;
}
// inline Vec3f Vec3f::middled( const Vec3f& pnt ) const {
// return getMiddle(pnt);
// }
inline Vec3f Vec3f::getMiddle( const Vec3f& pnt ) const {
return Vec3f( (x+pnt.x)/2.0f, (y+pnt.y)/2.0f, (z+pnt.z)/2.0f );
}
inline Vec3f& Vec3f::middle( const Vec3f& pnt ) {
x = (x+pnt.x)/2.0f;
y = (y+pnt.y)/2.0f;
z = (z+pnt.z)/2.0f;
return *this;
}
// Average (centroid) among points.
// Addition is sometimes useful for calculating averages too.
//
//
inline Vec3f& Vec3f::average( const Vec3f* points, int num ) {
x = 0.f;
y = 0.f;
z = 0.f;
for( int i=0; i<num; i++) {
x += points[i].x;
y += points[i].y;
z += points[i].z;
}
x /= num;
y /= num;
z /= num;
return *this;
}
// Normalization
//
//
// inline Vec3f Vec3f::normalized() const {
// return getNormalized();
// }
inline Vec3f Vec3f::getNormalized() const {
float length = (float)sqrt(x*x + y*y + z*z);
if( length > 0 ) {
return Vec3f( x/length, y/length, z/length );
} else {
return Vec3f();
}
}
inline Vec3f& Vec3f::normalize() {
float length = (float)sqrt(x*x + y*y + z*z);
if( length > 0 ) {
x /= length;
y /= length;
z /= length;
}
return *this;
}
// Limit length.
//
//
// inline Vec3f Vec3f::limited(float max) const {
// return getLimited(max);
// }
inline Vec3f Vec3f::getLimited(float max) const {
Vec3f limited;
float lengthSquared = (x*x + y*y + z*z);
if( lengthSquared > max*max && lengthSquared > 0 ) {
float ratio = max/(float)sqrt(lengthSquared);
limited.set( x*ratio, y*ratio, z*ratio);
} else {
limited.set(x,y,z);
}
return limited;
}
inline Vec3f& Vec3f::limit(float max) {
float lengthSquared = (x*x + y*y + z*z);
if( lengthSquared > max*max && lengthSquared > 0 ) {
float ratio = max/(float)sqrt(lengthSquared);
x *= ratio;
y *= ratio;
z *= ratio;
}
return *this;
}
// Perpendicular vector.
//
//
// inline Vec3f Vec3f::crossed( const Vec3f& vec ) const {
// return getCrossed(vec);
// }
inline Vec3f Vec3f::getCrossed( const Vec3f& vec ) const {
return Vec3f( y*vec.z - z*vec.y,
z*vec.x - x*vec.z,
x*vec.y - y*vec.x );
}
inline Vec3f& Vec3f::cross( const Vec3f& vec ) {
float _x = y*vec.z - z*vec.y;
float _y = z*vec.x - x*vec.z;
z = x*vec.y - y*vec.x;
x = _x;
y = _y;
return *this;
}
/**
* Normalized perpendicular.
*/
// inline Vec3f Vec3f::perpendiculared( const Vec3f& vec ) const {
// return getPerpendicular(vec);
// }
inline Vec3f Vec3f::getPerpendicular( const Vec3f& vec ) const {
float crossX = y*vec.z - z*vec.y;
float crossY = z*vec.x - x*vec.z;
float crossZ = x*vec.y - y*vec.x;
float length = (float)sqrt(crossX*crossX +
crossY*crossY +
crossZ*crossZ);
if( length > 0 )
return Vec3f( crossX/length, crossY/length, crossZ/length );
else
return Vec3f();
}
inline Vec3f& Vec3f::perpendicular( const Vec3f& vec ) {
float crossX = y*vec.z - z*vec.y;
float crossY = z*vec.x - x*vec.z;
float crossZ = x*vec.y - y*vec.x;
float length = (float)sqrt(crossX*crossX +
crossY*crossY +
crossZ*crossZ);
if( length > 0 ) {
x = crossX/length;
y = crossY/length;
z = crossZ/length;
} else {
x = 0.f;
y = 0.f;
z = 0.f;
}
return *this;
}
// Length
//
//
inline float Vec3f::length() const {
return (float)sqrt( x*x + y*y + z*z );
}
inline float Vec3f::lengthSquared() const {
return (float)(x*x + y*y + z*z);
}
/**
* Angle (deg) between two vectors.
* This is an unsigned relative angle from 0 to 180.
* http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
*/
inline float Vec3f::angle( const Vec3f& vec ) const {
Vec3f n1 = this->getNormalized();
Vec3f n2 = vec.getNormalized();
return (float)(acos( n1.dot(n2) )*RAD_TO_DEG);
}
inline float Vec3f::angleRad( const Vec3f& vec ) const {
Vec3f n1 = this->getNormalized();
Vec3f n2 = vec.getNormalized();
return (float)acos( n1.dot(n2) );
}
/**
* Dot Product.
*/
inline float Vec3f::dot( const Vec3f& vec ) const {
return x*vec.x + y*vec.y + z*vec.z;
}
// Non-Member operators
//
//
inline Vec3f operator+( float f, const Vec3f& vec ) {
return Vec3f( f+vec.x, f+vec.y, f+vec.z );
}
inline Vec3f operator-( float f, const Vec3f& vec ) {
return Vec3f( f-vec.x, f-vec.y, f-vec.z );
}
inline Vec3f operator*( float f, const Vec3f& vec ) {
return Vec3f( f*vec.x, f*vec.y, f*vec.z );
}
inline Vec3f operator/( float f, const Vec3f& vec ) {
return Vec3f( f/vec.x, f/vec.y, f/vec.z);
}
/// \endcond
#pragma once
#include <cstddef>
#include <math.h>
class Vec3f;
class Vec4f;
using namespace std;
#ifndef PI
#define PI 3.14159265358979323846
#endif
#ifndef TWO_PI
#define TWO_PI 6.28318530717958647693
#endif
#ifndef M_TWO_PI
#define M_TWO_PI 6.28318530717958647693
#endif
#ifndef FOUR_PI
#define FOUR_PI 12.56637061435917295385
#endif
#ifndef HALF_PI
#define HALF_PI 1.57079632679489661923
#endif
#ifndef DEG_TO_RAD
#define DEG_TO_RAD (PI/180.0)
#endif
#ifndef RAD_TO_DEG
#define RAD_TO_DEG (180.0/PI)
#endif
#ifndef MIN
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#endif
#ifndef CLAMP
#define CLAMP(val,min,max) ((val) < (min) ? (min) : ((val > max) ? (max) : (val)))
#endif
#ifndef ABS
#define ABS(x) (((x) < 0) ? -(x) : (x))
#endif
// #include "ofConstants.h"
/// \brief
/// Vec2f is a class for storing a two dimensional vector.
///
/// Moving through space requires knowledge of where things are and where they are going.
/// Vector Maths is the class of mathematics that gives us control over these
/// things in space, allowing for elegant and intuitive descriptions of complex
/// structures and movement. Vectors are at the heart of animations, particle
/// systems, and 2D and 3D graphics.
///
/// Vectors in mathematics in general are entities with magnitude (also called
/// length) and direction. A vector whose magnitude is 1 (ie a vector that is
/// *normalized*) is called a *unit vector*. Unit vectors are very handy for
/// storing directions as they can be easily scaled up (or down) to represent
/// motion in a particular direction with a particular length.
///
/// *You will also see the term vector used to describe an array of objects in C++
/// (such as text strings). Don't let this confuse you, they are quite different:
/// one of them is a mathematical term for a fixed-length list of numbers that
/// you can do mathematical operations on, the other is a C++-specific term that
/// means 'dynamically sizeable array'.*
///
/// Vec2f has two member variables, x and y, which allow to conveniently store
/// 2D properties of an object such as its position, velocity, or acceleration.
///
/// ~~~~{.cpp}
/// Vec2f v1; // v1.x is 0, v1.y is 0
/// v1.set( 10, 50 ); // now v1.x is 10, v1.y is 50
/// ~~~~
///
/// Using Vec2f greatly simplifies arithmetic operations in two dimensions. For
/// example if you have two vectors v1 and v2, both of which represent a 2D change
/// in position, you can find the total change of position of both of them just by
/// doing an addition v1 + v2:
///
/// ~~~~{.cpp}
/// Vec2f v1(5, 2); // v1 represents walking 5 steps forward then 2 steps sideways
/// Vec2f v2;
/// v2.set(1, 1); // v2 represents walking 1 step forward then 1 step sideways
/// // what happens if you do v1 followed by v2? just add v1 and v2 together:
/// Vec2f result = v1 + v2; // result is 6 steps forward then 3 steps sideways
/// ~~~~
///
/// You can scale an Vec2f by multiplying it with a float:
///
/// ~~~~{.cpp}
/// Vec2f v1(5, 2); // walk 5 steps forward and 2 steps right
/// // what happens if we do v1 three times?
/// Vec2f result = v1 * 3; // result is 15 steps forward and 6 steps right
/// ~~~~
///
/// This also works for subtraction and division.
///
/// As you can see this really makes dealing with vectors as easy as dealing with
/// single floats or ints, and can reduce the number of lines of code you have to
/// write by half, at the same time making your code much easier to read and
/// understand!
///
/// \sa Vec3f for 3D vectors
/// \sa Vec4f for 4D vectors
class Vec2f {
public:
/// \cond INTERNAL
static const int DIM = 2;
//// \endcond
/// \brief Stores the `x` component of the vector.
float x;
/// \brief Stores the `y` component of the vector.
float y;
//---------------------
/// \name Construct a 2D vector
/// \{
/// \brief Construct a 2D vector.
///
/// ~~~~{.cpp}
/// Vec2f v1; // default: v1.x is 0, v1.y is 0
/// Vec2f v2 = Vec2f(40, 20); // v2.x is 40, v2.y is 20
/// Vec3f v3(0.1, 0.3); // v3.x is 0.1, v3.y is 0.3
/// ~~~~
///
Vec2f();
/// \brief Construct a 2D vector with `x` and `y` set to `scalar`
explicit Vec2f( float scalar );
/// \brief Construct a 2D vector with specific `x` and `y components
///
/// ~~~~{.cpp}
/// Vec2f v1; // default: v1.x is 0, v1.y is 0
/// Vec2f v2 = Vec2f(40, 20); // v2.x is 40, v2.y is 20
/// Vec3f v3(0.1, 0.3); // v3.x is 0.1, v3.y is 0.3
/// ~~~~
///
/// \param x The x component
/// \param y The y component
Vec2f( float x, float y );
/// \brief Create a 2D vector (Vec2f) from a 3D vector (Vec3f) by
/// \throwing away the z component of the 3D vector.
///
/// ~~~~{.cpp}
/// Vec3f mom3d(40, 20, 50); // 3d vector
/// Vec2f v(mom3d); // v.x is 40, v.y is 20
/// ~~~~
///
Vec2f( const Vec3f& vec );
/// \brief Create a 2D vector (Vec2f) from a 4D vector (Vec4f) by throwing away the z
/// and w components of the 4D vector.
///
/// ~~~~{.cpp}
/// Vec4f mom4d(40, 20, 50, 80); // 4d vector
/// Vec2f v(mom4d); // v.x is 40, v.y is 20
/// ~~~~
///
Vec2f( const Vec4f& vec );
/// \}
//---------------------
/// \name Access components
/// \{
/// \brief Returns a pointer to the memory position of the first element of the vector (x);
/// the second element (y) immediately follows it in memory.
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// float * v1Ptr = v1.getPtr();
/// float x = *(v1Ptr); // x is 40
/// float y = *(v1Ptr+1); // y is 20
/// ~~~~
///
/// This is very useful when using arrays of Vec2fs to store geometry
/// information, as it allows the vector to be treated as a simple C array of
/// floats that can be passed verbatim to OpenGL.
float * getPtr() {
return (float*)&x;
}
const float * getPtr() const {
return (const float *)&x;
}
/// \brief Allows to access the x and y components of an Vec2f as though it is an array
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// float x = v1[0]; // x is 40
/// float y = v1[1]; // y is 20
/// ~~~~
///
/// This function can be handy if you want to do the same operation to both x and
/// y components, as it means you can just make a for loop that repeats twice.
float& operator[]( int n ){
return getPtr()[n];
}
float operator[]( int n ) const {
return getPtr()[n];
}
/// \brief Set x and y components of this vector with just one function call.
///
/// ~~~~{.cpp}
/// Vec2f v1;
/// v1.set(40, 20);
/// ~~~~
///
void set( float x, float y );
/// \brief Set the x and y components of this vector by copying the corresponding values from vec.
///
/// ~~~~{.cpp}
/// Vec2f v1(40, 20);
/// Vec2f v2;
/// v2.set(v1); // v2.x is 40, v2.y is 20
/// ~~~~
///
void set( const Vec2f& vec );
void set( float scalar );
/// \}
//---------------------
/// \name Comparison
/// \{
/// \brief Check for equality between two Vec2f
///
/// ~~~~{.cpp}
/// Vec2f v1(40, 20);
/// Vec2f v2(50, 30);
/// Vec2f v3(40, 20);
/// // ( v1 == v2 ) is false
/// // ( v1 == v3 ) is true
/// ~~~~
///
/// \returns true if each component is the same as the corresponding
/// component in vec, ie if x == vec.x and y == vec.y; otherwise returns
/// false.
bool operator==( const Vec2f& vec ) const;
/// \brief Check for inequality between two Vec2f
///
/// ~~~~{.cpp}
/// Vec2f v1(40, 20);
/// Vec2f v2(50, 30);
/// Vec2f v3(40, 20);
/// // ( v1 != v2 ) is true
/// // ( v1 != v3 ) is false
/// ~~~~
///
/// \returns true if any component is different to its corresponding
/// component in vec, ie if 'x != vec.x' or 'y != vec.y', otherwise returns
/// false.
bool operator!=( const Vec2f& vec ) const;
/// \brief Returns true if each component is *close enough* to its corresponding
/// component in vec, where what is *close enough* is determined by the value of
/// tolerance:
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(40.01, 19.999);
/// // v1.match(v2, 0.1) returns true
/// // v1.match(v2, 0.001) returns false
/// ~~~~
///
/// This is handy if, for example, you want to find out when a point becomes
/// *close enough* to another point to trigger an event.
///
bool match( const Vec2f& vec, float tolerance = 0.0001f ) const;
/// \brief Determine if two vectors are aligned
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(4, 2);
/// v1.isAligned(v2) // returns true
/// ~~~~
/// \param vec The vector to compare alignment with
/// \param tolerance an angle tolerance/threshold (specified in degrees) for deciding if the vectors are sufficiently aligned.
/// \returns true if both vectors are aligned (pointing in the same direction).
bool isAligned( const Vec2f& vec, float tolerance = 0.0001f ) const;
/// \brief Determine if two vectors are aligned with tolerance in radians
/// \param vec The vector to compare alignment with
/// \param tolerance an angle tolerance/threshold (specified in radians) for deciding if the vectors are sufficiently aligned.
/// \sa isAligned()
bool isAlignedRad( const Vec2f& vec, float tolerance = 0.0001f ) const;
/// \brief Determine if two vectors are aligned
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(4, 2);
/// v1.align(v2) // returns true
/// ~~~~
/// \param vec The vector to compare alignment with
/// \param tolerance an angle tolerance/threshold (specified in degrees) for deciding if the vectors are sufficiently aligned.
/// \returns true if both vectors are aligned (pointing in the same direction).
bool align( const Vec2f& vec, float tolerance = 0.0001f ) const;
/// \brief Determine if two vectors are aligned with tolerance in radians
/// \param vec The vector to compare alignment with
/// \param tolerance an angle tolerance/threshold (specified in radians) for deciding if the vectors are sufficiently aligned.
/// \sa align()
bool alignRad( const Vec2f& vec, float tolerance = 0.0001f ) const;
/// \}
//---------------------
/// \name Operators
/// \{
/// \brief Super easy vector addition. Returns a new vector (x+vec.x,y+vec.y).
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(25, 50);
/// Vec3f v3 = v1 + v2; // v3 is (65, 70)
/// ~~~~
Vec2f operator+( const Vec2f& vec ) const;
/// \brief Returns a new vector with a float value f added to both x and y members.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// Vec2f v2 = v1 + 10; // (12, 15)
/// ~~~~
Vec2f operator+( const float f ) const;
/// \brief Super easy addition assignment. Adds vec.x to x, and adds vec.y to y.
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(25, 50);
/// v1 += v2; // v1 is (65, 70)
/// ~~~~
Vec2f& operator+=( const Vec2f& vec );
/// \brief Adds a float value f to both x and y members.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// v1 += 10; // (12, 15)
/// ~~~~
Vec2f& operator+=( const float f );
/// \brief Super easy vector subtraction. Returns a new vector (x-vec.x,y-vec.y).
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(25, 50);
/// Vec3f v3 = v1 - v2; // v3 is (15, -30)
/// ~~~~
Vec2f operator-( const Vec2f& vec ) const;
/// \brief Returns a new vector with a float value f subtracted from both x and y members.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// Vec2f v2 = v1 - 10; // (-8, -5)
/// ~~~~
Vec2f operator-( const float f ) const;
/// \brief Returns a new Vec2f that is the inverted version (mirrored in X and Y) of this vector.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// Vec2f v2 = -v1; // (-2, -5)
/// ~~~~
Vec2f operator-() const;
/// \brief Super easy subtraction assignment. Subtracts vec.x from x, and subtracts vec.y from y.
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(25, 50);
/// v1 -= v2; // v1 is (15, -30)
/// ~~~~
Vec2f& operator-=( const Vec2f& vec );
/// \brief Subtract a float value f from both x and y members.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// v1 -= 10; // (-8, -5)
/// ~~~~
Vec2f& operator-=( const float f );
/// \brief Returns a new vector (x*vec.x , y*vec.y).
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(2, 4);
/// Vec2f v3 = v1 * v2; // (80, 80)
/// ~~~~
///
/// Useful for scaling a 2D point by a non-uniform scale.
///
Vec2f operator*( const Vec2f& vec ) const;
/// \brief Return a new Vec2f that is this vector scaled by multiplying both x
/// and y members by the float.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// Vec2f v2 = v1 * 4; // (8, 20)
/// ~~~~
Vec2f operator*( const float f ) const;
/// \brief Multiplies x by vec.x, and multiplies y by vec.y.
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(2, 4);
/// v1 *= v2; // v1 is now (80, 80)
/// ~~~~
///
/// Useful for scaling a 2D point by a non-uniform scale.
Vec2f& operator*=( const Vec2f& vec );
/// \brief Scale this vector by multiplying both x and y members by f.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// v1 *= 4; // (8, 20)
/// ~~~~
Vec2f& operator*=( const float f );
/// \brief Returns a new vector (x/vec.x,y/vec.y).
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(2, 4);
/// Vec3f v3 = v1 / v2; // (20, 5)
/// ~~~~
///
/// Useful for scaling a 2D point by a non-uniform scale.
Vec2f operator/( const Vec2f& vec ) const;
/// \brief Return a new Vec2f that is this vector scaled by dividing
/// both x and y members by f.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// Vec2f v2 = v1 / 4; // (0.5, 1.25)
/// ~~~~
Vec2f operator/( const float f ) const;
/// \brief Divides x by vec.x, and divides y by vec.y.
///
/// ~~~~{.cpp}
/// Vec2f v1 = Vec2f(40, 20);
/// Vec2f v2 = Vec2f(2, 4);
/// v1 *= v2; // v1 is now (20, 5)
/// ~~~~
///
/// Useful for scaling a 2D point by a non-uniform scale.
Vec2f& operator/=( const Vec2f& vec );
/// \brief Scale this vector by dividing both x and y members by f.
///
/// ~~~~{.cpp}
/// Vec2f v1(2, 5);
/// v1 /= 4; // (0.5, 1.25)
/// ~~~~
Vec2f& operator/=( const float f );
/// \cond INTERNAL
// friend ostream& operator<<(ostream& os, const Vec2f& vec);
// friend istream& operator>>(istream& is, const Vec2f& vec);
/// \endcond
/// \}
//---------------------
/// \name Simple manipulations
/// \{
/// Return a new Vec2f that is the result of scaling this vector up or down so
/// that it has the requested length.
///
/// ~~~~{.cpp}
/// Vec2f v1( 3, 4 ); // length is 5
/// Vec2f v2 = v1.getScaled( 15 ); // ( 9, 12 ), length is now 15
/// ~~~~Vec2f
///
/// \sa scale()
Vec2f getScaled( const float length ) const;
/// \brief Scales this vector up or down so that it has the requested length.
///
/// ~~~~{.cpp}
/// Vec2f v1( 3, 4 ); // length is 5
/// v1.scale( 15 ); // v1 is now (9, 12), with length 15
/// ~~~~
///
/// \sa getScaled()
Vec2f& scale( const float length );
/// \brief Return a new Vec2f that is the result of rotating this vector by angle
/// degrees around the origin.
///
/// ~~~~{.cpp}
/// Vec2f v1(1, 0);
/// Vec2f v2 = v1.getRotated( 45 ); // v2 is (√2, √2)
/// Vec3f v3 = v2.getRotated( 45 ); // v3 is (0, 1)
/// ~~~~
///
/// \sa getRotatedRad()
/// \sa rotate()
Vec2f getRotated( float angle ) const;
/// \brief Like getRotated() but rotates around `pivot` rather than around the origin
Vec2f getRotated( float angle, const Vec2f& pivot ) const;
/// \brief Return a new Vec2f that is the result of rotating this vector by angle
/// radians around the origin.
///
/// ~~~~{.cpp}
/// Vec2f v1(1, 0);
/// Vec2f v2 = v1.getRotatedRad( PI/4 ); // v2 is (√2, √2)
/// Vec3f v3 = v2.getRotatedRad( PI/4 ); // v3 is (0, 1)
/// ~~~~
///
Vec2f getRotatedRad( float angle ) const;
/// \brief Like getRotatedRad() but rotates around `pivot` rather than around the origin
Vec2f getRotatedRad( float angle, const Vec2f& pivot ) const;
/// \brief Rotate this vector by angle degrees around the origin.
///
/// ~~~~{.cpp}
/// Vec2f v1(1, 0);
/// v1.rotate( 45 ); // (√2, √2)
/// v1.rotate( 45 ); // (0, 1)
/// ~~~~
///
/// \sa getRotated()
Vec2f& rotate( float angle );
/// \brief Like rotate() but rotates around `pivot` rather than around the origin
Vec2f& rotate( float angle, const Vec2f& pivot );
/// \brief Rotate this vector by angle radians around the origin.
///
/// ~~~~{.cpp}
/// Vec2f v1(1, 0);
/// v1.rotate( PI/4 ); // (√2, √2)
/// v1.rotate( PI/4 ); // (0, 1)
/// ~~~~
///
/// \sa getRotatedRad()
Vec2f& rotateRad( float angle );
/// \brief Like rotateRad() but rotates around `pivot` rather than around the origin
Vec2f& rotateRad( float angle, const Vec2f& pivot );
/// \brief Get vector mapped to new coordinate system
///
/// In most cases you want `vx` and `vy` to be perpendicular and of unit length; if
/// they are not perpendicular you will have shearing as part of the mapping, and
/// if they are not of unit length you will have scaling as part of the mapping.
///
/// \returns A new Vec2f calculated by copying this vector and then mapping from
/// its default coordinate system -- origin (0,0), X direction (1,0), Y direction
/// (0,1) -- to a new coordinate system defined with origin at origin, X direction
/// vx, and Y direction vy.
Vec2f getMapped( const Vec2f& origin,
const Vec2f& vx,
const Vec2f& vy ) const;
/// \brief Maps this vector from its default coordinate system -- origin (0,0), X
/// direction (1,0), Y direction (0,1) -- to a new coordinate system defined with
/// origin at origin, X direction vx, and Y direction vy.
///
/// In most case you want vx and vy to be perpendicular and of unit length; if
/// they are not perpendicular you will have shearing as part of the mapping, and
/// if they are not of unit length you will have scaling as part of the mapping.
///
/// \sa perpendicular()
Vec2f& map( const Vec2f& origin,
const Vec2f& vx, const Vec2f& vy );
/// \}
//---------------------
/// \name Distance
/// \{
/// \brief Distance between two points.
///
/// Treats both this vector and pnt as points in 2D space, and calculates and
/// returns the distance between them.
///
/// ~~~~{.cpp}
/// Vec2f p1( 3, 4 );
/// Vec2f p2( 6, 8 );
/// float distance = p1.distance( p2 ); // distance is 5
/// ~~~~
///
/// Distance involves a square root calculation, which is one of the slowest
/// things you can do in programming. If you don't need an exact number but rather
/// just a rough idea of distance (for example when finding the shortest distance
/// of a bunch of points to a reference point, where it doesn't matter exactly
/// what the distances are, you just want the shortest), you can use
/// squareDistance() instead.
///
/// \param pnt The point to calculate the distance to
/// \returns The distance as float
/// \sa squareDistance()
float distance( const Vec2f& pnt) const;
/// \brief Distance between two points squared.
///
/// Treats both this vector and pnt as points in 2D space, and calculates and
/// returns the squared distance between them.
///
/// ~~~~{.cpp}
/// Vec2f p1( 3, 4 );
/// Vec2f p2( 6, 8 );
/// float distance = p1.distance( p2 ); // distance is 5
/// ~~~~
///
/// Use as a much faster alternative to [distance](#distance) if you don't need to
/// know an exact number but rather just a rough idea of distance (for example
/// when finding the shortest distance of a bunch of points to a reference point,
/// where it doesn't matter exactly what the distances are, you just want the
/// shortest). It avoids the square root calculation that is ordinarily required
/// to calculate a length.
///
/// \returns The distance squared as float
/// \sa distance()
float squareDistance( const Vec2f& pnt ) const;
/// \}
//---------------------
/// \name Interpolation
/// \{
/// \brief Linear interpolation
///
/// Perform a linear interpolation of this vector's position towards pnt
/// and return the interpolated position without altering the original
/// vector.
///
/// `p` is normally between 0 and 1 and where 0 means stay the original position and 1
/// means move all the way to pnt, but you can also have p greater than 1
/// overshoot pnt, or less than 0 to move backwards away from pnt.
///
/// ~~~~{.cpp}
/// Vec2f v1( 0, 5 );
/// Vec2f v2( 10, 10 );
/// Vec3f v3 = v1.getInterpolated( v2, 0.5 ); // v3 is (5, 7.5)
/// Vec3f v4 = v1.getInterpolated( v2, 0.8 ); // v4 is (8, 9)
/// ~~~~
///
/// \param pnt The point to move towards
/// \param p The amount to move towards pnt
/// \sa interpolate()
Vec2f getInterpolated( const Vec2f& pnt, float p ) const;
/// \brief Linear interpolation
///
/// Perform a linear interpolation of this vector's position towards pnt. p
/// controls the amount to move towards pnt. p is normally between 0 and 1 and
/// where 0 means stay the original position and 1 means move all the way to pnt,
/// but you can also have p greater than 1 overshoot pnt, or less than 0 to move
/// backwards away from pnt.
///
/// ~~~~{.cpp}
/// Vec2f v1( 0, 5 );
/// Vec2f v2( 10, 10 );
/// // go go gadget zeno
/// v1.interpolate( v2, 0.5 ); // v1 is now (5, 7.5)
/// v1.interpolate( v2, 0.5 ); // v1 is now (7.5, 8.75)
/// v1.interpolate( v2, 0.5 ); // v1 is now (8.75, 9.375)
/// v1.interpolate( v2, 0.5 ); // v1 is now (9.375, 9.6875)
/// ~~~~
///
/// \sa getInterpolated()
Vec2f& interpolate( const Vec2f& pnt, float p );
/// \brief Calculate and return the midpoint between this vector and pnt.
///
/// ~~~~{.cpp}
/// Vec2f v1(5, 0);
/// Vec2f v2(10, 10);
/// Vec3f mid = v1.getMiddle(v2); // mid gets (7.5, 5)
/// ~~~~
///
/// \param pnt The vector to find the middle to
/// \returns The middle between this vector and `pnt`
/// \sa middle()
Vec2f getMiddle( const Vec2f& pnt ) const;
/// \brief Set this vector to the midpoint between itself and pnt.
///
/// ~~~~{.cpp}
/// Vec2f v1( 0, 5 );
/// Vec2f v2( 10, 10 );
/// v1.middle( v2 ); // v1 is now (5, 7.5)
/// v1.middle( v2 ); // v1 is now (7.5, 8.75)
/// v1.middle( v2 ); // v1 is now (8.75, 9.375)
/// v1.middle( v2 ); // v1 is now (9.375, 9.6875)
/// ~~~~
///
/// \sa getMiddle()
Vec2f& middle( const Vec2f& pnt );
/// \brief Average vector over an array of points
///
/// Sets this vector to be the average (*centre of gravity* or *centroid*)
/// of a given array of Vec2f.
///
/// ~~~~{.cpp}
/// int numPoints = 10;
/// Vec2f points[numPoints];
/// for ( int i=0; i<numPoints; i++ ) {
/// points[i].set( ofRandom(0,100), ofRandom(0,100) );
/// }
/// Vec2f centroid;
/// centroid.average( points, numPoints );
/// // centroid now is the centre of gravity/average of all the random points
/// ~~~~
///
/// \param points The array of Vec2f to avarage over
/// \param num specifies the number of Vec2f in the array.
/// \returns Vector that is the avarage of the points in the array
Vec2f& average( const Vec2f* points, std::size_t num );
/// \}
//---------------------
/// \name Limit
/// \{
/// \brief Returns a normalized copy of this vector.
///
/// *Normalization* means to scale the vector so that its length
/// (magnitude) is exactly 1, at which stage all that is left is the
/// direction. A normalized vector is usually called a *unit vector*, and
/// can be used to represent a pure direction (heading).
///
/// ~~~~{.cpp}
/// Vec2f v1(5, 0);
/// Vec2f v1Normalized = v1.getNormalized(); // (1, 0)
/// Vec2f v2(5, 5);
/// Vec2f v2Normalized = v2.getNormalized(); // (√2, √2)
/// ~~~~
Vec2f getNormalized() const;
/// \brief Normalize the vector.
///
/// *Normalizing* means to scale the vector so that its length (magnitude) is
/// exactly 1, at which stage all that is left is the direction. A normalized
/// vector is usually called a *unit vector*, and can be used to represent a pure
/// direction (heading).
///
/// ~~~~{.cpp}
/// Vec2f v1(5, 0);
/// v1.normalize(); // v2 is now (1, 0)
/// Vec2f v2(5, 5);
/// v2.normalize(); // v2 is now (√2, √2)
/// ~~~~
/// \sa getNormalized()
Vec2f& normalize();
/// \brief Get vector limited by length
///
/// ~~~~{.cpp}
/// Vec2f v1(5, 1); // length is about 5.1
/// Vec2f v2(2, 1); // length is about 2.2
/// Vec2f v1Limited = v1.getLimited(3);
/// // v1Limited is (2.9417, 0.58835) which has length of 3 in the same direction as v1
/// Vec2f v2Limited = v2.getLimited(3);
/// // v2Limited is (2, 1) (same as v2)
/// ~~~~
///
/// \sa limit()
/// \param max The maximum length of the vector to return
/// \returns A copy of this vector with its length (magnitude) restricted to a
/// maximum of max units by scaling down if necessary.
Vec2f getLimited(float max) const;
/// \brief Restrict the length (magnitude) of this vector to a maximum of max units by scaling down if necessary.
///
/// ~~~~{.cpp}
/// Vec2f v1(5, 1); // length is about 5.1
/// Vec2f v2(2, 1); // length is about 2.2
/// v1.limit(3);
/// // v1 is now (2.9417, 0.58835) which has length of 3 in the same direction as at initialization
/// v2.limit(3);
/// // v2 is unchanged
/// ~~~~
///
/// \sa limit()
Vec2f& limit(float max);
/// \}
//---------------------
/// \name Measurement
/// \{
/// \brief Return the length (magnitude) of this vector.
///
/// ~~~~{.cpp}
/// Vec2f v(3, 4);
/// float len = v.length(); // len is 5 (3,4,5 triangle)
/// ~~~~
///
/// length() involves a square root calculation, which is one of the slowest things
/// you can do in programming. If you don't need an exact number but rather just a
/// rough idea of a length (for example when finding the shortest distance of a
/// bunch of points to a reference point, where it doesn't matter exactly what the
/// lengths are, you just want the shortest), you can use
/// lengthSquared() instead.
///
/// \sa lengthSquared()
float length() const;
/// \brief Return the squared length (squared magnitude) of this vector.
///
/// ~~~~{.cpp}
/// Vec2f v(3, 4);
/// float len = v.length(); // len is 5 (3,4,5 triangle)
/// ~~~~
///
/// Use as a much faster alternative to length() if you don't
/// need to know an accurate length but rather just a rough idea of a
/// length (for example when finding the shortest distance of a bunch of
/// points to a reference point, where it doesn't matter exactly what the
/// lengths are, you just want the shortest). It avoids the square root
/// calculation that is ordinarily required to calculate a length.
///
/// \sa length()
float lengthSquared() const;
/// \brief Calculate the angle to another vector in degrees
///
/// ~~~~{.cpp}
/// Vec2f v1(1,0);
/// Vec2f v2(0,1);
/// float angle = v1.angle(v2); // angle is 90
/// ~~~~
/// \param vec The vector to calculate the angle to
/// \returns The angle in degrees (-180...180)
float angle( const Vec2f& vec ) const;
/// \brief Calculate the angle to another vector in radians
///
/// ~~~~{.cpp}
/// Vec2f v1(1,0);
/// Vec2f v2(0,1);
/// float angle = v1.angleRad(v2); // angle is HALF_PI
/// ~~~~
/// \param vec The vector to calculate the angle to
/// \returns The angle in radians (-PI...PI)
float angleRad( const Vec2f& vec ) const;
/// \}
//---------------------
/// \name Perpendicular
/// \{
/// \brief Return the *normalized* Vec2f that is perpendicular to this vector
/// (ie rotated 90 degrees and normalized).
///
/// ![PERPENDICULAR](math/perpendicular.png)
/// Image courtesy of Wikipedia
///
/// ~~~~{.cpp}
/// Vec2f v(2, 5);
/// Vec2f u = v.getPerpendicular(); // u is (0.928, -0.371)
/// ~~~~
///
/// \sa perpendicular()
Vec2f getPerpendicular() const;
/// \brief Set this vector to its own **normalized** perpendicular (by
/// rotating 90 degrees and normalizing).
///
/// ![PERPENDICULAR](math/perpendicular.png)
/// Image courtesy of Wikipedia
///
/// ~~~~{.cpp}
/// Vec2f v(2, 5);
/// v.perpendicular(); // v is (0.928, -0.371)
/// ~~~~
/// \sa getPerpendicular()
Vec2f& perpendicular();
/// \brief Calculate and return the dot product of this vector with vec.
///
/// *Dot product* (less commonly known as *Euclidean inner product*) expresses
/// the angular relationship between two vectors. In other words it is a measure
/// of how *parallel* two vectors are. If they are completely perpendicular the dot
/// product is 0; if they are completely parallel their dot product is either 1 if
/// they are pointing in the same direction, or -1 if they are pointing in
/// opposite directions.
///
/// ![DOT](math/dotproduct.png)
/// Image courtesy of Wikipedia
///
/// ~~~~{.cpp}
/// Vec2f a1(1, 0);
/// Vec2f b1(0, 1); // 90 degree angle to a1
/// dot = a1.dot(b1); // dot is 0, ie cos(90)
///
/// Vec2f a2(1, 0);
/// Vec2f b2(1, 1); // 45 degree angle to a2
/// b2.normalize(); // vectors should to be unit vectors (normalized)
/// float dot = a2.dot(b2); // dot is 0.707, ie cos(45)
///
/// Vec2f a3(1, 0);
/// Vec2f b3(-1, 0); // 180 degree angle to a3
/// dot = a3.dot(b3); // dot is -1, ie cos(180)
/// ~~~~
///
/// \param vec The vector to dotproduct
float dot( const Vec2f& vec ) const;
/// \}
//---------------------------------------------------
// this methods are deprecated in 006 please dont use:
/// \cond INTERNAL
// getScaled
// OF_DEPRECATED_MSG("Use member method getScaled() instead.", Vec2f rescaled( const float length ) const);
//
// // scale
// OF_DEPRECATED_MSG("Use member method scale() instead.", Vec2f& rescale( const float length ));
//
// // getRotated
// OF_DEPRECATED_MSG("Use member method getRotated() instead.", Vec2f rotated( float angle ) const);
//
// // getNormalized
// OF_DEPRECATED_MSG("Use member method getNormalized() instead.", Vec2f normalized() const);
//
// // getLimited
// OF_DEPRECATED_MSG("Use member method getLimited() instead.", Vec2f limited(float max) const);
//
// // getPerpendicular
// OF_DEPRECATED_MSG("Use member method getPerpendicular() instead.", Vec2f perpendiculared() const);
//
// // getInterpolated
// OF_DEPRECATED_MSG("Use member method getInterpolated() instead.", Vec2f interpolated( const Vec2f& pnt, float p ) const);
//
// // getMiddled
// OF_DEPRECATED_MSG("Use member method getMiddled() instead.", Vec2f middled( const Vec2f& pnt ) const);
//
// // getMapped
// OF_DEPRECATED_MSG("Use member method getMapped() instead.", Vec2f mapped( const Vec2f& origin, const Vec2f& vx, const Vec2f& vy ) const);
//
// // squareDistance
// OF_DEPRECATED_MSG("Use member method squareDistance() instead.", float distanceSquared( const Vec2f& pnt ) const);
//
// // use getRotated
// OF_DEPRECATED_MSG("Use member method getRotated() instead.", Vec2f rotated( float angle, const Vec2f& pivot ) const);
// return all zero vector
static Vec2f zero() { return Vec2f(0, 0); }
// return all one vector
static Vec2f one() { return Vec2f(1, 1); }
/// \endcond
};
/// \cond INTERNAL
// Non-Member operators
//
Vec2f operator+( float f, const Vec2f& vec );
Vec2f operator-( float f, const Vec2f& vec );
Vec2f operator*( float f, const Vec2f& vec );
Vec2f operator/( float f, const Vec2f& vec );
/// \endcond
/////////////////
// Implementation
/////////////////
/// \cond INTERNAL
inline Vec2f::Vec2f(): x(0), y(0) {}
inline Vec2f::Vec2f( float _scalar ): x(_scalar), y(_scalar) {}
inline Vec2f::Vec2f( float _x, float _y ):x(_x), y(_y) {}
// Getters and Setters.
//
//
inline void Vec2f::set( float _scalar ) {
x = _scalar;
y = _scalar;
}
inline void Vec2f::set( float _x, float _y ) {
x = _x;
y = _y;
}
inline void Vec2f::set( const Vec2f& vec ) {
x = vec.x;
y = vec.y;
}
// Check similarity/equality.
//
//
inline bool Vec2f::operator==( const Vec2f& vec ) const {
return (x == vec.x) && (y == vec.y);
}
inline bool Vec2f::operator!=( const Vec2f& vec ) const {
return (x != vec.x) || (y != vec.y);
}
inline bool Vec2f::match( const Vec2f& vec, float tolerance ) const {
return (fabs(x - vec.x) < tolerance)
&& (fabs(y - vec.y) < tolerance);
}
//
// Checks if vectors look in the same direction.
// Tolerance is specified in degree.
inline bool Vec2f::isAligned( const Vec2f& vec, float tolerance ) const {
return fabs( this->angle( vec ) ) < tolerance;
}
inline bool Vec2f::align( const Vec2f& vec, float tolerance ) const {
return isAligned( vec, tolerance );
}
inline bool Vec2f::isAlignedRad( const Vec2f& vec, float tolerance ) const {
return fabs( this->angleRad( vec ) ) < tolerance;
}
inline bool Vec2f::alignRad( const Vec2f& vec, float tolerance ) const {
return isAlignedRad( vec, tolerance );
}
// Overloading for any type to any type
//
//
inline Vec2f Vec2f::operator+( const Vec2f& vec ) const {
return Vec2f( x+vec.x, y+vec.y);
}
inline Vec2f& Vec2f::operator+=( const Vec2f& vec ) {
x += vec.x;
y += vec.y;
return *this;
}
inline Vec2f Vec2f::operator-( const Vec2f& vec ) const {
return Vec2f(x-vec.x, y-vec.y);
}
inline Vec2f& Vec2f::operator-=( const Vec2f& vec ) {
x -= vec.x;
y -= vec.y;
return *this;
}
inline Vec2f Vec2f::operator*( const Vec2f& vec ) const {
return Vec2f(x*vec.x, y*vec.y);
}
inline Vec2f& Vec2f::operator*=( const Vec2f& vec ) {
x*=vec.x;
y*=vec.y;
return *this;
}
inline Vec2f Vec2f::operator/( const Vec2f& vec ) const {
return Vec2f( vec.x!=0 ? x/vec.x : x , vec.y!=0 ? y/vec.y : y);
}
inline Vec2f& Vec2f::operator/=( const Vec2f& vec ) {
vec.x!=0 ? x/=vec.x : x;
vec.y!=0 ? y/=vec.y : y;
return *this;
}
// inline ostream& operator<<(ostream& os, const Vec2f& vec) {
// os << vec.x << ", " << vec.y;
// return os;
// }
//
// inline istream& operator>>(istream& is, Vec2f& vec) {
// is >> vec.x;
// is.ignore(2);
// is >> vec.y;
// return is;
// }
//operator overloading for float
//
//
//inline void Vec2f::operator=( const float f){
// x = f;
// y = f;
//}
inline Vec2f Vec2f::operator+( const float f ) const {
return Vec2f( x+f, y+f);
}
inline Vec2f& Vec2f::operator+=( const float f ) {
x += f;
y += f;
return *this;
}
inline Vec2f Vec2f::operator-( const float f ) const {
return Vec2f( x-f, y-f);
}
inline Vec2f& Vec2f::operator-=( const float f ) {
x -= f;
y -= f;
return *this;
}
inline Vec2f Vec2f::operator-() const {
return Vec2f(-x, -y);
}
inline Vec2f Vec2f::operator*( const float f ) const {
return Vec2f(x*f, y*f);
}
inline Vec2f& Vec2f::operator*=( const float f ) {
x*=f;
y*=f;
return *this;
}
inline Vec2f Vec2f::operator/( const float f ) const {
if(f == 0) return Vec2f(x, y);
return Vec2f(x/f, y/f);
}
inline Vec2f& Vec2f::operator/=( const float f ) {
if(f == 0) return *this;
x/=f;
y/=f;
return *this;
}
// inline Vec2f Vec2f::rescaled( const float length ) const {
// return getScaled(length);
// }
inline Vec2f Vec2f::getScaled( const float length ) const {
float l = (float)sqrt(x*x + y*y);
if( l > 0 )
return Vec2f( (x/l)*length, (y/l)*length );
else
return Vec2f();
}
// inline Vec2f& Vec2f::rescale( const float length ){
// return scale(length);
// }
inline Vec2f& Vec2f::scale( const float length ) {
float l = (float)sqrt(x*x + y*y);
if (l > 0) {
x = (x/l)*length;
y = (y/l)*length;
}
return *this;
}
// Rotation
//
//
// inline Vec2f Vec2f::rotated( float angle ) const {
// return getRotated(angle);
// }
inline Vec2f Vec2f::getRotated( float angle ) const {
float a = (float)(angle*DEG_TO_RAD);
return Vec2f( x*cos(a) - y*sin(a),
x*sin(a) + y*cos(a) );
}
inline Vec2f Vec2f::getRotatedRad( float angle ) const {
float a = angle;
return Vec2f( x*cos(a) - y*sin(a),
x*sin(a) + y*cos(a) );
}
inline Vec2f& Vec2f::rotate( float angle ) {
float a = (float)(angle * DEG_TO_RAD);
float xrot = x*cos(a) - y*sin(a);
y = x*sin(a) + y*cos(a);
x = xrot;
return *this;
}
inline Vec2f& Vec2f::rotateRad( float angle ) {
float a = angle;
float xrot = x*cos(a) - y*sin(a);
y = x*sin(a) + y*cos(a);
x = xrot;
return *this;
}
// Rotate point by angle (deg) around pivot point.
//
//
// This method is deprecated in 006 please use getRotated instead
// inline Vec2f Vec2f::rotated( float angle, const Vec2f& pivot ) const {
// return getRotated(angle, pivot);
// }
inline Vec2f Vec2f::getRotated( float angle, const Vec2f& pivot ) const {
float a = (float)(angle * DEG_TO_RAD);
return Vec2f( ((x-pivot.x)*cos(a) - (y-pivot.y)*sin(a)) + pivot.x,
((x-pivot.x)*sin(a) + (y-pivot.y)*cos(a)) + pivot.y );
}
inline Vec2f& Vec2f::rotate( float angle, const Vec2f& pivot ) {
float a = (float)(angle * DEG_TO_RAD);
float xrot = ((x-pivot.x)*cos(a) - (y-pivot.y)*sin(a)) + pivot.x;
y = ((x-pivot.x)*sin(a) + (y-pivot.y)*cos(a)) + pivot.y;
x = xrot;
return *this;
}
inline Vec2f Vec2f::getRotatedRad( float angle, const Vec2f& pivot ) const {
float a = angle;
return Vec2f( ((x-pivot.x)*cos(a) - (y-pivot.y)*sin(a)) + pivot.x,
((x-pivot.x)*sin(a) + (y-pivot.y)*cos(a)) + pivot.y );
}
inline Vec2f& Vec2f::rotateRad( float angle, const Vec2f& pivot ) {
float a = angle;
float xrot = ((x-pivot.x)*cos(a) - (y-pivot.y)*sin(a)) + pivot.x;
y = ((x-pivot.x)*sin(a) + (y-pivot.y)*cos(a)) + pivot.y;
x = xrot;
return *this;
}
// Map point to coordinate system defined by origin, vx, and vy.
//
//
// This method is deprecated in 006 please use getMapped instead
// inline Vec2f Vec2f::mapped( const Vec2f& origin,
// const Vec2f& vx,
// const Vec2f& vy ) const{
// return getMapped(origin, vx, vy);
// }
inline Vec2f Vec2f::getMapped( const Vec2f& origin,
const Vec2f& vx,
const Vec2f& vy ) const
{
return Vec2f( origin.x + x*vx.x + y*vy.x,
origin.y + x*vx.y + y*vy.y );
}
inline Vec2f& Vec2f::map( const Vec2f& origin,
const Vec2f& vx, const Vec2f& vy )
{
float xmap = origin.x + x*vx.x + y*vy.x;
y = origin.y + x*vx.y + y*vy.y;
x = xmap;
return *this;
}
// Distance between two points.
//
//
inline float Vec2f::distance( const Vec2f& pnt) const {
float vx = x-pnt.x;
float vy = y-pnt.y;
return (float)sqrt(vx*vx + vy*vy);
}
//this method is deprecated in 006 please use squareDistance
// inline float Vec2f::distanceSquared( const Vec2f& pnt ) const {
// return squareDistance(pnt);
// }
inline float Vec2f::squareDistance( const Vec2f& pnt ) const {
float vx = x-pnt.x;
float vy = y-pnt.y;
return vx*vx + vy*vy;
}
// Linear interpolation.
//
//
//
// p==0.0 results in this point, p==0.5 results in the
// midpoint, and p==1.0 results in pnt being returned.
//
// this method is deprecated in 006 please use getInterpolated
// inline Vec2f Vec2f::interpolated( const Vec2f& pnt, float p ) const{
// return getInterpolated(pnt, p);
// }
inline Vec2f Vec2f::getInterpolated( const Vec2f& pnt, float p ) const {
return Vec2f( x*(1-p) + pnt.x*p, y*(1-p) + pnt.y*p );
}
inline Vec2f& Vec2f::interpolate( const Vec2f& pnt, float p ) {
x = x*(1-p) + pnt.x*p;
y = y*(1-p) + pnt.y*p;
return *this;
}
// this method is deprecated in 006 please use getMiddle
// inline Vec2f Vec2f::middled( const Vec2f& pnt ) const{
// return getMiddle(pnt);
// }
inline Vec2f Vec2f::getMiddle( const Vec2f& pnt ) const {
return Vec2f( (x+pnt.x)/2.0f, (y+pnt.y)/2.0f );
}
inline Vec2f& Vec2f::middle( const Vec2f& pnt ) {
x = (x+pnt.x)/2.0f;
y = (y+pnt.y)/2.0f;
return *this;
}
inline Vec2f& Vec2f::average( const Vec2f* points, std::size_t num ) {
if (0 == num) {
return *this;
}
x = 0.f;
y = 0.f;
for( size_t i=0; i<num; i++) {
x += points[i].x;
y += points[i].y;
}
x /= num;
y /= num;
return *this;
}
// Normalization
//
//
// inline Vec2f Vec2f::normalized() const {
// return getNormalized();
// }
inline Vec2f Vec2f::getNormalized() const {
float length = (float)sqrt(x*x + y*y);
if( length > 0 ) {
return Vec2f( x/length, y/length );
} else {
return Vec2f();
}
}
inline Vec2f& Vec2f::normalize() {
float length = (float)sqrt(x*x + y*y);
if( length > 0 ) {
x /= length;
y /= length;
}
return *this;
}
// Limit length.
//
//
// inline Vec2f Vec2f::limited(float max) const{
// return getLimited(max);
// }
inline Vec2f Vec2f::getLimited(float max) const {
Vec2f limited;
float lengthSquared = (x*x + y*y);
if( lengthSquared > max*max && lengthSquared > 0 ) {
float ratio = max/(float)sqrt(lengthSquared);
limited.set( x*ratio, y*ratio);
} else {
limited.set(x,y);
}
return limited;
}
inline Vec2f& Vec2f::limit(float max) {
float lengthSquared = (x*x + y*y);
if( lengthSquared > max*max && lengthSquared > 0 ) {
float ratio = max/(float)sqrt(lengthSquared);
x *= ratio;
y *= ratio;
}
return *this;
}
// Perpendicular normalized vector.
//
//
// inline Vec2f Vec2f::perpendiculared() const {
// return getPerpendicular();
// }
inline Vec2f Vec2f::getPerpendicular() const {
float length = (float)sqrt( x*x + y*y );
if( length > 0 )
return Vec2f( -(y/length), x/length );
else
return Vec2f();
}
inline Vec2f& Vec2f::perpendicular() {
float length = (float)sqrt( x*x + y*y );
if( length > 0 ) {
float _x = x;
x = -(y/length);
y = _x/length;
}
return *this;
}
// Length
//
//
inline float Vec2f::length() const {
return (float)sqrt( x*x + y*y );
}
inline float Vec2f::lengthSquared() const {
return (float)(x*x + y*y);
}
inline float Vec2f::angle( const Vec2f& vec ) const {
return (float)(atan2( x*vec.y-y*vec.x, x*vec.x + y*vec.y )*RAD_TO_DEG);
}
inline float Vec2f::angleRad( const Vec2f& vec ) const {
return atan2( x*vec.y-y*vec.x, x*vec.x + y*vec.y );
}
inline float Vec2f::dot( const Vec2f& vec ) const {
return x*vec.x + y*vec.y;
}
// Non-Member operators
//
//
inline Vec2f operator+( float f, const Vec2f& vec ) {
return Vec2f( f+vec.x, f+vec.y);
}
inline Vec2f operator-( float f, const Vec2f& vec ) {
return Vec2f( f-vec.x, f-vec.y);
}
inline Vec2f operator*( float f, const Vec2f& vec ) {
return Vec2f( f*vec.x, f*vec.y);
}
inline Vec2f operator/( float f, const Vec2f& vec ) {
return Vec2f( f/vec.x, f/vec.y);
}
/// \endcond
#include "Vec2f.h"
#include "Vec3f.h"
#include "Vec4f.h"
Vec2f::Vec2f( const Vec3f& vec ) {
x = vec.x;
y = vec.y;
}
Vec2f::Vec2f( const Vec4f& vec ) {
x = vec.x;
y = vec.y;
}
#pragma once
#include "Vec2f.h"
#include "Vec3f.h"
#include "Vec4f.h"
以上是关于c_cpp 矢量函数(openFrameworks的Vec2f / 3f / 4f端口)的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp openFrameworks ofxPBR ofApp文件
c_cpp openFrameworks - 使用ofFmodSoundPlayer从audioPlayer获取原始音频帧
c_cpp openFrameworks内联着色器模板(仅限vert和frag)