Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm trying to add rotation functions to my class, to rotate around the X, Y, Z - axis, but the output is not exactly what i expected
I made sure that my formulas are correct, they seem to be correct, but i don't know. i took them from this : Rotating a Vector in 3D Space
#include <iostream>
using namespace std;
#include <math.h>
// Vector class, to handle all the vector operations for us
// Thanks to : https://stackoverflow.com/questions/14607640/rotating-a-vector-in-3d-space
class cVector
{
public:
float x;
float y;
float z;
// Constructor
cVector();
cVector(float x1, float y1, float z1);
// returns the vector's magnitude
float Magnitude();
// Normalize ( change length to 1, while keeping the same direction)
void Normalize();
// Rotate around the Axis
void RotateX(float angle);
void RotateY(float angle);
void RotateZ(float angle);
// TODO : Add operators for Addition & Substraction
// Addition
cVector operator+(cVector const& v1) const
{
return cVector(x + v1.x,
y + v1.y,
z + v1.z);
}
void operator+=(cVector const& v1)
{
x += v1.x;
y += v1.y;
z += v1.z;
}
// Substraction
cVector operator-(cVector const& v1) const
{
return cVector(x - v1.x,
y - v1.y,
z - v1.z);
}
void operator-=(cVector const& v1)
{
x -= v1.x;
y -= v1.y;
z -= v1.z;
}
// Multiplication
void operator*=(const float scalar)
{
x *= scalar;
y *= scalar;
z *= scalar;
}
cVector operator*(const float scalar) const
{
return cVector(x * scalar,
y * scalar,
z * scalar);
}
// Division
void operator/=(const float scalar)
{
x /= scalar;
y /= scalar;
z /= scalar;
}
cVector operator/(const float scalar) const
{
return cVector(x / scalar,
y / scalar,
z / scalar);
}
};
// Constructor
cVector::cVector()
{
}
cVector::cVector(float x1, float y1, float z1)
{
x = x1;
y = y1;
z = z1;
}
// returns the vector's magnitude
float cVector::Magnitude()
{
return sqrt((x * x) + (y * y) + (z * z));
}
// Normalize ( change length to 1, while keeping the same direction)
void cVector::Normalize()
{
float flMagnitude = Magnitude();
// We devide the coordinates by the magnitude
x /= flMagnitude;
y /= flMagnitude;
z /= flMagnitude;
}
// Rotate around the Axis
void cVector::RotateX(float angle)
{
y = y * cos(angle) - z * sin(angle);
z = y * sin(angle) + z * cos(angle);
}
void cVector::RotateY(float angle)
{
x = (x * cos(angle)) + (z * sin(angle));
z = (-x * sin(angle)) + (z * cos(angle));
}
void cVector::RotateZ(float angle)
{
x = x * cos(angle) - y * sin(angle);
y = x * sin(angle) + y * cos(angle);
}
void PrintVector(cVector vec)
{
cout << "X : " << vec.x << " Y : " << vec.y << " Z : " << vec.z << endl;
}
// TODO : Add operators for Addition & Substraction
int main()
{
cout << "Hello world!" << endl;
cVector vec(10, 0, 0);
vec.RotateZ(1.57f);
PrintVector(vec);
cin.get();
return 0;
}
I expect the method to keep the same magnitude of the vector, and return ( 0, 10, 0) since i'm rotating by pi/2 , but that's not what i'm getting. apparently if i rotate by pi, i get a good result, but other than that, it doesn't work.
First in your Rotation for example in RotateZ you should save the x in some temporary because if you modify it & then try to use it for the y it's obviously gonna cause you an error, ie you should do something like this
void cVector::RotateZ(float angle)
{
float temp = x;
x = x * cos(angle) - y * sin(angle);
y = temp * sin(angle) + y * cos(angle);
}
Second the value of pi you are given is way too over-rounded so the values are false
you can do something like for you pi value
const float Pi = 3.1415926535;
Related
I tried to write a program where a vector is calculated that bisects the angle between two lines that share one common point.
For that I've come up with some code (Since this it not the only thing I'm trying to do the code is a bit longer but I've boiled down the problem to this snipped.):
#include <iostream>
#include <cmath>
// A 2D Vector class
class PVector {
public: PVector() = default;
public: PVector(double _x, double _y) : x(_x), y(_y) {};
public: double x, y;
public: PVector set(double _x, double _y) {
x = _x, y = _y;
return *this;
};
public: double getMag() const {
return sqrt(x * x + y * y);
};
public: PVector setMag(double mag) {
mag *= getMag();
return (mag == 0) ? set(0, 0) : set(x / mag, y / mag);
};
public: PVector &operator+=(const PVector &rhs) {
x += rhs.x, y += rhs.y;
return *this;
};
public: PVector operator+(const PVector &rhs) {
return PVector(*this) += rhs;
};
public: PVector &operator-=(const PVector &rhs) {
x -= rhs.x, y -= rhs.y;
return *this;
};
public: PVector operator-(const PVector &rhs) {
return PVector(*this) -= rhs;
};
public: PVector &operator*=(const double &m) {
x *= m, y *= m;
return *this;
};
};
// A function to convert a 2D vector into an angle
double vector2Angle(double x, double y) {
if (x == 0)
return (y >= 0) ? 0 : 180;
else if (y == 0)
return (x > 0) ? 90 : 270;
double angle = atan(y / x);
// bottom left (90 - 180)
if (x < 0 && y < 0)
// angle is positive (180 location)
angle = M_PI / 2;
// top left (0 - 90)
else if (x < 0)
// angle is negative (90 positive) + (0 location)
angle += M_PI / 2;
// bottom right (180 - 270)
else if (y < 0)
// angle is negative (90 positive) + (180 location)
angle += 1.5 * M_PI;
// top right (270 - 360)
else {
angle += 1.5 * M_PI;
// angle is positive
}
return angle;
};
double vector2Angle(PVector v) {
return vector2Angle(v.x, v.y);
};
int main()
{
PVector p0 = PVector(90, 90);
PVector p1 = PVector(10, 90);
PVector p2 = PVector(10, 10);
// The sum of two unit vectors must return a vector that bisects the angle between the two vectors.
std::cout << "Expected: " << (vector2Angle(p1 - p0) + vector2Angle(p1 - p2)) / 2 << std::endl;
std::cout << "Got: " << vector2Angle((p1 - p0).setMag(1) + (p1 - p2).setMag(1)) << std::endl;
return 0;
}
From intuition the output should be either 135° or 315° but the program delivers:
Expected: 135
Got: 0.785398
The first strange thing about this output is that one is in degrees although vector2Angle returns a radian value. Even stranger is the fact that both results are in different units. And at last I'm wondering where my mistake in the calculation is because 0.785... radian are about 45° and not 135°.
I'm trying to make a quadcopter drone. I'm using an mpu6050 to get acceleration & angular speed and then convert them to Roll / pitch / yaw
With the acceleration, i'm also trying to get the speed & position by integration. However , i need them to be in absolute coordinate system, because the mpu6050 gives you the values in its relative coordinates system.
the origin of the new coordinate system is the starting position of the drone, and the direction is "where the drone is looking" , we assume Yaw = 0 at the beginning, and we get yaw using the gyrometer's data.
I tried to rotate the vectors using the Roll / pitch values, but that doesn't seem to work very well.
I tried with this being the gravity vector for example : (-2, -2, -1)
If i convert it to the absolute coordinate system, i should get : (0,0, 3)
#include <iostream>
using namespace std;
#include <math.h>
// Vector class, to handle all the vector operations for us
// Thanks to : https://stackoverflow.com/questions/14607640/rotating-a-vector-in-3d-space
class cVector
{
public:
float x;
float y;
float z;
// Constructor
cVector();
cVector(float x1, float y1, float z1);
// returns the vector's magnitude
float Magnitude();
// Normalize ( change length to 1, while keeping the same direction)
void Normalize();
// Rotate around the Axis
void RotateX(float angle);
void RotateY(float angle);
void RotateZ(float angle);
// TODO : Add operators for Addition & Substraction
// Addition
cVector operator+(cVector const& v1) const
{
return cVector(x + v1.x,
y + v1.y,
z + v1.z);
}
void operator+=(cVector const& v1)
{
x += v1.x;
y += v1.y;
z += v1.z;
}
// Substraction
cVector operator-(cVector const& v1) const
{
return cVector(x - v1.x,
y - v1.y,
z - v1.z);
}
void operator-=(cVector const& v1)
{
x -= v1.x;
y -= v1.y;
z -= v1.z;
}
// Multiplication
void operator*=(const float scalar)
{
x *= scalar;
y *= scalar;
z *= scalar;
}
cVector operator*(const float scalar) const
{
return cVector(x * scalar,
y * scalar,
z * scalar);
}
// Division
void operator/=(const float scalar)
{
x /= scalar;
y /= scalar;
z /= scalar;
}
cVector operator/(const float scalar) const
{
return cVector(x / scalar,
y / scalar,
z / scalar);
}
};
// Constructor
cVector::cVector()
{
}
cVector::cVector(float x1, float y1, float z1)
{
x = x1;
y = y1;
z = z1;
}
// returns the vector's magnitude
float cVector::Magnitude()
{
return sqrt((x * x) + (y * y) + (z * z));
}
// Normalize ( change length to 1, while keeping the same direction)
void cVector::Normalize()
{
float flMagnitude = Magnitude();
// We devide the coordinates by the magnitude
x /= flMagnitude;
y /= flMagnitude;
z /= flMagnitude;
}
// Rotate around the Axis
void cVector::RotateX(float angle)
{
// Calculate the sinus and cosinus
float flCos = static_cast<float>(cos(angle));
float flSin = static_cast<float>(sin(angle));
// We save the current values temporarily
float _y = y;
float _z = z;
y = _y * flCos - _z * flSin;
z = _y * flSin + _z * flCos;
}
void cVector::RotateY(float angle)
{
// Calculate the sinus and cosinus
float flCos = static_cast<float>(cos(angle));
float flSin = static_cast<float>(sin(angle));
// We save the current values temporarily
float _x = x;
float _z = z;
x = _x * flCos + _z * flSin;
z = - _x * flSin + _z * flCos;
}
void cVector::RotateZ(float angle)
{
// Calculate the sinus and cosinus
float flCos = static_cast<float>(cos(angle));
float flSin = static_cast<float>(sin(angle));
// We save the current values temporarily
float _x = x;
float _y = y;
x = _x * flCos - _y * flSin;
y = _x * flSin + _y * flCos;
}
void PrintVector(cVector vec)
{
cout << "X : " << vec.x << " Y : " << vec.y << " Z : " << vec.z << endl;
}
// TODO : Add operators for Addition & Substraction
int main()
{
cVector vec(-2, -2, -1);
// Calculate pitch / roll
float pitch = static_cast<float>(atan2( vec.y , sqrt( pow(vec.x,2) + pow(vec.z,2) ) ));
float roll = static_cast<float>(atan2(-1 * vec.x , sqrt( pow(vec.y,2) + pow(vec.z,2) ) ));
// vec.RotateY(1.570796f);
vec.RotateX(roll);
vec.RotateY(pitch);
PrintVector(vec);
cin.get();
return 0;
}
expected result ( 0, 0, 3 )
Actual results : (-0.104919 , -0.824045, -2.8827 )
I am trying to write some position/orientation methods for my small & simple 3d-space calculation library. But I'm stuck on the following problem.
I store 3d line as start and end points. However it should be possible to store it as start point and line's length + orientation as well (it's just a good example to test if orientation calculations works).
By orientation I mean rotation from the initial "0" orientation (which places the end at start + [0,legth,0]). So I first rotate the [0,length,0] by orientation and then add start to it to get end point.
The problem is, my orientation calculations fails somewhere. After calculating the orientation I get different ending point.
I use left-handed coordinate system with Y-axis pointing up, but I don't think it's important here.
Here's the code (I've tried to name the methods in the way you can check if the steps are ok; here's the full source code if you want to compile it yourself):
Point3D start = { 5.0f, 4.0f, 7.0f };
Point3D end = { 15.0f, 6.0f, 14.0f };
Point3D direction = (end - start);
std::wcout << L"Direction: "; direction.output();
float angle = Point3D(0.0f, 1.0f, 0.0f).getAngleToAnotherVectorInRadians(direction);
Point3D axis = direction.getCrossProduct(Point3D(0.0f, 1.0f, 0.0f)).getNormalized();
Quaternion o = Quaternion(AxisAngle(axis, angle));
std::wcout << L"\nAxisAngle: "; AxisAngle(axis, angle).output();
std::wcout << L"\nOrientation: "; o.output();
//test - end2 should be equal to end
Point3D offset(0.0f, (end - start).getLengthAsVector(), 0.0f);
offset = o.rotatePoint(offset);
std::wcout << L"\nOffset: "; offset.output();
Point3D end2 = start + offset;
std::wcout << L"\nEnd2: "; end2.output();
The code produces such output (without a comments, of course):
Direction: {10, 2, 7} //looks ok
AxisAngle: {{-0.573462, 0, 0.819232}, 1.40839}
Orientation: {-0.371272, 0, 0.530388, 0.762132}
Offset: {-10, 2, -7} //Almost! It should be {10, 2, 7}
End2: {-5, 6, -9.53674e-07} //Wrong! It should be { 15, 6, 14 }
In case that all steps are ok but there are some mistakes in methods' implementations I post here the important code for classes (so you can reproduce the problem): Point3D, AxisAngle, Quaternion.
I highly believe that problem(s) lay(s) in my main steps or in AxisAngle calculations. I think that AxisAngle to Quaternion transformation is ok (but I pass the wrong AxisAngle to Quaternion constructor).
The Point3D:
struct Point3D {
protected:
float x, y, z;
public:
Point3D() : x(0.0f), y(0.0f), z(0.0f) {}
Point3D(float x, float y, float z) : x(x), y(y), z(z) {}
void output() { std::wcout << L"{" << x << L", " << y << L", " << z << L"}"; }
Point3D operator-(const Point3D &point) const {
Point3D temp;
temp.setX(getX() - point.getX());
temp.setY(getY() - point.getY());
temp.setZ(getZ() - point.getZ());
return temp;
}
Point3D operator+ (const Point3D &value) const {
Point3D temp;
temp.setX(getX() + value.getX());
temp.setY(getY() + value.getY());
temp.setZ(getZ() + value.getZ());
return temp;
}
inline float getX() const { return x; } inline float getY() const { return y; } inline float getZ() const { return z; }
inline void setX(float x) { this->x = x; } inline void setY(float y) { this->y = y; } inline void setZ(float z) { this->z = z; }
inline float getLengthAsVector() const {
return sqrt(x*x + y*y + z*z);
}
inline Point3D getCrossProduct(const Point3D &anotherVector) const {
//based on: http://www.sciencehq.com/physics/vector-product-multiplying-vectors.html
return Point3D(
y * anotherVector.z - anotherVector.y * z,
z * anotherVector.x - anotherVector.z * x,
x * anotherVector.y - anotherVector.x * y
);
}
inline float getDotProduct(const Point3D &anotherVector) const {
//based on: https://www.ltcconline.net/greenl/courses/107/Vectors/DOTCROS.HTM
return x * anotherVector.x + y * anotherVector.y + z * anotherVector.z;
}
inline float getAngleToAnotherVectorInRadians(const Point3D &anotherVector) const {
//based on: http://math.stackexchange.com/questions/974178/how-to-calculate-the-angle-between-2-vectors-in-3d-space-given-a-preset-function
return acos(getDotProduct(anotherVector) / (getLengthAsVector() * anotherVector.getLengthAsVector()));
}
Point3D getNormalized() const {
float length = std::abs(sqrt(x*x + y*y + z*z));
Point3D result(x / length, y / length, z / length);
return result;
}
};
The AxisAngle:
class AxisAngle {
protected:
Point3D axis;
float angleInRadians;
public:
AxisAngle(const AxisAngle &other) { axis = other.axis; angleInRadians = other.angleInRadians; }
AxisAngle::AxisAngle(float x, float y, float z, float angleInRadians) {
this->axis = Point3D(x, y, z);
this->angleInRadians = angleInRadians;
}
AxisAngle::AxisAngle(const Point3D &axis, float angleInRadians) {
this->axis = axis;
this->angleInRadians = angleInRadians;
}
Point3D getAxis() const { return axis; }
float getAngleInRadians() const { return angleInRadians; }
void output() { std::wcout << L"{"; axis.output(); std::wcout << L", " << angleInRadians << L"}"; }
};
And last but not least, Quaternion:
class Quaternion {
protected:
float x; float y; float z; float w;
public:
Quaternion() { x = 0.0f; y = 0.0f; z = 0.0f; w = 1.0f; }
Quaternion(const Quaternion &other) { x = other.x; y = other.y; z = other.z; w = other.w; }
Quaternion(float x, float y, float z, float w) { this->x = x; this->y = y; this->z = z; this->w = w; }
Quaternion(const AxisAngle &axisAngle) {
Point3D axis = axisAngle.getAxis();
float angleInRadians = axisAngle.getAngleInRadians();
x = sin(angleInRadians / 2) * axis.getX();
y = sin(angleInRadians / 2) * axis.getY();
z = sin(angleInRadians / 2) * axis.getZ();
w = cos(angleInRadians / 2);
normalizeIt();
}
float getLength() const {
return sqrt(x*x + y*y + z*z + w*w);
}
void normalizeIt() {
float length = getLength();
x = x / length;
y = y / length;
z = z / length;
w = w / length;
}
Quaternion getConjugated() const {
return Quaternion(-x, -y, -z, w);
}
Quaternion multiply(Quaternion by) {
//"R" for result
float wR = w * by.getW() - x * by.getX() - y * by.getY() - z * by.getZ();
float xR = x * by.getW() + w * by.getX() + y * by.getZ() - z * by.getY();
float yR = y * by.getW() + w * by.getY() + z * by.getX() - x * by.getZ();
float zR = z * by.getW() + w * by.getZ() + x * by.getY() - y * by.getX();
return Quaternion(xR, yR, zR, wR);
}
//rotate Point3D p around [0,0,0] with this Quaternion
Point3D rotatePoint(Point3D p) const {
Quaternion temp = multiply(p).multiply(getConjugated());
return Point3D(temp.getX(), temp.getY(), temp.getZ());
//G: P' = Q(P-G)Q' + G <- to rotate P around G with Quaternion
}
Quaternion multiply(Point3D r) const {
float wR = -x * r.getX() - y * r.getY() - z * r.getZ();
float xR = w * r.getX() + y * r.getZ() - z * r.getY();
float yR = w * r.getY() + z * r.getX() - x * r.getZ();
float zR = w * r.getZ() + x * r.getY() - y * r.getX();
return Quaternion(xR, yR, zR, wR);
}
inline float getX() const { return x; } inline void setX(float x) { this->x = x; }
inline float getY() const { return y; } inline void setY(float y) { this->y = y; }
inline float getZ() const { return z; } inline void setZ(float z) { this->z = z; }
inline float getW() const { return w; } inline void setW(float w) { this->w = w; }
void output() { std::wcout << L"{" << x << L", " << y << L", " << z << L", " << w << L"}"; }
};
In case somebody would ask: I do want to use quaternions. They may not look 100% needed here, but storing 3d object's orientation as quaternion has many benefits in more complex computations (and most game engines / 3d software use it as well "under the mask").
Your axis has the wrong orientation. It should be:
Point3D axis = Point3D(0.0f, 1.0f, 0.0f).getCrossProduct(direction).getNormalized();
Use the two left-hand rules to figure out the correct order.
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 am programming in OpenGL and C++. I know 2 points on 1 line (a diagonal line) and wish to rotate an object around that diagonal line. How can I go about doing this? I know how to use glrotatef to rotate it around the x, y or z axis but am not sure about this.
The x, y and z parameters to glRotate can specify any arbitrary axis, not just the x, y and z axes. To find an axis passing through your line, just subtract the end-points of the line to get an axis vector: if the two points are (x1, y1, z1) and (x2, y2, z2), the axis you need is (x2-x1, y2-y1, z2-z1).
Edit: As #chris_l pointed out, this works only if the line passes through the origin. If not, first apply a translation of (-x1, -y1, -z1) so that the line passes through the origin, then apply the above rotation, and translate it back by (x1, y1, z1).
Hey, how about doing some quaternions / vector maths? =) I've done that using small "patch" on my Vector class:
double NumBounds(double value)
{
if (fabs(value) < (1 / 1000000.0f))
return 0; else
return value;
}
class Vector
{
private:
double x, y, z;
public:
Vector(const Vector &v)
{
x = NumBounds(v.x); y = NumBounds(v.y); z = NumBounds(v.z);
}
Vector(double _x, double _y, double _z)
{
x = NumBounds(_x); y = NumBounds(_y); z = NumBounds(_z);
}
Vector Normalize()
{
if (Length() != 0)
return Vector(x / Length(), y / Length(), z / Length()); else
return *this;
}
double operator[](unsigned int index) const
{
if (index == 0)
return NumBounds(x); else
if (index == 1)
return NumBounds(y); else
if (index == 2)
return NumBounds(z); else
return 0;
}
void operator=(const Vector &v)
{
x = NumBounds(v.x); y = NumBounds(v.y); z = NumBounds(v.z);
}
Vector operator+(const Vector &v)
{
return Vector(x + v.x, y + v.y, z + v.z);
}
Vector operator-(const Vector &v)
{
return Vector(x - v.x, y - v.y, z - v.z);
}
double operator*(const Vector &v)
{
return NumBounds((x * v.x) + (y * v.y) + (z * v.z));
}
Vector operator*(double s)
{
return Vector(x * s, y * s, z * s);
}
Vector DotProduct(const Vector &v)
{
double k1 = (y * v.z) - (z * v.y);
double k2 = (z * v.x) - (x * v.z);
double k3 = (x * v.y) - (y * v.x);
return Vector(NumBounds(k1), NumBounds(k2), NumBounds(k3));
}
Vector Rotate(Vector &axis, double Angle)
{
Vector v = *this;
return ((v - axis * (axis * v)) * cos(angle)) + (axis.DotProduct(v) * sin(angle)) + (axis * (axis * v));
}
};
Using this class you can easily rotate any vector around any other one:
Vector a(1.0f, 0.0f, 0.0f), b(0.0f, 1.0f, 0.0f), c(0.0f, 0.0f, 0.0f);
c = a.Rotate(b, M_PI / 2.0f); // rotate vector a around vector b for 90 degrees (PI / 2 radians): should be Vector(0, 0, 1);
glrotate does the rotation about an axis. One method is to perform transformations which align rotation axis with one of coordinate axis, perform the rotation, then reverse the first step. If you need speed you can combine the operations into a special transformation matrix and apply them in one step. There's a description here.