I'm trying to make a Vec class to represent a set of 3 doubles, x, y, z, respectively. What I would like to do is make it so that I can multiply a scalar times the vector and have it multiply each component.
I have been able to get it to work when I mutliply a vector by a scalar, but not when I do the reverse. For example, the following works:
Vec a = Vec(1.0, 1.0, 1.0);
Vec b = a * 2.0;
But, whenever I try to multiply a scalar by a vector, it doesn't work. Ideally the command would look like this:
Vec a = Vec(1.0, 1.0, 1.0);
Vec b = 2.0 * a;
Here is the code I've done so far:
#include "Vec.h"
#include <limits>
#include <cmath>
#include "constants.h"
#include <iostream>
#include <string>
double Vec::angle( const Vec & vec) {
return acos((this->dot(vec))/(this->mag() * mag()));
}
double Vec::angle_d(const Vec & vec) {
return (angle(vec) * _PI / 180.0);
}
double Vec::angle_r(const Vec & vec) {
return this->angle(vec);
}
Vec Vec::cross( const Vec& vec) {
return Vec( (y * vec.z - z * vec.y),
(z * vec.x - x * vec.z),
(x * vec.y - y * vec.x));
}
double Vec::dot( const Vec & vec) {
return (x * vec.x + y * vec.y + z * vec.z);
}
double Vec::mag() {
return std::sqrt(x*x + y*y + z*z);
}
Vec Vec::operator=(const Vec& rhs) {
return Vec(rhs);
}
Vec Vec::operator*(const Vec& rhs) {
return Vec( x * rhs.x, y * rhs.y, z * rhs.z);
}
Vec Vec::operator*(const double rhs) {
return Vec(rhs * x, rhs * y, rhs * z);
}
Vec::Vec() :
x(std::numeric_limits<double>::signaling_NaN()),
y(std::numeric_limits<double>::signaling_NaN()),
z(std::numeric_limits<double>::signaling_NaN()) { }
Vec::Vec( double c) :
x(c), y(c), z(c) {}
Vec::Vec(const Vec & vec) :
x(vec.x), y(vec.y), z(vec.z) { }
Vec::Vec(double a, double b, double c)
: x(a), y(b), z(c) { }
You need a global operator that takes two arguments: a double and then a Vec, and it can be easily implemented by calling the operator you already have listed
inline Vec operator*(double s, const Vec& v) {
return v * s;
}
Try to create new global operator:
Vec operator*(int i, const Vec& rhs) {
return Vec(i * rhs.x, i * rhs.y, i * rhs.z);
}
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 need to multiply a const Vector by an int, but I have to declare the overload as a non-member function and not as a method or it will not compile; how would I write the overload as a method?
namespace N
{
class Vector {
public:
double x, y, z;
Vector( );
Vector(double x, double y = 0, double z = 0);
Vector operator*(double k);
//friend Vector operator*(const Vector u, double k);
};
}
namespace N
{
Vector::Vector( )
{
x = 0;
y = 0;
z = 0;
}
// Creates a vector with initial Cartesian components.
//
Vector::Vector(double x, double y, double z) :
x(x),
y(y),
z(z)
{
}
// Allows multiplying a vector by a scalar.
//
Vector Vector::operator*(double k)
{
Vector scaled;
scaled.x = x * k;
scaled.y = y * k;
scaled.z = z * k;
return scaled;
}
// Allows multiplying a vector by a scalar.
//
/*Vector operator*(const Vector u, double k)
{
return Vector(u.x * k, u.y * k, u.z * k);
}*/
}
const N::Vector A(3, 4);
const N::Vector B(4, 3);
int main( )
{
N::Vector resulting = A * 3;
return 0;
}
As a member, simply change the code to
Vector operator*(double k) const;
and in the definition
Vector Vector::operator*(double k) const ...
As top-level:
friend Vector operator*(const Vector& u, double k);
and
Vector operator*(const Vector& u, double k)
{
return Vector(u.x * k, u.y * k, u.z * k);
}
I'm trying to write a class for the UnitVector, having already written the one for a generic Vector. The UnitVector class diverges from the Vector class only by the fact that the abs variable is set to 1.0f. I'd like to know what the best approach to the problem would be, whether it's better to make another class, UnitVector, that inherits the Vector class (my current idea, that's giving me problems) or to just write a method in the Vector class
Here's my code for the class Vector:
Vector.h
class Vector
{
public:
Vector();
Vector(float x, float y);
void set_by_angle(float abs, float angle);
void set(float x, float y);
void rotate(float angle);
void scale(float scale_factor);
void translate(float x, float y);
void translate(Vector v);
float get_abs();
float get_angle();
static Vector create_by_angle(float abs, float angle);
static Vector create(float x, float y);
static Vector create_from_vectors(Vector v1, Vector v2, float abs);
static float get_distance(Vector v1, Vector v2);
static float get_angle(float x, float y);
static float get_angle(Vector v);
void to_string();
Vector operator=(const Vector &v);
bool operator==(const Vector &v);
bool operator!=(const Vector &v);
Vector operator+=(const Vector &v);
friend Vector operator+(const Vector &v1, const Vector &v2);
friend Vector operator-(const Vector &v1, const Vector &v2);
float x;
float y;
private:
float abs;
float angle;
};
Vector.cpp
#define _USE_MATH_DEFINES
#include <math.h>
#include <iostream>
#include <string>
#include "vector.h"
using namespace std;
Vector::Vector() : Vector(0, 0) {}
Vector::Vector(float x, float y)
{
set(x, y);
}
void Vector::set_by_angle(float abs, float angle)
{
this->abs = abs;
this->angle = angle;
x = abs * cos(angle);
y = abs * sin(angle);
}
void Vector::set(float x, float y)
{
this->x = x;
this->y = y;
abs = get_abs();
angle = get_angle();
}
void Vector::rotate(float angle)
{
set_by_angle(this->abs, this->angle + angle);
}
void Vector::scale(float scale_factor)
{
set(x * scale_factor, y * scale_factor);
}
void Vector::translate(float x, float y)
{
set(this->x + x, this->y + y);
}
void Vector::translate(Vector v)
{
translate(v.x, v.y);
}
float Vector::get_abs()
{
return sqrt(pow(x, 2) + pow(y, 2));
}
float Vector::get_angle()
{
return get_angle(x, y);
}
Vector Vector::create_by_angle(float abs, float angle)
{
Vector v;
v.set_by_angle(abs, angle);
return v;
}
Vector Vector::create(float x, float y)
{
Vector v;
v.set(x, y);
return v;
}
float Vector::get_distance(Vector v1, Vector v2)
{
return sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2));
}
Vector Vector::create_from_vectors(Vector v1, Vector v2, float abs)
{
float x = v2.x - v1.x;
float y = v2.y - v1.y;
Vector v;
v.set_by_angle(abs, Vector(x, y).get_angle());
return v;
}
float Vector::get_angle(float x, float y)
{
float tan = 0.0f;
float angle = 0.0f;
if (x != 0)
{
tan = y / x;
angle = atan(tan);
// this setting applies to the graphic reference system
if (x > 0 && y < 0) angle = 2 * M_PI + angle;
if (x < 0 && y > 0) angle += M_PI;
if (x < 0 && y < 0) angle += M_PI;
}
if (x == 0)
{
if (y > 0) angle = M_PI_2;
if (y < 0) angle = 3 * M_PI_2;
}
if (y == 0)
{
if (x > 0) angle = 0.0f;
if (x < 0) angle = M_PI;
}
return angle;
}
float Vector::get_angle(Vector v)
{
return get_angle(v.x, v.y);
}
void Vector::to_string()
{
cout << "x: " + std::to_string(x) + " y: " + std::to_string(y) << endl;
}
Vector operator+(const Vector &v1, const Vector &v2)
{
Vector tmp;
tmp.set(v1.x + v2.x, v1.y + v2.y);
return tmp;
}
Vector operator-(const Vector &v1, const Vector &v2)
{
return v1 + Vector(-v2.x, -v2.y);
}
Vector Vector::operator+=(const Vector &v)
{
set(x + v.x, y + v.y);
return *this;
}
Vector Vector::operator=(const Vector &v)
{
set(v.x, v.y);
return *this;
}
bool Vector::operator==(const Vector &v)
{
return
(
(x == v.x)
&&
(y == v.y)
);
}
bool Vector::operator!=(const Vector &v)
{
return !(*this == v);
}
Thanks in advance!
Just add the following two methods:
void normalize()
{
float scalar = 1.0 / this->get_abs();
this->x *= scalar;
this->y *= scalar;
}
And:
static Vector get_unit(const Vector &v)
{
float scalar = 1.0 / v.get_abs();
return Vector(v.x * scalar, v.y * scalar);
}
I override the addition operation, so that I can add two vectors of my struct Vec3
// addition
Vec3 operator+(Vec3<T> &other) {
return Vec3(this->x + other.x, this->y + other.y, this->z + other.z);
}
// product with one scalar
Vec3 operator*(float scalar) {
return Vec3(this->x * scalar, this->y * scalar, this->z * scalar);
}
The Vec3 has just three attributes from type T.
When using it T is a float, and I execute this code:
vec temp = vecOne * skalarOne + vecTwo * scalarTwo;
I get this error:
Binary operator '+' can't be applied to the expressions of type
'pray::Vec3' and 'pray::Vec3'
I don't get this error if calculationg the multiplication first and save the result in a vector and then doing the vector addition.
Anyone any idea? Thanks!
You need to change the function signatures to
Vec3 operator+(const Vec3<T> &other) const
&c., otherwise an anonymous temporary cannot bind to it.
You should return a reference to the vec3 like this:
// addition
Vec3 operator+(const Vec3& other) {
return { x + other.x, y + other.y, z + other.z };
}
// product with one scalar
Vec3 operator*(float scalar) {
return { x * scalar, y * scalar, z * scalar };
}
Edit: Here is my complete runable solution, if the fix above wont work for you.
template <typename T>
class Vec3 {
public:
Vec3(T x, T y, T z) : x(x), y(y), z(z) {}
T x;
T y;
T z;
// addition
Vec3 operator+(const Vec3<T>& other) {
return { x + other.x, y + other.y, z + other.z };
}
// product with one scalar
Vec3 operator*(float scalar) {
return { x * scalar, y * scalar, z * scalar };
}
};
int main() {
Vec3<float> a(2, 2, 2);
Vec3<float> b(1, 2, 3);
float num = 3;
Vec3<float> c = a + b;
Vec3<float> d = a * num;
Vec3<float> e = a * num + b * num;
}
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.