One time, my program runs and shows expected output, and sometime it don't (it compiles without any errors). Try-Catch doesen't seem to affect on this random output.
v3f is a simple class that holds 3 floats: x,y,z and some basic math operations on them (all of them work perfectly fine)
v3f calculate_normal(v3f a, v3f b, v3f c);
"calculate_normal" is just a simple multiplication and subtraction function that returns v3f, AND when it "decides" to work it gives expected output.
int main()
{
lv::v3f c(-0.5, -0.5, 0);
lv::v3f b(0, .5f, 0);
lv::v3f a(0.5, -0.5, 0);
/* if I add here
v3f d = a - b;
*/ it works !
lv::v3f normal;
std::cout << "1\n";
normal = lv::calculate_normal(a, b, c);
std::cout << "2\n";
std::cout << normal.x << " " << normal.y << " " << normal.z << std::endl;
std::cout << "3\n";
return 0;
}
I cout'ed 1, 2 and 3 to see when program breaks and it's sometimes outputting all:
output:
1
2
0 0 1
3
And sometimes it stops on "1" (before calculating normal)
output:
1
// - - - - - - - - - - - - - - "Vector3.h"
#ifndef _LV_VECTOR_3_H_
#define _LV_VECTOR_3_H_
namespace lv{
template <class T>
class Vector3
{
public:
T x, y, z;
Vector3(T _x = 0, T _y = 0, T _z = 0) : x(_x), y(_y), z(_z){}
float length()
{
return sqrt( pow(x, 2) + pow(y, 2) + pow(z, 2) );
}
Vector3<T> normal()
{
float l = length();
return Vector3<T>(x/l, y/l, z/l);
}
void normalize()
{
float l = length();
x /= l;
y /= l;
z /= l;
}
Vector3<T>& operator += (const Vector3<T>& o)
{
this->x += o.x;
this->y += o.y;
this->z += o.z;
return *this;
}
Vector3<T>& operator -= (const Vector3<T>& o)
{
this->x -= o.x;
this->y -= o.y;
this->z -= o.z;
return *this;
}
Vector3<T>& operator *= (const Vector3<T>& o)
{
this->x *= o.x;
this->y *= o.y;
this->z *= o.z;
return *this;
}
Vector3<T>& operator /= (const Vector3<T>& o)
{
this->x /= o.x;
this->y /= o.y;
this->z /= o.z;
return *this;
}
friend Vector3<T>& operator + (const Vector3<T>& o, const Vector3<T> p)
{
Vector3<T>* tmp;
tmp->x = o.x + p.x;
tmp->y = o.y + p.y;
tmp->z = o.z + p.z;
return *tmp;
}
friend Vector3<T>& operator - (const Vector3<T>& o, const Vector3<T> p)
{
Vector3<T>* tmp;
tmp->x = o.x - p.x;
tmp->y = o.y - p.y;
tmp->z = o.z - p.z;
return *tmp;
}
friend Vector3<T>& operator / (const Vector3<T>& o, const Vector3<T> p)
{
Vector3<T>* tmp;
tmp->x = o.x / p.x;
tmp->y = o.y / p.y;
tmp->y = o.z / p.z;
return *tmp;
}
friend Vector3<T>& operator * (const Vector3<T>& o, const Vector3<T> p)
{
Vector3<T>* tmp;
tmp->x = o.x * p.x;
tmp->y = o.y * p.y;
tmp->z = o.z * p.z;
return *tmp;
}
friend Vector3<T>& operator * (const Vector3<T>&o, float p)
{
Vector3<T>* tmp;
tmp->x = o.x * p;
tmp->y = o.y * p;
tmp->z = o.z * p;
return *tmp;
}
friend Vector3<T>& operator / (const Vector3<T>&o, float p)
{
Vector3<T>* tmp;
tmp->x = o.x / p;
tmp->y = o.y / p;
tmp->z = o.z / p;
return *tmp;
}
};
#define v3f Vector3<float>
#define v3i Vector3<int>
#define v3d Vector3<double>
#define v3ui Vector3<unsigned int>
}; // L V
#endif
// - - - - - - - - - - - - - - "Vector.h"
#ifndef _LV_VECTOR_H_
#define _LV_VECTOR_H_
#include "Vector2.h"
#include "Vector3.h"
#include "Vector4.h"
#endif
// - - - - - - - - - - - - - - "Utils.h"
#ifndef _LV_UTILS_H_
#define _LV_UTILS_H_
#include "Vector.h"
namespace lv {
v3f calculate_normal(v3f a, v3f b, v3f c)
{
std::cout << "a\n";
v3f u = b - a;
v3f v = c - a;
std::cout << "b\n";
v3f n;
n.x = u.y * v.z - u.z * v.y;
n.y = u.z * v.x - u.x * v.z;
n.z = u.x * v.y - u.y * v.x;
std::cout << "c\n";
return n;
}
}; // L V
#endif
// - - - - - - - - - - - - - - "main.cpp"
#include <iostream>
#include "Liviana/Math/Utils.h"
int main()
{
lv::v3f c(-0.5, -0.5, 0);
lv::v3f b(0, .5f, 0);
lv::v3f a(0.5, -0.5, 0);
lv::v3f normal;
std::cout << "1\n";
normal = lv::calculate_normal(a, b, c);
std::cout << "2\n";
std::cout << normal.x << " " << normal.y << " " << normal.z << std::endl;
std::cout << "3\n";
return 0;
}
Only the mutating operators should return references. The other operators should return values.
OK:
Vector3<T>& operator += (const Vector3<T>& o)
Not ok:
friend Vector3<T>& operator + (const Vector3<T>& o, const Vector3<T> p)
The above is not ok, because...what are you going to return a reference to? 1 + 2 is neither 1 nor 2. It's something else. You'll need storage for the result (a Vector3) and you'll need to return it by value.
friend Vector3<T> operator + (const Vector3<T>& o, const Vector3<T> p) {
Vector3<T> tmp;
tmp.x = o.x + p.x;
tmp.y = o.y + p.y;
tmp.z = o.z + p.z;
return tmp;
}
Note the & is gone from the return type.
You are dereferencing an uninitialized pointer in each of your arithmetic operators:
Vector3<T>& operator + (const Vector3<T>& o, const Vector3<T> p)
Vector3<T>* tmp; // Where does tmp point to?
tmp->x = o.x + p.x;
tmp->y = o.y + p.y;
tmp->z = o.z + p.z;
return *tmp;
}
Dereferencing a pointer that doesn't point to a valid object within its lifetime is Undefined Behaviour, and causes your program to be invalid and able to do literally anything.
You should instead avoid using pointers. Just use an ordinary local variable and return it by value:
Vector3<T> operator + (const Vector3<T>& o, const Vector3<T> p)
Vector3<T> tmp; // No more pointer
tmp.x = o.x + p.x;
tmp.y = o.y + p.y;
tmp.z = o.z + p.z;
return tmp;
}
Related
This question already has answers here:
Why can an aggreggate struct be brace-initialized, but not emplaced using the same list of arguments as in the brace initialization?
(2 answers)
Closed 1 year ago.
I have a fairly bog standard Vector4 struct (the math kind not the C++ kind) which is a POD and is templated:
template<typename T>
struct Vector4 {
T x, y, z, w;
Vector4 operator+(const Vector4& other) const { return Vector4{ x + other.x, y + other.y, z + other.z, w + other.w }; }
Vector4 operator-(const Vector4& other) const { return Vector4{ x - other.x, y - other.y, z - other.z, w - other.w }; }
Vector4 operator*(const Vector4& other) const { return Vector4{ x * other.x, y * other.y, z * other.z, w * other.w }; }
Vector4 operator/(const Vector4& other) const { return Vector4{ x / other.x, y / other.y, z / other.z, w / other.w }; }
Vector4 operator+(const T& a) const { return Vector4{ x + a, y + a, z + a, w + a }; }
Vector4 operator-(const T& a) const { return Vector4{ x - a, y - a, z - a, w - a }; }
Vector4 operator*(const T& a) const { return Vector4{ x * a, y * a, z * a, w * a }; }
Vector4 operator/(const T& a) const { return Vector4{ x / a, y / a, z / a, z / a }; }
Vector4& operator+=(const Vector4& other) { x += other.x; y += other.y; z += other.z; w += other.w; return *this; }
Vector4& operator-=(const Vector4& other) { x -= other.x; y -= other.y; z -= other.z; w -= other.w; return *this; }
Vector4& operator*=(const Vector4& other) { x *= other.x; y *= other.y; z *= other.z; w *= other.w; return *this; }
Vector4& operator/=(const Vector4& other) { x /= other.x; y /= other.y; z /= other.z; w /= other.w; return *this; }
Vector4& operator+=(const T& a) { x += a; y += a; z += a; w += a; return *this; }
Vector4& operator-=(const T& a) { x -= a; y -= a; z -= a; w -= a; return *this; }
Vector4& operator*=(const T& a) { x *= a; y *= a; z *= a; w *= a; return *this; }
Vector4& operator/=(const T& a) { x /= a; y /= a; z /= a; w /= a; return *this; }
T& operator[](size_t index) { return *(reinterpret_cast<T*>(this) + index); }
};
using Vector4f = Vector4<float>;
using Vector4i = Vector4<int>;
using Vector4i32 = Vector4<int32_t>;
using Vector4ui32 = Vector4<uint32_t>;
using Vector4i64 = Vector4<int64_t>;
using Vector4ui64 = Vector4<uint64_t>;
The problem I am having is that I cant make a std::vector of my Vector4 class. When I try the following:
std::vector<ogl::Vector4f> vec;
vec.emplace_back(1.0f, 2.0f, 3.0f, 4.0f);
I get this compile error
'Vector4::Vector4': no overloaded function takes 4 arguments
I have my own vector (C++ kind not math kind) class that I use and I tried using emplace_back with it but I got the same error. I also tried using and not using allocators (in my custom vector class) and have tried almost everything under the sun!
I can fix this issue by defining a constructor, but then it doesn't become a POD anymore. Normal construction using brace initialization works fine so I don't what's wrong.
If anyone can explain why this is happening/how to fix this (or if this is normal behaviour) it would be most appreciated.
emplace_back uses parentheses to initialize the value, which means a constructor is required to use it until C++20. C++20 introduced parenthesized initialization of aggregates, so you code becomes valid as is.
Until then you can just do
vec.push_back({1.0f, 2.0f, 3.0f, 4.0f});
I get error C2440: '=' : cannot convert from 'math::Vec3' to 'float' but i don't understand why. I think buffer is Vec3 type and v object is type Vec3 also.
The Vec3 class is used as a generic three-dimensional vector and thus it defines several numerical operators that can be used on Vec3 and S data.
Image.h
#ifndef _IMAGE
#define _IMAGE
#include "Array.h"
#include "Serializable.h"
#include "Vec3.h"
using namespace math;
class Image : public Array<Vec3<float>>, public Serializable
{
public:
enum channel_t { RED = 0, GREEN, BLUE };
protected:
Vec3<float> *buffer;
public:
Vec3<float> getPixel(unsigned int x, unsigned int y) const;
/*code*/
};
#endif
Image.cpp
#include "Image.h"
using namespace math;
Vec3<float> Image::getPixel(unsigned int x, unsigned int y) const {
math::Vec3<float> v;
int s = 0;
if ((x <= Image::getWidth()) && (y <= Image::getHeight()) && (x >= 0) && (y >= 0))
{
for (unsigned int i = 1; i == getWidth(); i++)
{
for (unsigned int j = 1; i == getHeight(); j++)
{
if (i == x - 1 && j == y - 1)
goto label;
else
s = s + 3;
}
}
label:
v[Image::RED] = buffer[s + RED]; <-------------------HERE
v[Image::GREEN] = buffer[s + GREEN]; <-------------------I GET AN
v[Image::BLUE] = buffer[s + BLUE]; <-------------------ERROR
}
return v;
}//end of getPixel
Vec3.h
#ifndef _Vec3_
#define _Vec3_
namespace math
{
template <typename S>
class Vec3
{
public:
// data members
//! The first coordinate of the vector
union { S x, r; };
//! The second coordinate of the vector
union { S y, g; };
//! The third coordinate of the vector
union { S z, b; };
S & operator [] (size_t index)
{
return *((S*)this + index);
}
Vec3<S> operator + (const Vec3<S> & right)
{
Vec3<S> left;
left.x = x + right.x;
left.y = y + right.y;
left.z = z + right.z;
return left;
}
Vec3<S> operator - (const Vec3<S> & right)
{
Vec3<S> left;
left.x = x - right.x;
left.y = y - right.y;
left.z = z - right.z;
return left;
}
Vec3<S> operator * (const Vec3<S> & right)
{
Vec3<S> left;
left.x = x * right.x;
left.y = y * right.y;
left.z = z * right.z;
return left;
}
Vec3<S> operator * (S right)
{
Vec3<S> left;
left.x = x * right;
left.y = y * right;
left.z = z * right;
return left;
}
Vec3<S> operator / (S right)
{
Vec3<S> left;
left.x = x / right;
left.y = y / right;
left.z = z / right;
return left;
}
Vec3<S> operator / (const Vec3<S> & right)
{
Vec3<S> left;
left.x = x / right.x;
left.y = y / right.y;
left.z = z / right.z;
return left;
}
Vec3<S> & operator += (const Vec3<S> & right)
{
x += right.x;
y += right.y;
z += right.z;
return *this;
}
Vec3<S> & operator -= (const Vec3<S> & right)
{
x -= right.x;
y -= right.y;
z -= right.z;
return *this;
}
Vec3<S> & operator /= (const Vec3<S> & right)
{
x /= right.x;
y /= right.y;
z /= right.z;
return *this;
}
Vec3<S> & operator *= (const Vec3<S> & right)
{
x *= right.x;
y *= right.y;
z *= right.z;
return *this;
}
Vec3<S> & operator *= (S right)
{
x *= right;
y *= right;
z *= right;
return *this;
}
Vec3<S> & operator /= (S right)
{
x /= right;
y /= right;
z /= right;
return *this;
}
Vec3<S>(S x, S y, S z) : x(x), y(y), z(z) {}
Vec3<S>(S val) : x(val), y(val), z(val) {}
Vec3<S>() : x(), y(), z() {}
Vec3<S>(const Vec3<S> & right) : x(right.x), y(right.y), z(right.z) {}
Vec3<S> & operator = (const Vec3<S> & right)
{
x = right.x;
y = right.y;
z = right.z;
return *this;
}
bool operator == (const Vec3<S> & right) const
{
return x == right.x && y == right.y && z == right.z;
}
bool operator != (const Vec3<S> & right) const
{
return x != right.x || y != right.y || z != right.z;
}
};
template<typename S>
Vec3<S> operator * (S a, Vec3<S> v)
{
return v*a;
}
template<typename S>
Vec3<S> operator * (int a, Vec3<S> v)
{
return v*S(a);
}
template<typename S>
Vec3<S> operator * (Vec3<S> v, int a)
{
return v*S(a);
}
template<typename S>
Vec3<S> operator / (Vec3<S> v, int a)
{
return v/S(a);
}
} // namespace math
#endif
v and buffer have different types:
Vec3<float> *buffer;
math::Vec3<float> v;
buffer is pointer to Vec3 and when you write "buffer[s + RED];" you try to get s + RED element of pointer. But in v vector and v[Image::RED] is red channel (it is float).
Try to use this:
v[Image::RED] = buffer[s][RED];
buffer is not of math::Vec3 type but a pointer to object of such type, which can be also interpreted as an array of such objects. buffer[s + RED] is one element of this array, so it's of math::Vec3 type while v[Image::RED] is of float type.
You may want to write
v[Image::RED] = buffer[s][Image::RED];
buffer is a pointer to Vec3<float>, so buffer[k] is a Vec3<float>.
And v[x] is a float, not a Vec3<float>.
Your indexing suggests that you intend to have buffer be a "flat" representation of pixels as floats, in which case you could use
std::vector<float> buffer;
(or char* buffer; but that invites a whole mess of memory management problems.)
and you can use arithmetic rather than a search loop:
Vec3<float> Image::getPixel(unsigned int x, unsigned int y) const {
math::Vec3<float> v;
if (x < getWidth() && y < getHeight() && x >= 0 && y >= 0)
{
int s = 3 * y * getWidth() + 3 * x;
v[RED] = buffer[s + RED];
v[GREEN] = buffer[s + GREEN];
v[BLUE] = buffer[s + BLUE];
}
return v;
}
(This uses zero-based indexing; your code seems conflicted about whether pixels are zero-based or one-based.)
v is of type math::Vec3<float> and v[0] is a float.
buffer is a pointer to Vec3<float> and by indexing it you use operator[] of the pointer, which is array access. So by buffer[i] you get a Vec3<float>, which is not convertible to a simple float.
So I have code like this:
#include <iostream>
#include <string>
using namespace std;
#pragma region Class Definitions
struct Vector3
{
double x;
double y;
double z;
};
class Plane {
Vector3 point, normal, p_p1, p_p2, p_p3;
public:
Plane(Vector3 p1,
Vector3 p2, Vector3 p3);
const Vector3& get_point() const;
const Vector3& get_normal() const;
double get_hnf_d() const;
Vector3 closest_point(const Vector3& p);
double distance_to(const Vector3& p);
Vector3 intersect_line(const Line &l);
};
int main()
{
a.x = 1;
a.y = 2;
a.z = 3;
b.x = -1;
b.y = 2;
b.z = -2;
s = -2;
o.x = 0;
o.y = 0;
o.z = 0;
p1.x = sqrt(1 / 8);
p1.y = sqrt(1 / 8);
p1.z = sqrt(3 / 4);
p2.x = 0;
p2.y = 2 * sqrt(1 / 8);
p2.z = 0;
p3.x = sqrt(1 / 8) + sqrt(3 / 8);
p3.y = sqrt(1 / 8) + sqrt(3 / 8);
p3.z = sqrt(3 / 4) - sqrt(1 / 4);
q1.x = 1;
q1.y = 1;
q1.z = 1;
q2.x = -1;
q2.y = -1;
q2.z = -1;
switch (choice)
{
...
Plane _plane(p1, p2, p3);
cout << "Distance to p1, p2, p3 respectievly is : " << _plane.distance_to(p1) << endl;
}
return 0;
}
Plane::Plane(Vector3 p1, Vector3 p2, Vector3 p3)
{
p_p1 = p1;
p_p2 = p2;
p_p3 = p3;
}
const Vector3 & Plane::get_point() const
{
return p_p1;
}
const Vector3 & Plane::get_normal() const
{
return normalize(p_p2);
}
double Plane::get_hnf_d() const
{
Vector3 n, numerator;
double denominator;
numerator = cross_product(substract(p_p1, p_p3), substract(p_p2, p_p3));
denominator = sqrt(pow(numerator.x, 2) + pow(numerator.y, 2) + pow(numerator.z, 2));
cout <<"read" << numerator.y << numerator.x << denominator;
n.x = numerator.x / denominator;
n.y = numerator.y / denominator;
n.z = numerator.z / denominator;
//distance from origin
return -1 * dot_product(p_p1, n);
}
Vector3 Plane::closest_point(const Vector3 & p)
{
return Vector3();
}
double Plane::distance_to(const Vector3 & p)
{
return get_hnf_d() + dot_product(p, get_normal()) ;
}
And I am setting the values as such:
Plane::Plane(Vector3 p1, Vector3 p2, Vector3 p3)
{
p_p1 = p1;
p_p2 = p2;
p_p3 = p3;
}
However I always get 0s returned for values whenever I try to say print p_p1.x, thereby failing my computation. where am I wrong? I am really a C++ beginner.
Thanks.
You are doing integer divisions in the line:
p1.x = sqrt(1 / 8);
1/8 is 0 in C++
This is true in all other initialization.
Try writing
p1.x = sqrt(1.0 / 8.0);
at first you must declare in main p1 and p2 and p3 and initialize them then pass them to plane's constructor:
#include <iostream>
using namespace std;
#include <cmath>
struct Vector3
{
double x;
double y;
double z;
};
class Plane
{
Vector3 point, normal, p_p1, p_p2, p_p3;
public:
Plane(Vector3 p1,
Vector3 p2, Vector3 p3) : p_p1(p1), p_p2(p2), p_p3(p3){}
double distance_to(const Vector3& p)const;
};
double Plane:: distance_to(const Vector3& p)const
{
return get_hnf_d() + dot_product(p, get_normal()) ;
}
int main()
{
Vector3 p1 = {sqrt(1.0 / 8.0), sqrt(1.0 / 8.0), sqrt(3.0 / 4.0)};
// do the same thing as above
Vector3 p2, p3;
Plane _plane(p1, p2, p3);
cout << "Distance to p1 is : " << _plane.distance_to(p1) << endl;
return 0;
}
this is just a sample not full code
Let say that we have two rectangles, defined with their bottom-left and top-right corners. For example: rect1 (x1, y1)(x2, y2) and rect2 (x3, y3)(x4, y4).
I'm trying to find the coordinates(bottom-left and top-right) of the intersected rectangle.
Any ideas, algorithm, pseudo code, would be greatly appreciated.
p.s. I found similar questions but they check only if 2 rectangle intersect.
If the input rectangles are normalized, i.e. you already know that x1 < x2, y1 < y2 (and the same for the second rectangle), then all you need to do is calculate
int x5 = max(x1, x3);
int y5 = max(y1, y3);
int x6 = min(x2, x4);
int y6 = min(y2, y4);
and it will give you your intersection as rectangle (x5, y5)-(x6, y6). If the original rectangles do not intersect, the result will be a "degenerate" rectangle (with x5 >= x6 and/or y5 >= y6), which you can easily check for.
P.S. As usual, small details will depend on whether you have to consider touching rectangles as intersecting.
To look for an intersection, you will have to do some simple comparison of the points:
So as we can see from the image if x3, y3 is greater or equal to x1, y1 and less than or equal to x2, y2 then it is inside the first rectangle, similarly you will need to check if x4, y4 falls inside the range of x1,y1 to x2,y2 as well.
if both conditions prove to be true then you can be sure that the second rectangle is totally encompassed by the first.
You will need to check the other way around as well, if finding out which is inside which is important to you.
You also have to have the rectangles be axis aligned, otherwise this will not work reliably.
Let me know if you need more detail, although I think a quick Google search will uncover much more detail for you very easily, but let me know and I can make a rectangle collision tutorial if you like.
In More Detail:
To find out if the rectangles have any intersections you can check the coordinates of their defining points, for our purposes we shall use top left and bottom right corner coordinates.
We can utilise a class to make this easier for us, and to maximise on the usability of the code we can use a 2d Vector and a 2d Point:
2dVectorPoint.h
#include <cmath>
class Vector2D
{
public:
float x;
float y;
Vector2D() {}
Vector2D(float inX, float inY)
{
x = inX;
y = inY;
}
Vector2D& Set(float inX, float inY)
{
x = inX;
y = inY;
return (*this);
}
float& operator [](long k) { return ((&x)[k]); }
const float& operator [](long k) const { return ((&x)[k]); }
Vector2D& operator +=(const Vector2D& v)
{
x += v.x;
y += v.y;
return (*this);
}
Vector2D& operator -=(const Vector2D& v)
{
x -= v.x;
y -= v.y;
return (*this);
}
Vector2D& operator *=(float t)
{
x *= t;
y *= t;
return (*this);
}
Vector2D& operator /=(float t)
{
float f = 1.0F / t;
x *= f;
y *= f;
return (*this);
}
Vector2D& operator &=(const Vector2D& v)
{
x *= v.x;
y *= v.y;
return (*this);
}
Vector2D operator -(void) const { return (Vector2D(-x, -y)); }
Vector2D operator +(const Vector2D& v) const { return (Vector2D(x + v.x, y + v.y)); }
Vector2D operator -(const Vector2D& v) const { return (Vector2D(x - v.x, y - v.y)); }
Vector2D operator *(float t) const { return (Vector2D(x * t, y * t)); }
Vector2D operator /(float t) const { float f = 1.0F / t; return (Vector2D(x * , y * f)); }
float operator *(const Vector2D& v) const { return (x * v.x + y * v.y); }
Vector2D operator &(const Vector2D& v) const { return (Vector2D(x * v.x, y * v.y)); }
bool operator ==(const Vector2D& v) const { return ((x == v.x) && (y == v.y)); }
bool operator !=(const Vector2D& v) const { return ((x != v.x) || (y != v.y)); }
Vector2D& Normalize(void) { return (*this /= sqrtf(x * x + y * y)); }
Vector2D& Rotate(float angle);
};
class Point2D : public Vector2D
{
public:
Point2D() {}
Point2D(float r, float s) : Vector2D(r, s) {}
Point2D& operator =(const Vector2D& v)
{
x = v.x;
y = v.y;
return (*this);
}
Point2D& operator *=(float t)
{
x *= t;
y *= t;
return (*this);
}
Point2D& operator /=(float t)
{
float f = 1.0F / t;
x *= f;
y *= f;
return (*this);
}
Point2D operator -(void) const{ return (Point2D(-x, -y)); }
Point2D operator +(const Vector2D& v) const { return (Point2D(x + v.x, y + v.y)); }
Point2D operator -(const Vector2D& v) const { return (Point2D(x - v.x, y - v.y)); }
Vector2D operator -(const Point2D& p) const { return (Vector2D(x - p.x, y - p.y)); }
Point2D operator *(float t) const { return (Point2D(x * t, y * t)); }
Point2D operator /(float t) const
{
float f = 1.0F / t;
return (Point2D(x * f, y * f));
}
};
inline Vector2D operator *(float t, const Vector2D& v){ return (Vector2D(t * v.x, t * v.y));}
inline Point2D operator *(float t, const Point2D& p){ return (Point2D(t * p.x, t * p.y));}
inline float Dot(const Vector2D& v1, const Vector2D& v2){ return (v1 * v2);}
inline float Magnitude(const Vector2D& v){ return (sqrtf(v.x * v.x + v.y * v.y));}
inline float InverseMag(const Vector2D& v){ return (1.0F / sqrtf(v.x * v.x + v.y * v.y));}
inline float SquaredMag(const Vector2D& v){ return (v.x * v.x + v.y * v.y);}
struct Origin2D_
{
const Point2D& operator +(const Vector2D& v) { return (static_cast<const Point2D&>(v)); }
Point2D operator -(const Vector2D& v) { return (Point2D(-v.x, -v.y)); }
};
2dVectorPoint.cpp
#include "2dVectorPoint.h"
Origin2D_ Origin2D;
Vector2D& Vector2D::Rotate(float angle)
{
float s = sinf(angle);
float c = cosf(angle);
float nx = c * x - s * y;
float ny = s * x + c * y;
x = nx;
y = ny;
return (*this);
}
extern Origin2D_ Origin2D;
Code used is adapted from here to save my fingers.
Then we can utilise this to easily compare:
we can define rectangle 1 as having P1 and P2 as its bounds and rectangle 2 as having P3 and P4 as its bounds, giving us the following comparison:
if ( P2.y <= P3.y && P1.y >= P4.y && P2.x>= P3.x && P1.x <= P4.x )
{
return true;
}
This will return a true value for any instance of intersection or for rectangle 1 encompassing rectangle 2 totally.
To only check for intersections just remove the equality check (take all the = out of the above equation), and you will be checking only for intersections. If you have an intersection you could then use linear algebra to evaluate the exact coordinates.
Let's say that a box has a radius X and radius Y (I know it has not but this term is useful here).
You will have:
rect1_x_radius = (x2-x1)/2
rect1_y_radius = (y2-y1)/2
and
rect2_x_radius = (x4-x3)/2
rect2_y_radius = (y4-y3)/2
Now if rect middle points are further away than sum of their radiuses in appropriate direction - they do not collide.
Otherwise they do - this hint should suffice.
You should be now able to finish your assignment.
UPDATE:
OK - let's solve it for 1D - later you'll solve it for 2D. Look at this piece of ... art ;-)
You see 2 segments - now some calculations:
rA = (maxA-minA) / 2
rB = (maxB-minB) / 2
midA = minA + rA
midB = minB + rB
mid_dist = |midA - midB|
Now how to check if collision occurs? As I said if sum of 'radiuses' is less than segments' distance - there is no collision:
if ( mid_dist > fabs(rA+rB) )
{
// no intersection
}
else
{
// segments intersect
}
Now it is your work to calculate intersection / common part in 1D and 2D. It is up to you now (o ryou can read Andrey's answer).
Here is the same situation but in 2D - two 1D situations:
You can deal with the x and y direction separately.
Assume that x1 <= x3 (the first box is at least as far to the left as the second). Then, there is overlap if and only if x1 <= x3 <= x2.
Similarly, assume y1 <= y3 (the first box is at least as far to the bottom as the second). Then, there is overlap if and only if y1 <= y3 <= y2.
If there is overlap in both directions, there is a rectangle overlapping. You can find the coordinates by sorting the x and y coordinates and selecting the middle two.
In pseudocode:
if (((x1 <= x3 && x3 <= x2) || (x3 <= x1 && x1 <= x4)) // x-overlap
&&
((y1 <= y3 && y3 <= y2) || (y3 <= y1 && y1 <= y4)) // y-overlap
) {
int[] xs = {x1, x2, x3, x4};
int[] ys = {y1, y2, y3, y4};
sort(xs);
sort(ys);
// bottom-left: xs[1], ys[1]
// top-right: xs[2], ys[2]
}
Just in case a straightforward C# solution would suit anyone:
public struct Rectangle
{
public double Left { get; }
public double Top { get; }
public double Width { get; }
public double Height { get; }
public double Right => Left + Width;
public double Bottom => Top + Height;
public static Rectangle Empty { get; } = new Rectangle(0, 0, 0, 0);
public Rectangle(double left, double top, double width, double height)
{
Left = left;
Top = top;
Width = width;
Height = height;
}
public static bool RectanglesIntersect(Rectangle rectangle1, Rectangle rectangle2)
{
rectangle1 = rectangle1.Normalize();
rectangle2 = rectangle2.Normalize();
if (rectangle2.Left >= rectangle1.Right)
return false;
if (rectangle2.Right <= rectangle1.Left)
return false;
if (rectangle2.Top >= rectangle1.Bottom)
return false;
if (rectangle2.Bottom <= rectangle1.Top)
return false;
return true;
}
public static Rectangle GetIntersection(Rectangle rectangle1, Rectangle rectangle2)
{
rectangle1 = rectangle1.Normalize();
rectangle2 = rectangle2.Normalize();
if (rectangle1.IntersectsWith(rectangle2))
{
double left = Math.Max(rectangle1.Left, rectangle2.Left);
double width = Math.Min(rectangle1.Right, rectangle2.Right) - left;
double top = Math.Max(rectangle1.Top, rectangle2.Top);
double height = Math.Min(rectangle1.Bottom, rectangle2.Bottom) - top;
return new Rectangle(left, top, width, height);
}
return Empty;
}
public Rectangle GetIntersection(Rectangle rectangle)
{
return GetIntersection(this, rectangle);
}
public bool IntersectsWith(Rectangle rectangle)
{
return RectanglesIntersect(this, rectangle);
}
public Rectangle NormalizeWidth()
{
if (Width >= 0)
return this;
Rectangle result = new Rectangle(Left + Width, Top, -Width, Height);
return result;
}
public Rectangle NormalizeHeight()
{
if (Height >= 0)
return this;
Rectangle result = new Rectangle(Left, Top + Height, Width, -Height);
return result;
}
public Rectangle Normalize()
{
Rectangle result = NormalizeWidth().NormalizeHeight();
return result;
}
}
I've been trying to resolve a error for the last day or so and can't seem to work it through.
It's the kind of error that the fix is probably very easy :S
I tried to search for similar questions but the fixes don't apply.
main.c
int main(int argc, char *argv[]){
int width, height;
std::vector<Obj*> world;
world.push_back(new Sphere(Vec(0, 0, -22), 2, Vec(0.2, 0.2, 0.2), true));
(...)
return 0;
}
The error is found when I try to create a Sphere.
Relevant classes
Obj.h
class Obj
{
public:
Vec color;
bool culling;
virtual bool intersect(const Vec &ray_orig, Vec &ray_dir, float *t0 = NULL, float *t1 = NULL) = 0;
};
Sphere.h
class Sphere: public Obj
{
public:
Vec center;
float radius, radius2;
Sphere(Vec center, float radius, Vec color, bool culling);
bool intersect(const Vec &ray_orig, Vec &ray_dir, float *t0 = NULL, float *t1 = NULL);
};
Sphere.c
Sphere::Sphere(Vec center, float radius, Vec color, bool culling){
this->center = center;
this->radius = radius;
this->color = color;
this->culling = culling;
}
bool Sphere::intersect(const Vec &ray_orig, Vec &ray_dir, float *t0 = NULL, float *t1 = NULL) {...}
These second error appears when I do this->color = color;. Not sure if they are related.
Vec is a simple struct with 3 variables.
If you need more information I'll add as soon as possible.
Thank you in advance.
Jose
EDIT
Sorry for the delay.
intersect(...) is the only function in the obj class. Is there anyway to maintain the abstraction since there are several objects(sphere,box,...).
As requested here goes the definition of vec.h
vec.h
struct Vec {
float x, y, z;
Vec() {x = 0, y = 0, z = 0;}
Vec(float val) {x = val, y = val, z = val;}
Vec(float x_val,float y_val,float z_val) {x = x_val, y = y_val, z = z_val;}
Vec(const Vec& copy) : x(copy.x), y(copy.y), z(copy.z) { }
Vec operator+ (const Vec& p) const {
return Vec(x + p.x, y + p.y, z + p.z);
}
Vec operator- (const Vec& p) const {
return Vec(x - p.x, y - p.y, z - p.z);
}
Vec& operator += (const Vec& p) {
x += p.x; y += p.y; z += p.z;
return *this;
}
Vec& operator -= (const Vec& p) {
x -= p.x; y -= p.y; z -= p.z;
return *this;
}
Vec operator* (const float f) const {
return Vec(f * x, f * y, f * z);
}
Vec& operator*= (const float f) {
x *= f; y *= f; z *= f;
return *this;
}
Vec operator/ (const float f) const {
float inv = 1.f / f;
return Vec(inv * x, inv * y, inv * z);
}
Vec& operator/= (const float f) {
float inv = 1.f / f;
x *= inv; y *= inv; z *= inv;
return *this;
}
Vec& operator= (const Vec& p) {
x = p.x; y = p.y; z = p.z;
return *this;
}
bool operator== (const Vec& p) {
if(x == p.x && y == p.y && z == p.z)
return true;
return false;
}
float length_squared() const {
return x*x + y*y + z*z;
}
float length() const {
return sqrt(length_squared());
}
Vec norm() const {
float nor = x * x + y * y + z * z;
if (nor > 0) {
float invNor = 1 / sqrt(nor);
(float)x *= invNor, (float)y *= invNor, (float)z *= invNor;
}
return *this;
}
Vec cross(const Vec&b) {
return Vec(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);
}
float dot(const Vec& v) {
return x * v.x + y * v.y + z * v.z;
}
};
It seems the problem was indeed in the vec file.
Can't find a reasoning about the fix, but changing the Vec struct to a class fixed all the problems.
Thanks for the help.