Ich habe ein paar Klassen von einer älteren Version eines meiner Math Libraries. Ich benutze sie nicht mehr besonders, seit ich die GLM-Mathematikbibliothek benutzt habe, aber für den Zweck dieser Antwort werden sie zeigen, was benötigt wird.
GeneralMath.h - Diese allgemeine mathematische Klasse wird für grundlegende mathematische Operationen benötigt.
#ifndef GENERALMATH_H
#define GENERALMATH_H
#include "stdafx.h"
class Math {
public:
static const float PI;
static const float PI_HALVES;
static const float PI_THIRDS;
static const float PI_FOURTHS;
static const float PI_SIXTHS;
static const float PI_2;
static const float PI_INVx180;
static const float PI_DIV180;
static const float PI_INV;
static const float ZERO;
Math();
inline static bool isZero(float fValue);
inline static float sign(float fValue);
inline static int randomRange(int iMin, int iMax);
inline static float randomRange(float fMin, float fMax);
inline static float degree2Radian(float fDegrees);
inline static float radian2Degree(float fRadians);
inline static float correctAngle(float fAngle, bool bDegrees, float fAngleStart = 0.0f);
inline static float mapValue(float fMinY, float fMaxY, float fMinX, float fMaxX, float fValueX);
template<class T>
inline static void constrain(T min, T max, T &value);
template<class T>
inline static void swap(T &value1, T &value2);
}; // Math
// -----------------------------------------------------------------------
// degree2Radian()
// Convert Angle In Degrees To Radians
inline float Math::degree2Radian(float fDegrees) {
return fDegrees * PI_DIV180;
} // degree2Radian
// -----------------------------------------------------------------------
// radian2Degree()
// Convert Angle In Radians To Degrees
inline float Math::radian2Degree(float fRadians) {
return fRadians * PI_INVx180;
} // radian2Degree
// -----------------------------------------------------------------------
// correctAngle()
// Returns An Angle Value That Is Alway Between fAngleStart And fAngleStart + 360
// If Radians Are Used, Then Range Is fAngleStart To fAngleStart + 2PI
inline float Math::correctAngle(float fAngle, bool bDegrees, float fAngleStart) {
if (bDegrees) {
// Using Degrees
if (fAngle < fAngleStart) {
while (fAngle < fAngleStart) {
fAngle += 360.0f;
}
}
else if (fAngle >= (fAngleStart + 360.0f)) {
while (fAngle >= (fAngleStart + 360.0f)) {
fAngle -= 360.0f;
}
}
return fAngle;
}
else {
// Using Radians
if (fAngle < fAngleStart) {
while (fAngle < fAngleStart) {
fAngle += Math::PI_2;
}
}
else if (fAngle >= (fAngleStart + Math::PI_2)) {
while (fAngle >= (fAngleStart + Math::PI_2)) {
fAngle -= Math::PI_2;
}
}
return fAngle;
}
} // correctAngle
// -----------------------------------------------------------------------
// isZero()
// Tests If Input Value Is Close To Zero
inline bool Math::isZero(float fValue) {
if ((fValue > -ZERO) && (fValue < ZERO)) {
return true;
}
return false;
} // isZero
// -----------------------------------------------------------------------
// sign()
// Returns 1 If Value Is Positive, -1 If Value Is Negative Or 0 Otherwise
inline float Math::sign(float fValue) {
if (fValue > 0) {
return 1.0f;
}
else if (fValue < 0) {
return -1.0f;
}
return 0;
} // sign
// -----------------------------------------------------------------------
// randomRange()
// Return A Random Number Between iMin And iMax Where iMin < iMax
// NOTE: This function is quite old; haven't had time to update the random number generator system
inline int Math::randomRange(int iMin, int iMax) {
if (iMax < iMin) {
swap(iMax, iMin);
}
return (iMin + ((iMax - iMin +1) * rand())/(RAND_MAX+1));
} // randomRange
// -----------------------------------------------------------------------
// randomRange()
// Return A Random Number Between fMin And fMax Where fMin < fMax
// NOTE: This function is quite old; haven't had time to update the random number generator system
inline float Math::randomRange(float fMin, float fMax) {
if (fMax < fMin) {
swap(fMax, fMin);
}
return (fMin + (rand()/(float)RAND_MAX)*(fMax-fMin));
} // randomRange
// -----------------------------------------------------------------------
// mapValue()
// Returns The fValueY That Corresponds To A Point On The Line Going From Min To Max
inline float Math::mapValue(float fMinY, float fMaxY, float fMinX, float fMaxX, float fValueX) {
if (fValueX >= fMaxX) {
return fMaxY;
}
else if (fValueX <= fMinX) {
return fMinY;
}
else {
float fM = (fMaxY - fMinY)/(fMaxX - fMinX);
float fB = fMaxY - fM * fMaxX;
return (fM*fValueX + fB);
}
} // mapValue
// -----------------------------------------------------------------------
// constrain()
// Prevent Value From Going Outside The Min, Max Range.
template<class T>
inline void Math::constrain(T min, T max, T &value) {
if (value < min) {
value = min;
return;
}
if (value > max) {
value = max;
}
} // constrain
// -----------------------------------------------------------------------
// swap()
template<class T>
inline void Math::swap(T &value1, T &value2) {
T temp;
temp = value1;
value1 = value2;
value2 = temp;
} // swap
#endif // GENERALMATH_H
GeneralMath.cpp
#include "stdafx.h"
#include "GeneralMath.h"
const float Math::PI = 4.0f * atan(1.0f); // tan(pi/4) = 1
const float Math::PI_HALVES = 0.50f * Math::PI;
const float Math::PI_THIRDS = Math::PI * 0.3333333333333f;
const float Math::PI_FOURTHS = 0.25f * Math::PI;
const float Math::PI_SIXTHS = Math::PI * 0.6666666666667f;
const float Math::PI_2 = 2.00f * Math::PI;
const float Math::PI_DIV180 = Math::PI/180.0f;
const float Math::PI_INVx180 = 180.0f/Math::PI;
const float Math::PI_INV = 1.0f/Math::PI;
const float Math::ZERO = (float)1e-7;
// -----------------------------------------------------------------------
// Math()
// Default Constructor
Math::Math() {
} // Math
Vector3.h
#ifndef VECTOR3_H
#define VECTOR3_H
#include "stdafx.h"
#include "GeneralMath.h"
class Vector3 {
public:
union {
float m_f3[3];
struct {
float m_fx;
float m_fy;
float m_fz;
};
};
inline Vector3();
inline Vector3(float x, float y, float z);
inline Vector3(float *pfv);
~Vector3();
// Operators
inline Vector3 operator+(const Vector3 &v3) const;
inline Vector3 operator+() const;
inline Vector3& operator+=(const Vector3 &v3);
inline Vector3 operator-(const Vector3 &v3) const;
inline Vector3 operator-() const;
inline Vector3& operator-=(const Vector3 &v3);
inline Vector3 operator*(const float &fValue) const;
inline Vector3& operator*=(const float &fValue);
inline Vector3 operator/(const float &fValue) const;
inline Vector3& operator/=(const float &fValue);
// -------------------------------------------------------------------
// operator*()
// Pre Multiple Vector By A Scalar
inline friend Vector3 Vector3::operator*(const float &fValue, const Vector3 v3) {
return Vector3(fValue*v3.m_fx, fValue*v3.m_fy, fValue*v3.m_fz);
} // operator*
// -------------------------------------------------------------------
// operator/()
// Pre Divide Vector By A Scalar Value
inline friend Vector3 Vector3::operator/(const float &fValue, const Vector3 v3) {
Vector3 vec3;
if (Math::isZero(v3.m_fx)) {
vec3.m_fx = 0.0f;
} else {
vec3.m_fx = fValue/v3.m_fx;
}
if (Math::isZero(v3.m_fy)) {
vec3.m_fy = 0.0f;
} else {
vec3.m_fy = fValue/v3.m_fy;
}
if (Math::isZero(v3.m_fz)) {
vec3.m_fz = 0.0f;
} else {
vec3.m_fz = fValue/v3.m_fz;
}
return vec3;
} // operator/
// -----------------------------------------------------------------
// operator/()
// Divide Vector by Vector component wise returns scalar value.
inline friend float Vector3::operator/(const Vector3& v1, const Vector3& v2) {
if (Math::isZero(v2.m_fx) ||
Math::isZero(v2.m_fy) ||
Math::izZero(v2.m_fz)) {
throw (std::string("Divide by Zero"));
}
float val = v1.m_fx/v2.m_fx;
if ((val == (v1.m_fy/v2.m_fy)) &&
(val == (v1.m_fz/v2.m_fz))) {
return val;
}
} // operator/
// Functions
inline float divideByVector(const Vector3& v);
inline Vector3 rotateX(float fRadians);
inline Vector3 rotateY(float fRadians);
inline Vector3 rotateZ(float fRadians);
inline void setPerpendicularXZ(Vector3 v3);
inline void setPerpendicularXY(Vector3 v3);
inline void setPerpendicularYZ(Vector3 v3);
inline Vector3 cross(const Vector3 v3) const;
inline float dot(const Vector3 v3) const;
inline float getAngle(const Vector3 &v3, const bool bNormalized = false, bool bRadians = true);
inline float getCosAngle(const Vector3 &v3, const bool bNormalized = false);
inline float length() const;
inline float length2() const;
inline void normalize();
inline void zero();
inline bool isZero() const;
}; // Vector3
// -----------------------------------------------------------------------
// Vector3()
// Constructor
inline Vector3::Vector3() :
m_fx(0.0f),
m_fy(0.0f),
m_fz(0.0f) {
} // Vector3
// -----------------------------------------------------------------------
// Vector3()
// Constructor
inline Vector3::Vector3(float x, float y, float z) :
m_fx(x),
m_fy(y),
m_fz(z) {
} // Vector3
// -----------------------------------------------------------------------
// Vector3()
// Constructor
inline Vector3::Vector3(float *pfv) {
m_fx = pfv[0];
m_fy = pfv[1];
m_fz = pfv[2];
} // Vector3
// -----------------------------------------------------------------------
// operator+()
// Unary - Operator:
inline Vector3 Vector3::operator+() const {
return *this;
} // operator+
// -----------------------------------------------------------------------
// operator+()
// Binary - Add Two Vectors Together
inline Vector3 Vector3::operator+(const Vector3 &v3) const {
return Vector3(m_fx + v3.m_fx,
m_fy + v3.m_fy,
m_fz + v3.m_fz);
} // operator+
// -----------------------------------------------------------------------
// operator+=()
// Add Two Vectors Together
inline Vector3 &Vector3::operator+=(const Vector3 &v3) {
m_fx += v3.m_fx;
m_fy += v3.m_fy;
m_fz += v3.m_fz;
return *this;
} // operator+=
// -----------------------------------------------------------------------
// operator-()
// Unary - Operator: Negate Each Value
inline Vector3 Vector3::operator-() const {
return Vector3(-m_fx, -m_fy, -m_fz);
} // operator-
// -----------------------------------------------------------------------
// operator-()
// Binary - Take This Vector And Subtract Another Vector From It
inline Vector3 Vector3::operator-(const Vector3 &v3) const {
return Vector3(m_fx - v3.m_fx,
m_fy - v3.m_fy,
m_fz - v3.m_fz);
} // operator-
// -----------------------------------------------------------------------
// operator-=()
// Subtract Two Vectors From Each Other
inline Vector3 &Vector3::operator-=(const Vector3 &v3) {
m_fx -= v3.m_fx;
m_fy -= v3.m_fy;
m_fz -= v3.m_fz;
return *this;
} // operator-=
// -----------------------------------------------------------------------
// operator*()
// Post Multiple Vector By A Scalar
inline Vector3 Vector3::operator*(const float &fValue) const {
return Vector3(m_fx*fValue, m_fy*fValue, m_fz*fValue);
} // operator*
// -----------------------------------------------------------------------
// operator*=()
// Multiply This Vector By A Scalar
inline Vector3& Vector3::operator*=(const float &fValue) {
m_fx *= fValue;
m_fy *= fValue;
m_fz *= fValue;
return *this;
} // operator*=
// -----------------------------------------------------------------------
// operator/()
// Post Divide Vector By A Scalar
inline Vector3 Vector3::operator/(const float &fValue) const {
Vector3 v3;
if (Math::isZero(fValue)) {
v3.m_fx = 0.0f;
v3.m_fy = 0.0f;
v3.m_fz = 0.0f;
} else {
float fValue_Inv = 1/fValue;
v3.m_fx = v3.m_fx * fValue_Inv;
v3.m_fy = v3.m_fy * fValue_Inv;
v3.m_fz = v3.m_fz * fValue_Inv;
}
return v3;
} // operator/
// -----------------------------------------------------------------------
// operator/=()
// Divide This Vector By A Scalar
inline Vector3& Vector3::operator/=(const float &fValue) {
if (Math::isZero(fValue)) {
m_fx = 0.0f;
m_fy = 0.0f;
m_fz = 0.0f;
} else {
float fValue_Inv = 1/fValue;
m_fx *= fValue_Inv;
m_fy *= fValue_Inv;
m_fy *= fValue_Inv;
}
return *this;
} // operator/=
// -----------------------------------------------------------------------
// divideByVector()
// Division Is Performed By A Vector Component Basis And Returns A Scalar
// With (x*V1) = V2 since (x*V1) = (x*V1i, x*V1j, x*V1k) = V2(i,j,k)
// Then As long as the this vector does not have a 0 component
// We only need to perform the division on the first element of this vector
// where x = V2i/V1i. No need to perform division on j or k.
inline float Vector3::divideByVector(const Vector3& v) {
if (Math::isZero(v.m_fx) ||
Math::isZero(v.m_fy) ||
Math::izZero(v.m_fz)) {
throw( std::string("Divide By 0"));
}
float val = m_fx/v.m_fx;
if ((val == (m_fy/v.m_fy)) &&
(val == (m_fz/v.m_fz))) {
return val;
}
} // divideByVector
// -----------------------------------------------------------------------
// rotateX()
// Rotate This Vector About The X Axis
inline Vector3 Vector3::rotateX(float fRadians) {
Vector3 v3;
v3.m_fx = m_fx;
v3.m_fy = m_fy*cos(fRadians) - m_fz*sin(fRadians);
v3.m_fz = m_fy*sin(fRadians) + m_fz*cos(fRadians);
return v3;
} // rotateX
// -----------------------------------------------------------------------
// rotateY()
// Rotate This Vector About The Y Axis
inline Vector3 Vector3::rotateY(float fRadians) {
Vector3 v3;
v3.m_fx = m_fx*cos(fRadians) + m_fz*sin(fRadians);
v3.m_fy = m_fy;
v3.m_fz = -m_fx*sin(fRadians) + m_fz*cos(fRadians);
return v3;
} // rotateY
// -----------------------------------------------------------------------
// rotateZ()
// Rotate This Vector About The Z Axis
inline Vector3 Vector3::rotateZ(float fRadians) {
Vector3 v3;
v3.m_fx = m_fx*cos(fRadians) - m_fy*sin(fRadians);
v3.m_fy = m_fx*sin(fRadians) + m_fy*cos(fRadians);
v3.m_fz = m_fz;
return v3;
} // rotateZ
// -----------------------------------------------------------------------
// setPerpendicularXY()
// Make This Vector Perp To Vector3
inline void Vector3::setPerpendicularXY(Vector3 v3) {
m_fx = -v3.m_fy;
m_fy = v3.m_fx;
m_fz = v3.m_fz;
} // setPerpendicularXY
// -----------------------------------------------------------------------
// setPerpendicularXZ()
// Make This Vector Perp To Vector3
inline void Vector3::setPerpendicularXZ(Vector3 v3) {
m_fx = -v3.m_fz;
m_fy = v3.m_fy;
m_fz = v3.m_fx;
} // setPerpendicularXZ
// -----------------------------------------------------------------------
// setPerpendicularYX()
// Make This Vector Perp To Vector3
inline void Vector3::setPerpendicularYZ(Vector3 v3) {
m_fx = v3.m_fx;
m_fy = -v3.m_fz;
m_fz = v3.m_fy;
} // setPerpendicularYZ
// -----------------------------------------------------------------------
// cross()
// Get The Cross Product Of Two Vectors
inline Vector3 Vector3::cross(const Vector3 v3) const {
return Vector3(m_fy*v3.m_fz - m_fz*v3.m_fy,
v3.m_fx*m_fz - m_fx*v3.m_fz,
m_fx*v3.m_fy - m_fy*v3.m_fx);
} // cross
// -----------------------------------------------------------------------
// dot()
// Return The Dot Product Between This Vector And Another One
inline float Vector3::dot(const Vector3 v3) const {
return (m_fx * v3.m_fx +
m_fy * v3.m_fy +
m_fz * v3.m_fz);
} // dot
// -----------------------------------------------------------------------
// normalize()
// Make The Length Of This Vector Equal To One
inline void Vector3::normalize() {
float fMag;
fMag = sqrt(m_fx*m_fx + m_fy*m_fy + m_fz*m_fz);
if (fMag <= Math::ZERO) {
m_fx = 0.0f;
m_fy = 0.0f;
m_fz = 0.0f;
return;
}
fMag = 1/fMag;
m_fx *= fMag;
m_fy *= fMag;
m_fz *= fMag;
} // normalize
// -----------------------------------------------------------------------
// isZero()
// Return True if Vector Is (0,0,0)
inline bool Vector3::isZero() const {
if (Math::isZero(m_fx) && Math::isZero(m_fy) && Math::isZero(m_fz)) {
return true;
} else {
return false;
}
} // isZero
// -----------------------------------------------------------------------
// zero()
// Set The Value To (0,0,0)
inline void Vector3::zero() {
m_fx = 0.0f;
m_fy = 0.0f;
m_fz = 0.0f;
} // Zero
// -----------------------------------------------------------------------
// getCosAngle()
// Returns The cos(Angle) Value Between This Vector And Vector V. This
// Is Less Expensive Than Using GetAngle
inline float Vector3::getCosAngle(const Vector3 &v3, const bool bNormalized) {
// a . b = |a||b|cos(angle)
// -> cos-1((a.b)/(|a||b|))
// Make Sure We Do Not Divide By Zero
float fMagA = length();
if (fMagA <= Math::ZERO) {
// This (A) Is An Invalid Vector
return 0;
}
float fValue = 0;
if (bNormalized) {
// v3 Is Already Normalized
fValue = dot(v3)/fMagA;
}
else {
float fMagB = v3.length();
if (fMagB <= Math::ZERO) {
// B Is An Invalid Vector
return 0;
}
fValue = dot(v3)/(fMagA*fMagB);
}
// Correct Value Due To Rounding Problem
Math::constrain(-1.0f, 1.0f, fValue);
return fValue;
} // getCosAngle
// -----------------------------------------------------------------------
// getAngle()
// Returns The Angle Between This Vector And Vector V in Radians.
// This Is More Expensive Than Using GetCosAngle
inline float Vector3::getAngle(const Vector3 &v3, const bool bNormalized, bool bRadians) {
// a . b = |a||b|cos(angle)
// -> cos-1((a.b)/(|a||b|))
if (bRadians) {
return acos(this->getCosAngle(v3));
}
else {
// Convert To Degrees
return Math::radian2Degree(acos(getCosAngle(v3, bNormalized)));
}
} // GetAngle
// -----------------------------------------------------------------------
// length()
// Return The Length Of This Vector
inline float Vector3::length() const {
return sqrtf(m_fx * m_fx +
m_fy * m_fy +
m_fz * m_fz);
} // length
// -----------------------------------------------------------------------
// length2()
// Return The Length Of This Vector
inline float Vector3::length2() const {
return (m_fx * m_fx +
m_fy * m_fy +
m_fz * m_fz);
} // length2
#endif // VECTOR3_H
Vector3.cpp
#include "stdafx.h"
#include "Vector3.h"
// -----------------------------------------------------------------------
// ~Vector3()
// Destructor
Vector3::~Vector3() {
} // ~Vector3
Wenn Sie innerhalb meiner Vector3-Klasse feststellen, habe ich eine Reihe von Operatoren und allgemein definierten Funktionen, die auf Vektoren von 3 Komponenten angewendet werden können. Jetzt geben die Operatoren für Division einen Vektor3 zurück und teilen jede Komponente durch einen Skalar. Aus diesem Grund habe ich auch einen Freund Operator/und einen Funktionsaufruf divideByVector enthalten. Sie werden die gleiche Operation ausführen. Sie im Code zu verwenden ist so einfach wie.
#include "stdafx.h" // string isostream etc.
#include "Vector3.h"
int main() {
Vector3 v1 (4.0f, 4.0f, 4.0f);
Vector3 v2 (2.0f, 2.0f, 2.0f);
float value = v1.divideByVector(v2);
std::cout << value << std::endl;
value = v2.divideByVector(v1);
std::cout << value << std::endl;
std::cout << v1/v2 << std::endl;
std::cout << v2/v1 << std::endl;
v1.m_fx = 0;
v2.m_fx = 0;
std::cout << v1.divideByVector(v2) << std::endl;
std::cout << v2.divideByVector(v1) << std::endl;
std::cout << v1/v2 << std::endl;
std::cout << v2/v1 << std::endl;
std::cout << "\nPress any key to quit.\n" << std::endl;
_getch();
return 0;
} // main
Sie können auch Vektoren versuchen waren jede Komponente eines nicht ein Vielfaches der Komponenten eines anderen zum Beispiel: v1(15.0f, 25.0f, 30.0f) & v2(3.0f, 5.0f, 7.0f)
wo dies aufgrund v2's k component
jetzt fehlschlägt, wenn v2's k component was 6.0f
dann wieder der Ergebniswert 5
sein sollte, und wenn Wenn Sie die Division umkehren, sollte es 0.2
sein.Jetzt mit meinem Compiler (VS2015), wenn diese Werte nicht häufig ein Vielfaches der gedruckten Nachricht auf dem Bildschirm ist für mich:
-nan(ind)
Wenn Sie 0 als Wert übergeben und versuchen, es zu teilen, dann wird der Debugger werfen eine nicht behandelte Ausnahme. Normalerweise würde dies als eine Nachricht ausgelöst und in einem try { ... } catch(...) { }
Block gefangen werden. Allerdings habe ich weder meine Logger noch meine ExceptionHandler-Klasse für diese Demonstration verfügbar. Beachten Sie auch, dass einige meiner Funktionen in dieser älteren Bibliothek veraltete oder überarbeitete Funktionen sind, da ich rand
oder srand
nicht mehr verwende, da ich jetzt die Bibliothek <random>
verwende.
Nun, wenn x ein Skalar ist, dass alle überprüfen die Komponenten von V2 und V1 sind so, dass x = V2.x/V1.x = V2.y/V1.y = V2.z/V1.z, ansonsten existiert an x nicht, die diese Gleichung erfüllen. Wenn eine Komponente von V1 0 ist, muss das entsprechende Element von V2 ebenfalls 0 sein (überspringe das einfach). Wenn alle null sind ... x ist undefiniert. –
In Ihrer ursprünglichen Gleichung 'x * V1 = V2', ist es der Fall, wenn' x' mit 'V1' multipliziert wird, dass es eine komponentenweise Multiplikation durchführt? So dass (x * V1) = (x * V1i, x * V1j, x * V1k) = V2 (i, j, k,) '? –
Für diese Frage weiß ich bereits, dass es ein solches x gibt. Francis x ist in diesem Fall ein Skalar, also ist es elementweise multipliziert. – user3255596