以编程方式在向量中找到标量

时间:2016-04-19 18:01:50

标签: c++ vector-graphics

我有两个相等的向量V1和V2

x * V1 = V2

当我需要确定x时,V1和V2都是已知的。我也确切地知道有一个x可以解决这个问题。

我可以用手工建立一个方程组来获得x。事实上,我不需要进行任何高斯消除,因为它是如此简单的设置。这导致我尝试x = V2.x / V1.x.然而,这可能导致除以零。

我是用C ++写的,如果这很重要的话。

谢谢!

5 个答案:

答案 0 :(得分:1)

作为我自己问题的答案

x =(V2.x + V2.y + V2.z)/(V1.x + V1.y + V1.z)

如果V1全为零,那将无法工作,但在我的情况下不会发生这种情况。

答案 1 :(得分:1)

怎么样:

double getX(const std::vector<double>& V1, const std::vector<double>& V2) {
    if (V1.size() != V2.size()) return 0; 
    for( int i=0; i<V1.size(); i++ ){
       if(V1[i] != 0) {
            return v2[i] / v1[i];
       } 
    }
    return 0;
}

答案 2 :(得分:1)

提问者自己的解决方案存在缺陷,因为如果(V1.x + V1.y + V1.z)加起来它会失败:

x =(V2.x + V2.y + V2.z)/(V1.x + V1.y + V1.z)

以下是此问题的正确解决方案:

path.data: /data1/es1,/data2/es1,/data3/es1

答案 3 :(得分:0)

只需循环通过V1的坐标,找到第一个非零,然后除。

答案 4 :(得分:0)

我的一个数学库的旧版本中有几个类。我不再特别使用它们了,因为我最近一直在使用GLM数学库,但为了这个答案的目的,他们将展示所需要的东西。

GeneralMath.h - 执行基本数学运算需要此通用数学类。

#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

如果您注意到我的Vector3类中有一堆操作符和常用的函数,可以应用于3个组件的向量。现在,除法运算符返回一个vector3,并用标量除以每个分量。由于这个原因,我还包括了一个朋友操作符/和一个函数调用divideByVector。他们将做同样的操作。在代码中使用它们就像这样简单。

#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

您还可以尝试向量,其中一个组件的每个组件不是另一个组件的多个组合,例如:v1( 15.0f, 25.0f, 30.0f ) & v2( 3.0f, 5.0f, 7.0f)如果v2's k component现在v2's k component was 6.0f,则会因5而失败返回的结果值应为0.2,如果您反转除法,则应为-nan(ind) 。现在使用我的编译器(VS2015)如果这些值不是常见的倍数打印的消息给我的屏幕是:

try { ... } catch( ... ) {  }

如果将0作为值传递并尝试除以它,则调试器将抛出未处理的异常。通常,这将作为消息抛出并捕获到rand块中。但是我没有我的Logger和我的ExceptionHandler类可用于此演示。另请注意,由于我现在使用srand库,因此我不再使用<random>willRotateToInterfaceOrientation:,因此旧版库中的某些功能已弃用或已修订。