2

I'm passing a ivec2 (2 dimentional int vector) throw multiple methods calls of differnent classes. All by value. However after the first pass it starts to corrupt. Since the vector implementation if part of the library (called visualisation library), I'm guessing I'm doing something wrong.

Here is the callstack: callstack

The parameter in question is pixel. Its created in TesselatedHeightField::getHeightAt(vl::fvec2 uv):

vl::ivec2 pixel = vl::ivec2(
  static_cast<int> (std::floor(uv.x() * hfImage_->width())),
  static_cast<int> (std::floor(uv.y() * hfImage_->height())));

float patchesHeightPerCent = heightField_->getPatchContainer()->getRelativeHeightAt(pixel);

The debugger tells me that the values of pixel are 177 and 23, which is fine.

Down the callstack in:

float
PatchContainer::getRelativeHeightAt(vl::ivec2 pixel)
{
  float relHeight = 0.0;
  for (PatchesVector::iterator iter = patches_.begin(); iter != patches_.end(); ++iter)
    {
      relHeight += (*iter)->getRelativeHeightAt(pixel);
    }
  return relHeight;
}

the pixel is allready corrupted showing -1073751104 and 177 for its values.

In Patch::getRelativeHeightAt(vl::ivec2 pixel) the values are -1073751204 and -1073751224.

In Patch::inside(vl::ivec2 pixel) the values are -1073751316 and -1208145864 .

about vl::ivec2

Again vl::ivec2 is part of the library.

vl::ivec2 is a type def typedef Vector2<GLint> ivec2;

Here are the contents of the ivec2 implementation. (Party of the library, not created by me).

    /**************************************************************************************/
/*                                                                                    */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.com                                               */
/*                                                                                    */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  All rights reserved.                                                              */
/*                                                                                    */
/*  Redistribution and use in source and binary forms, with or without modification,  */
/*  are permitted provided that the following conditions are met:                     */
/*                                                                                    */
/*  - Redistributions of source code must retain the above copyright notice, this     */
/*  list of conditions and the following disclaimer.                                  */
/*                                                                                    */
/*  - Redistributions in binary form must reproduce the above copyright notice, this  */
/*  list of conditions and the following disclaimer in the documentation and/or       */
/*  other materials provided with the distribution.                                   */
/*                                                                                    */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
/*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
/*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
/*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
/*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
/*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
/*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
/*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
/*                                                                                    */
/**************************************************************************************/

#ifndef Vector2_INCLUDE_ONCE
#define Vector2_INCLUDE_ONCE

#include <vlCore/OpenGLDefs.hpp>
#include <cmath>

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

#ifdef dot
#undef dot
#endif

#ifdef cross
#undef cross
#endif

namespace vl
{
  // trigonometric constants

  //! Greek Pi constant using \p double precision.
  const double dPi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093845;
  //! Constant to convert degrees into radians using \p double precision.
  const double dDEG_TO_RAD = dPi / 180.0;
  //! Constant to convert radians into degrees using \p double precision.
  const double dRAD_TO_DEG = 180.0 / dPi;

  //! Greek Pi constant using \p float precision.
  const float fPi = (float)3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093845;
  //! Constant to convert degrees into radians using \p float precision.
  const float fDEG_TO_RAD = float(dPi / 180.0);
  //! Constant to convert radians into degrees using \p float precision.
  const float fRAD_TO_DEG = float(180.0 / dPi);

  // fast square root

  #if VL_FAST_SQUARE_ROOTS == 1
    #define VL_FLOAT_SQRT(x)    fast_sqrt(x)
    #define VL_FLOAT_INVSQRT(x) fast2_inversesqrt(x)
  #else
    #define VL_FLOAT_SQRT(x)    ((float)::sqrt(x))
    #define VL_FLOAT_INVSQRT(x) (1.0f/(float)::sqrt(x))
  #endif

  // fast square root functions, see Dave Eberly's paper and http://www.beyond3d.com/content/articles/8/

  inline float fast1_inversesqrt(float x)
  {
    float xhalf = 0.5f*x;
    union { float f; unsigned int i; } num;
    num.f = x;
    num.i = 0x5f3759df - (num.i>>1);
    x = num.f;
    x = x*(1.5f - xhalf*x*x); // single iteration, very quick, but very poor precision
    return x;
  }
  inline float fast2_inversesqrt(float x)
  {
    float xhalf = 0.5f*x;
    union { float f; unsigned int i; } num;
    num.f = x;
    num.i = 0x5f3759df - (num.i>>1);
    x = num.f;
    x = x*(1.5f - xhalf*x*x);
    x = x*(1.5f - xhalf*x*x); // two iterations, sligthtly better precision
    return x;
  }
  inline float fast_sqrt(float x) { if (x == 0.0f) return 0.0f; else return x * fast2_inversesqrt(x); }

  /**
   * The Vector2 class is a template class that implements a generic 2 components vector, see also vl::fvec2, vl::dvec2, vl::uvec2, vl::ivec2, vl::svec2, vl::usvec2, vl::bvec2, vl::ubvec2.
   * \sa Vector4, Vector3, Matrix4, Matrix3, Matrix2
   */
  template<typename T_Scalar>
  class Vector2
  {
  public:
    typedef T_Scalar scalar_type;
    static const int scalar_count = 2;
    Vector2(const Vector2& other) { *this = other; }
    Vector2() { x() = y() = 0; }

    template<class T>
    explicit Vector2(const T& other)
    {
      x() = (T_Scalar)other.x();
      y() = (T_Scalar)other.y();
    }

    explicit Vector2(T_Scalar x, T_Scalar y)
    {
      mScalar[0] = x;
      mScalar[1] = y;
    }

    T_Scalar* ptr() { return mScalar; }
    const T_Scalar* ptr() const { return mScalar; }

    const T_Scalar& x() const { return mScalar[0]; }
    const T_Scalar& y() const { return mScalar[1]; }

    T_Scalar& x() { return mScalar[0]; }
    T_Scalar& y() { return mScalar[1]; }

    const T_Scalar& r() const { return mScalar[0]; }
    const T_Scalar& g() const { return mScalar[1]; }

    T_Scalar& r() { return mScalar[0]; }
    T_Scalar& g() { return mScalar[1]; }

    const T_Scalar& s() const { return mScalar[0]; }
    const T_Scalar& t() const { return mScalar[1]; }

    T_Scalar& s() { return mScalar[0]; }
    T_Scalar& t() { return mScalar[1]; }

    Vector2 operator+(const Vector2& other) const
    {
      return Vector2(x()+other.x(), y()+other.y());
    }
    Vector2 operator-(const Vector2& other) const
    {
      return Vector2(x()-other.x(), y()-other.y());
    }
    Vector2 operator*(const Vector2& other) const
    {
      return Vector2(x()*other.x(), y()*other.y());
    }
    Vector2 operator/(const Vector2& other) const
    {
      return Vector2(x()/other.x(), y()/other.y());
    }
    Vector2 operator+(T_Scalar val) const
    {
      return Vector2(x()+val, y()+val);
    }
    Vector2 operator-(T_Scalar val) const
    {
      return Vector2(x()-val, y()-val);
    }
    Vector2 operator*(T_Scalar val) const
    {
      return Vector2(x()*val, y()*val);
    }
    Vector2 operator/(T_Scalar val) const
    {
      return Vector2(x()/val, y()/val);
    }
    Vector2 operator-() const
    {
      return Vector2(-x(), -y());
    }
    Vector2& operator+=(const Vector2& other)
    {
      *this = *this + other;
      return *this;
    }
    Vector2& operator-=(const Vector2& other)
    {
      *this = *this - other;
      return *this;
    }
    Vector2& operator*=(const Vector2& other)
    {
      *this = *this * other;
      return *this;
    }
    Vector2& operator/=(const Vector2& other)
    {
      *this = *this / other;
      return *this;
    }
    Vector2& operator+=(T_Scalar val)
    {
      *this = *this + val;
      return *this;
    }
    Vector2& operator-=(T_Scalar val)
    {
      *this = *this - val;
      return *this;
    }
    Vector2& operator*=(T_Scalar val)
    {
      *this = *this * val;
      return *this;
    }
    Vector2& operator/=(T_Scalar val)
    {
      *this = *this / val;
      return *this;
    }
    Vector2& operator=(const Vector2& other)
    {
      x() = other.x();
      y() = other.y();
      return *this;
    }
    Vector2& operator=(T_Scalar val)
    {
      x() = y() = val;
      return *this;
    }
    bool operator==(const Vector2& other) const
    {
      return x() == other.x() && y() == other.y();
    }
    bool operator!=(const Vector2& other) const
    {
      return !operator==(other);
    }
    bool operator<(const Vector2& other) const
    {
      if (x() != other.x())
        return x() < other.x();
      else
        return y() < other.y();
    }
    T_Scalar& operator[](unsigned i) { return mScalar[i]; }
    const T_Scalar& operator[](unsigned i) const { return mScalar[i]; }
    T_Scalar length() const { return ::sqrt(x()*x()+y()*y()); }
    T_Scalar lengthSquared() const { return x()*x()+y()*y(); }
    bool isNull() const { return !x() && !y(); }
    const Vector2& normalize(T_Scalar *len=NULL)
    {
      T_Scalar l = length();
      if (len)
        *len = l;
      if (l)
        *this *= (T_Scalar)(1.0/l); 
      return *this; 
    }

  protected:
    T_Scalar mScalar[scalar_count];
  };

  template<typename T>
  inline const Vector2<T> operator*(T val, const Vector2<T>& v)
  {
    return v * val;
  }

  //! A 2 components vector with \p GLint precision.
  typedef Vector2<GLint> ivec2;
  //! A 2 components vector with \p GLuint precision.
  typedef Vector2<GLuint> uvec2;
  //! A 2 components vector with \p GLfloat precision.
  typedef Vector2<GLfloat> fvec2;
  //! A 2 components vector with \p GLdouble precision.
  typedef Vector2<GLdouble> dvec2;
  //! A 2 components vector with \p GLbyte precision.
  typedef Vector2<GLbyte> bvec2;
  //! A 2 components vector with \p GLubyte precision.
  typedef Vector2<GLubyte> ubvec2;
  //! A 2 components vector with \p GLshort precision.
  typedef Vector2<GLshort> svec2;
  //! A 2 components vector with \p GLushort precision.
  typedef Vector2<GLushort> usvec2;

  #if VL_PIPELINE_PRECISION == 2
    //! Defined as: \p 'typedef \p dvec2 \p vec2'. See also \ref VL_PIPELINE_PRECISION.
    typedef dvec2 vec2;
  #else
    //! Defined as: \p 'typedef \p fvec2 \p vec2'. See also \ref VL_PIPELINE_PRECISION.
    typedef fvec2 vec2;
  #endif

  inline float dot(const fvec2& v1, const fvec2& v2) { return v1.x()*v2.x() + v1.y()*v2.y(); }
  inline double dot(const dvec2& v1, const dvec2& v2) { return v1.x()*v2.x() + v1.y()*v2.y(); }
  inline float dot(const ivec2& v1, const ivec2& v2) { return (float)(v1.x()*v2.x() + v1.y()*v2.y()); }
  inline float dot(const uvec2& v1, const uvec2& v2) { return (float)(v1.x()*v2.x() + v1.y()*v2.y()); }

  inline float min(float a, float b) { return a < b ? a : b; }
  inline double min(double a, double b) { return a < b ? a : b; }
  inline int min(int a, int b) { return a < b ? a : b; }
  inline unsigned int min(unsigned int a, unsigned int b) { return a < b ? a : b; }
  inline float max(float a, float b) { return a > b ? a : b; }
  inline double max(double a, double b) { return a > b ? a : b; }
  inline int max(int a, int b) { return a > b ? a : b; }
  inline unsigned int max(unsigned int a, unsigned int b) { return a > b ? a : b; }
  inline float clamp(float x, float minval, float maxval) { return min(max(x,minval),maxval); }
  inline double clamp(double x, double minval, double maxval) { return min(max(x,minval),maxval); }
  inline int clamp(int x, int minval, int maxval) { return min(max(x,minval),maxval); }
  inline unsigned int clamp(unsigned int x, unsigned int minval, unsigned int maxval) { return min(max(x,minval),maxval); }

  inline fvec2 min(const fvec2& a, const fvec2& b)
  {
    return fvec2( a.x() < b.x() ? a.x() : b.x(),
      a.y() < b.y() ? a.y() : b.y());
  }
  inline fvec2 min(const fvec2& a, float b)
  {
    return fvec2( a.x() < b ? a.x() : b,
      a.y() < b ? a.y() : b);
  }
  inline dvec2 min(const dvec2& a, const dvec2& b)
  {
    return dvec2( a.x() < b.x() ? a.x() : b.x(),
      a.y() < b.y() ? a.y() : b.y());
  }
  inline dvec2 min(const dvec2& a, double b)
  {
    return dvec2( a.x() < b ? a.x() : b,
      a.y() < b ? a.y() : b);
  }
  inline ivec2 min(const ivec2& a, const ivec2& b)
  {
    return ivec2( a.x() < b.x() ? a.x() : b.x(),
      a.y() < b.y() ? a.y() : b.y());
  }
  inline ivec2 min(const ivec2& a, int b)
  {
    return ivec2( a.x() < b ? a.x() : b,
      a.y() < b ? a.y() : b);
  }
  inline uvec2 min(const uvec2& a, const uvec2& b)
  {
    return uvec2( a.x() < b.x() ? a.x() : b.x(),
      a.y() < b.y() ? a.y() : b.y());
  }
  inline uvec2 min(const uvec2& a, unsigned int b)
  {
    return uvec2( a.x() < b ? a.x() : b,
      a.y() < b ? a.y() : b);
  }
  inline fvec2 max(const fvec2& a, const fvec2& b)
  {
    return fvec2( a.x() > b.x() ? a.x() : b.x(),
      a.y() > b.y() ? a.y() : b.y());
  }
  inline fvec2 max(const fvec2& a, float b)
  {
    return fvec2( a.x() > b ? a.x() : b,
      a.y() > b ? a.y() : b);
  }
  inline dvec2 max(const dvec2& a, const dvec2& b)
  {
    return dvec2( a.x() > b.x() ? a.x() : b.x(),
      a.y() > b.y() ? a.y() : b.y());
  }
  inline dvec2 max(const dvec2& a, double b)
  {
    return dvec2( a.x() > b ? a.x() : b,
      a.y() > b ? a.y() : b);
  }
  inline ivec2 max(const ivec2& a, const ivec2& b)
  {
    return ivec2( a.x() > b.x() ? a.x() : b.x(),
      a.y() > b.y() ? a.y() : b.y());
  }
  inline ivec2 max(const ivec2& a, int b)
  {
    return ivec2( a.x() > b ? a.x() : b,
      a.y() > b ? a.y() : b);
  }
  inline uvec2 max(const uvec2& a, const uvec2& b)
  {
    return uvec2( a.x() > b.x() ? a.x() : b.x(),
      a.y() > b.y() ? a.y() : b.y());
  }
  inline uvec2 max(const uvec2& a, unsigned int b)
  {
    return uvec2( a.x() > b ? a.x() : b,
      a.y() > b ? a.y() : b);
  }
  inline fvec2 clamp(const fvec2& x, float minval, float maxval) { return min(max(x,minval),maxval); }
  inline fvec2 clamp(const fvec2& x, const fvec2& minval, const fvec2& maxval) { return min(max(x,minval),maxval); }
  inline dvec2 clamp(const dvec2& x, double minval, double maxval) { return min(max(x,minval),maxval); }
  inline dvec2 clamp(const dvec2& x, const dvec2& minval, const dvec2& maxval) { return min(max(x,minval),maxval); }
  inline ivec2 clamp(const ivec2& x, int minval, int maxval) { return min(max(x,minval),maxval); }
  inline ivec2 clamp(const ivec2& x, const ivec2& minval, const ivec2& maxval) { return min(max(x,minval),maxval); }
  inline uvec2 clamp(const uvec2& x, unsigned int minval, unsigned int maxval) { return min(max(x,minval),maxval); }
  inline uvec2 clamp(const uvec2& x, const uvec2& minval, const uvec2& maxval) { return min(max(x,minval),maxval); }
}

#endif

Any help is appreciated.

Visualisation Library Homepage

Edit:

I did put a breakpoint at Vector2(const Vector2& other) { *this = other; }. Here are the debuger results: before execution

This calls:

Vector2& operator=(const Vector2& other)
{
  x() = other.x();
  y() = other.y();
  return *this;
}

Resulting in: after = operator

At the end of the copy constructor the debugger yelds vales that are incorrect. after copy constructor

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Velrok
  • 345
  • 4
  • 17
  • 1
    what does `x()` and `y()` return/look like? – Nim Jul 06 '11 at 13:51
  • I added the missig code to the question. – Velrok Jul 06 '11 at 13:57
  • why you need a distint template to asign operator (const T& other)? – Zhen Jul 06 '11 at 14:16
  • Vector2<> misses a default constructor as well as a constructor that accepts two scalar values as in your first snippet. – Sebastian Mach Jul 06 '11 at 14:20
  • @phresnel I didn't post the complete source code in an attempt to keep it simple. Because its seams to create more trouble that it solves here is the compleme source of the vector2. Remember the source is part of the library, as a result I'm not sure why some code is designed the way it is. – Velrok Jul 06 '11 at 14:26
  • @Velrok - You should add edits to your question, not to the answers. – Bo Persson Jul 06 '11 at 14:59
  • These new screenshots are helpful... and wierd. The address of `this` changed. Are you compiling with optimizations enabled? – Ben Voigt Jul 06 '11 at 15:03
  • @BoPersson Thx. I wasn't sure where to put it. – Velrok Jul 06 '11 at 15:03
  • @BenVoigt No. I don't use any optimization `-O0` . – Velrok Jul 06 '11 at 15:48
  • @Velrok: That's messed up. Only reason I can think of for the address of `this` changing like that is if the debugger is reading a CPU register that's temporarily used for something else, and without optimization enabled, that shouldn't happen. Do you get the same problems with a newer version of gcc? The one you have is 3 years old. – Ben Voigt Jul 06 '11 at 16:30
  • @BenVoigt We have a very "stable" CentOS here ;) . Because I'm not an admin, and I need to make progress I wount persue this issue further. Its also just a prove of consept software, so performance and maintainablity arn't priorities here. I'm sorry. I know its unsetisfying. – Velrok Jul 07 '11 at 08:43

2 Answers2

2

What OS is this? It sounds like a calling convention or structure layout mismatch, which you could easily get if not using the same compiler version and options for all files.

Put a breakpoint in the ivec2 copy constructor and see whether the value are correct there.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I compiles the library myself under CentOS using g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-48) – Velrok Jul 06 '11 at 14:00
  • Including the source so that I can use the debugger will take some minutes. – Velrok Jul 06 '11 at 14:02
  • I'm quied new to c++ so this seams like an indepth problem to me. – Velrok Jul 06 '11 at 14:51
  • 1
    It looks like the problem is the copy constructor. I changed all method signatures from `(const vl::ivec2 pixel)` to `(const vl::ivec2& pixel)`, therefor passing by const reference. Now everything works like expected. Also this is just a workaround. It works for me. I posted a thread in the developer forum pointing to this stack overflow question. – Velrok Jul 06 '11 at 15:40
0

You could remove explicit from the copy constructor. But its explicit to stop pass by value as this is inefficient

QuentinUK
  • 2,997
  • 21
  • 20