We have found that HP's printer drivers fail to handle PlgBlt()s properly for many of their printers.
Our intention is to handle any orthogonal rotations ourselves, and only have the printer handle scale and translation (which it seems to handle correctly).
I have a 2D matrix available to me at the point in code where I am about to "draw" the bitmap to the printer's DC.
I am weak as hell in math, and I understand just enough about matrix math to use them to transform 2D or 3D coordinates. But the underlying math is opaque to me.
So, what I need is to detect if a given 2D matrix is orthogonal in its transformation (the rotation aspect anyway). I suppose another way to ask this question would be: How do I get the rotation vector back out of the 2D matrix? If I knew the angle of rotation in radians or degrees, I could say whether its orthogonal or not (0,90,180,270).
Presumably, the code is generic on this subject, but below is the basics of the code we use, in case that helps:
typedef double ThreeByThreeMatrix[3][3]; // 3x3 for an X, Y coordinate transformation matrix
Then there's a wrapper for that which handles most obvious operations:
class Simple2DTransform
{
public:
////////////////////////////////////////////////////
// Construction
////////////////////////////////////////////////////
// we always begin life as an identity matrix (you can then apply scale, skew, etc.)
Simple2DTransform()
{
Reset();
}
////////////////////////////////////////////////////
// Operators
////////////////////////////////////////////////////
bool operator == (const Simple2DTransform & rhs) const
{
return memcmp(m_matrix, rhs.m_matrix, sizeof(m_matrix)) == 0;
}
Simple2DTransform & operator *= (const Simple2DTransform & rhs)
{
return *this = GetCrossProduct(rhs);
}
////////////////////////////////////////////////////
// Setup
////////////////////////////////////////////////////
// reset to the identity matrix
Simple2DTransform & Reset()
{
memcpy(m_matrix, GetIdentityMatrix(), sizeof(m_matrix));
return *this;
}
// combine with the specified translation
Simple2DTransform & Translate(double x_shift, double y_shift)
{
Simple2DTransform transform;
translate(x_shift, y_shift, transform.m_matrix);
return *this *= transform;
}
// combine with the specified operations (these are cumulative operations, so rotating twice by 1 degree gives a total of 2 degrees rotation)
Simple2DTransform & Rotate(double radians)
{
Simple2DTransform transform;
rotate(radians, transform.m_matrix);
return *this *= transform;
}
// apply a heterogeneous scale factor
Simple2DTransform & Scale(double x_scale, double y_scale)
{
Simple2DTransform transform;
scale(x_scale, y_scale, transform.m_matrix);
return *this *= transform;
}
// apply a homogeneous scale factor
Simple2DTransform & Scale(double scale)
{
return Scale(scale, scale);
}
// apply a skew
Simple2DTransform & Skew(double skew)
{
Simple2DTransform transform;
skew_y(skew, transform.m_matrix);
return *this *= transform;
}
////////////////////////////////////////////////////
// Queries
////////////////////////////////////////////////////
// return the cross product of this and the given matrix
Simple2DTransform GetCrossProduct(const Simple2DTransform & rhs) const
{
Simple2DTransform result;
GEMM(m_matrix, rhs.m_matrix, result.m_matrix);
return result;
}
// returns the inverse of ourselves
Simple2DTransform GetInverse() const
{
// note: invert mucks with both matrices, so we use a copy of ourselves for it
Simple2DTransform original(*this), inverse;
invert(original.m_matrix, inverse.m_matrix);
return inverse;
}
// derivative values
double GetCoefficient(int i, int j) const
{
return m_matrix[i][j];
}
// return the cross product
double GetDeterminate() const
{
return m_matrix[0][0]*m_matrix[1][1] - m_matrix[0][1]*m_matrix[1][0];
}
// returns the square root of the determinate (this ignores heterogeneous scaling factors)
double GetScale() const
{
return sqrt(abs(GetDeterminate()));
}
// returns true if there is a scale factor
bool IsStretched() const
{
return (abs(abs(m_matrix[0][0]) - abs(m_matrix[1][1])) > 1.0e-7
|| abs(abs(m_matrix[0][1]) - abs(m_matrix[1][0])) > 1.0e-7);
}
// true if we're the identity matrix
bool IsIdentity() const
{
return memcmp(m_matrix, GetIdentityMatrix(), sizeof(m_matrix)) == 0;
}
// returns true if this represents the same transformation as the given subtable
bool IsSubtableEqual(const SUBTABLE * pSubTable) const
{
ASSERT(pSubTable);
if (abs(pSubTable->tran1 - m_matrix[0][0]) > 1.0e-7)
return false;
if (abs(pSubTable->tran2 - m_matrix[1][0]) > 1.0e-7)
return false;
if (abs(pSubTable->tran3 - m_matrix[0][1]) > 1.0e-7)
return false;
if (abs(pSubTable->tran4 - m_matrix[1][1]) > 1.0e-7)
return false;
return true;
}
////////////////////////////////////////////////////
// Application / Execution
////////////////////////////////////////////////////
void Transform(const SimplePoint & point, SimplePoint & newpoint) const
{
newpoint.x = point.x * m_matrix[0][0] + point.y * m_matrix[1][0] + m_matrix[2][0];
newpoint.y = point.x * m_matrix[0][1] + point.y * m_matrix[1][1] + m_matrix[2][1];
}
void Transform(SimplePoint & point) const
{
SimplePoint newpoint;
Transform(point, newpoint);
point = newpoint;
}
void Transform(const SimpleRect & rect, SimpleRect & newrect) const
{
newrect.minX = rect.minX * m_matrix[0][0] + rect.minY * m_matrix[1][0] + m_matrix[2][0];
newrect.minY = rect.minX * m_matrix[0][1] + rect.minY * m_matrix[1][1] + m_matrix[2][1];
newrect.maxX = rect.maxX * m_matrix[0][0] + rect.maxY * m_matrix[1][0] + m_matrix[2][0];
newrect.maxY = rect.maxX * m_matrix[0][1] + rect.maxY * m_matrix[1][1] + m_matrix[2][1];
}
void Transform(SimpleRect & rect) const
{
SimpleRect newrect;
Transform(rect, newrect);
rect = newrect;
}
void Transform(CPoint & point) const
{
SimplePoint newpoint(point);
Transform(newpoint);
point.x = (int)(newpoint.x > 0.0 ? newpoint.x + 0.5 : newpoint.x - 0.5);
point.y = (int)(newpoint.y > 0.0 ? newpoint.y + 0.5 : newpoint.y - 0.5);
}
void Transform(SimplePoint point, CPoint & transformed) const
{
Transform(point);
transformed.x = (int)(point.x > 0.0 ? point.x + 0.5 : point.x - 0.5);
transformed.y = (int)(point.y > 0.0 ? point.y + 0.5 : point.y - 0.5);
}
void Transform(CPoint point, SimplePoint & transformed) const
{
transformed = point;
Transform(transformed);
}
void Transform(double dx, double dy, double & x, double & y) const
{
SimplePoint point(dx, dy);
Transform(point);
x = point.x;
y = point.y;
}
void Transform(double & x, double & y) const
{
SimplePoint point(x, y);
Transform(point);
x = point.x;
y = point.y;
}
SimplePoint GetTransformed(SimplePoint point) const
{
Transform(point);
return point;
}
CPoint GetTransformed(CPoint point) const
{
Transform(point);
return point;
}
SimpleRect GetTransformed(const CRect & rect) const
{
return SimpleRect(GetTransformed(SimplePoint(rect.left, rect.bottom)), GetTransformed(SimplePoint(rect.right, rect.top)));
}
SimpleRect GetTransformed(double x1, double y1, double x2, double y2) const
{
return SimpleRect(GetTransformed(SimplePoint(x1, y1)), GetTransformed(SimplePoint(x2, y2)));
}
double GetTransformedX(double x, double y) const
{
return GetTransformed(SimplePoint(x, y)).x;
}
double GetTransformedY(double x, double y) const
{
return GetTransformed(SimplePoint(x, y)).y;
}
double GetTransformedX(int x, int y) const
{
return GetTransformed(SimplePoint(x, y)).x;
}
double GetTransformedY(int x, int y) const
{
return GetTransformed(SimplePoint(x, y)).y;
}
double GetTransformedX(const SimplePoint & point) const
{
return GetTransformed(point).x;
}
double GetTransformedY(const SimplePoint & point) const
{
return GetTransformed(point).y;
}
int GetTransformedIntX(double x, double y) const
{
CPoint point;
Transform(SimplePoint(x, y), point);
return point.x;
}
int GetTransformedIntY(double x, double y) const
{
CPoint point;
Transform(SimplePoint(x, y), point);
return point.y;
}
int GetTransformedIntX(const SimplePoint & point) const
{
CPoint pt;
Transform(point, pt);
return pt.x;
}
int GetTransformedIntY(const SimplePoint & point) const
{
CPoint pt;
Transform(point, pt);
return pt.y;
}
protected:
////////////////////////////////////////////////////
// Static Class Operations
////////////////////////////////////////////////////
static const ThreeByThreeMatrix & GetIdentityMatrix();
////////////////////////////////////////////////////
// Instance Variables
////////////////////////////////////////////////////
ThreeByThreeMatrix m_matrix;
};
Let A = (0, 0), B = (1, 0). Transform both through the matrix to get A' and B'. Measure the angle of the vector B' - A'. That should give you the angle.
To measure the angle of the vector, you can use atan2 (B'.y - A'.y, B'.x - A'.x)
Related
I am trying to figure out how to find the axis of class Square's axis as shown below? But I've been trying for hours and still did not managed to solve it. Can someone with their high level expertise show me the ropes to do it? Because both center function call and axis function call in main() does call the same x() and y(), hence brought me to a state of confusion. I know the inheritance of square from circle is weird. But it is what my school wants. Note: Main() CANNOT be modified! Thanks!
Output:
Square::axis test failed
8.87627 0.284967
3.82567 0.958537
Tests passed: 50%
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
class Object
{
public:
private:
float d;
public:
Object(float n) : d(n){}
Object(){}
float depth() const
{
return d;
}
struct PointType
{
float x2;
float y2;
PointType( float x1, float y1) :x2(x1),y2(y1){}
PointType(){}
float x()
{
return x2;
}
float y()
{
return y2;
}
PointType center()
{
return *this;
}
};
struct VectorType
{
float tx;
float ty;
VectorType( float tx1, float ty1) :tx(tx1),ty(ty1){}
VectorType( ){}
};
virtual ~Object()
{}
};
class Point :public Object
{
private:
PointType mpoint;
public:
Point(const PointType& pt, float& y1) :Object(y1), mpoint(pt) {}
Point(const PointType& pt):mpoint(pt){}
Point(){}
Point center() const
{
return *this;
}
float x()
{
return mpoint.x2;
}
float y()
{
return mpoint.y2;
}
virtual ~Point(){}
};
class Circle : public Point
{
private:
Object::PointType m_pt;
float r;
public:
Circle(const PointType pts, float rad, float dep)
: Point(m_pt,dep),m_pt(pts),r(rad) {}
Circle(const PointType pts, float rad):m_pt(pts),r(rad){}
Circle(){}
float radius() const
{
return r;
}
Circle center() const
{
return *this;
};
float x()
{
return m_pt.x2;
}
float y()
{
return m_pt.y2;
}
};
class Square: public Circle
{
private:
Object::PointType s_pt;
Object::VectorType v_pt;
float a=getRadius();
public:
Square(const PointType spts,const VectorType vpts,float depth) :
Circle(spts,a,depth),s_pt(spts),v_pt(vpts){}
Square(const Object::PointType& spts, const VectorType vpts):s_pt(spts),v_pt(vpts){}
Square axis() const
{
return Square(s_pt,v_pt,getRadius());
}
Square center() const
{
return *this;
}
float radius() const
{
return a;
}
float getRadius() const
{
float rad= sqrt(v_pt.tx * v_pt.tx + v_pt.ty * v_pt.ty);
return rad;
}
float x() const
{
return s_pt.x2;
// v_pt.tx/radius();
}
float y() const
{
return s_pt.y2;
// v_pt.ty/radius();
}
};
const float EPSILON = 1e-5f;
bool is_near(float x, float y)
{
return std::abs(x - y) < EPSILON;
}
float frand()
{
return 10.0f * float(rand()) / float(RAND_MAX);
}
int main()
{
srand(unsigned(time(0)));
int count = 0;
int max_count = 0;
float x = frand();
float y = frand();
float sx = frand();
float sy = frand();
float depth = frand();
Square square(Square::PointType(x, y), Square::VectorType(sx, sy), depth);
if (is_near(square.center().x(), x) &&
is_near(square.center().y(), y))
{
++count;
}
else
{
std::cout << " - Square::center test failed" << std::endl;
}
++max_count;
float radius = std::sqrt(sx * sx + sy * sy);
if (is_near(square.axis().x(), sx / radius) &&
is_near(square.axis().y(), sy / radius))
{
++count;
}
else
{
std::cout << " - Square::axis test failed" << std::endl;
}
++max_count;
std::cout << square.axis().x()<< " " << sx / radius<<std::endl;
std::cout << square.axis().y()<< " " << sy / radius<<std::endl;
int result = static_cast<int>(
100.0f * static_cast<float>(count) / static_cast<float>(max_count) + 0.5f
);
std::cout << "Tests passed: " << result << "%" << std::endl;
return result;
}
I'm trying to implement collision detection in sfml using the separating axis theorem but my function to get the min translation vector (getMtv()) is always returning that there is a collision (MTV::IsValid()). I was following a tutorial here
but I can't see where I went wrong.
#include <iostream>
#include <math.h>
#include <SFML/Graphics.hpp>
#include <gtest/gtest.h>
typedef sf::Vector2f Vector2;
typedef sf::Vector2f Axis;
typedef sf::Vector2f Projection;
typedef std::vector<Axis> AxesVec;
class MTV
{
private:
bool _valid;
Axis _axis;
float _overlap;
public:
MTV(Axis axis, float overlap, bool valid)
{
_valid = valid;
_overlap = overlap;
_axis = axis;
}
bool IsValid() const
{
return _valid;
}
};
Vector2 perpendicular(Vector2 v)
{
return Vector2(v.y, -v.x);
}
float dot(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.x) + (vec1.y * vec2.y);
}
float magnitude(Vector2 v)
{
return std::sqrt(dot(v,v));
}
class Polygon : public sf::ConvexShape
{
public:
const AxesVec& GetAxes() const
{
return axes;
}
AxesVec axes;
void generateAxes()
{
for (int i = 0; i < getPointCount(); i++)
{
// get the current vertex
Vector2 p1 = getPoint(i); //shape.vertices[i];
// get the next vertex
Vector2 p2 = getPoint(i + 1 == getPointCount() ? 0 : i + 1);
// subtract the two to get the edge vector
Vector2 edge = p1 - p2;
// get either perpendicular vector
Vector2 normal = perpendicular(edge);
// the perp method is just (x, y) => (-y, x) or (y, -x)
axes.push_back(normal / magnitude(normal));
}
};
float cross(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.y) - (vec1.y * vec2.x);
}
Vector2 project(Polygon p, Axis axis)
{
float min = dot(axis, p.getPoint(0)); //axis.dot(shape.vertices[0]);
float max = min;
for (int i = 1; i < p.getPointCount(); i++)
{
// NOTE: the axis must be normalized to get accurate projections
float prj = dot(axis, p.getPoint(i));//axis.dot(shape.vertices[i]);
if (prj < min)
{
min = prj;
}
else if (prj > max)
{
max = prj;
}
}
//Projection proj = new Projection(min, max);
return Projection(min, max);
}
class Collison
{
private:
Vector2 mtv;
Polygon a;
Polygon b;
};
bool overlap(Projection a, Projection b)
{
// x = min & y = max
return !(a.x > b.y || a.x > b.y);
}
float getOverlap(Projection a, Projection b)
{
// x = min & y = max
return (a.y < b.y) ? a.y - b.x : b.y - a.x;
}
MTV getMtv(Polygon a, Polygon b)
{
float overlapMax = std::numeric_limits<float>::infinity();// really large value;
float Overlap;
Axis smallest;// = null;
AxesVec axesA = a.GetAxes();
AxesVec axesB = b.GetAxes();
// loop over the axes1
for (auto&& axis : axesA) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
float o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
for (auto&& axis : axesB) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
double o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
//MTV mtv = new MTV(smallest, overlap);
// if we get here then we know that every axis had overlap on it
// so we can guarantee an intersection
return MTV(smallest, Overlap, true);
}
int main(int argc, char **argv)
{
Polygon polygon;
polygon.setPointCount(3);
polygon.setPoint(0, sf::Vector2f(500, 100));
polygon.setPoint(1, sf::Vector2f(250, 500));
polygon.setPoint(2, sf::Vector2f(750, 500));
polygon.setFillColor(sf::Color::Red);
polygon.generateAxes();
Polygon polygon2;
polygon2.setPointCount(3);
polygon2.setPoint(0, sf::Vector2f(100, 0));
polygon2.setPoint(1, sf::Vector2f(50, 150));
polygon2.setPoint(2, sf::Vector2f(150, 150));
polygon2.generateAxes();
//polygon2.setPoint(0, sf::Vector2f(100, 0));
//polygon2.setPoint(1, sf::Vector2f(500, 150));
//polygon2.setPoint(2, sf::Vector2f(250, 150));
polygon2.setFillColor(sf::Color::Green);
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
// clear the window with black color
window.clear(sf::Color::Black);
// draw everything here...
window.draw(polygon);
window.draw(polygon2);
std::cout << getMtv(polygon, polygon2).IsValid() << std::endl;
// end the current frame
window.display();
}
return 0;
}
I'm having an issue with the inheritance of my operator overloading functions in my derived class.
#pragma once
#include "Math.hpp"
using namespace Math;
class Euler
{
public:
float x, y, z;
Euler();
Euler(const float &, const float &, const float &);
float &operator[](const char &) const;
Euler &operator=(const Euler &);
Euler &operator+=(const Euler &);
Euler &operator-=(const Euler &);
Euler &operator*=(const float &);
Euler &operator/=(const float &);
Euler operator+(const Euler &) const;
Euler operator-(const Euler &) const;
Euler operator*(const float &) const;
Euler operator/(const float &) const;
bool operator==(const Euler &) const;
bool operator!=(const Euler &) const;
bool IsValid() const;
void Clear();
};
inline Euler::Euler()
{
x = y = z = 0.f;
}
inline Euler::Euler(const float &_x, const float &_y, const float &_z)
{
x = _x;
y = _y;
z = _z;
}
inline float &Euler::operator[](const char &c) const
{
return ((float *)this)[c];
}
inline Euler &Euler::operator=(const Euler &e)
{
x = e.x;
y = e.y;
z = e.z;
return *this;
}
inline Euler &Euler::operator+=(const Euler &e)
{
x += e.x;
y += e.y;
z += e.z;
return *this;
}
inline Euler &Euler::operator-=(const Euler &e)
{
x -= e.x;
y -= e.y;
z -= e.z;
return *this;
}
inline Euler &Euler::operator*=(const float &e)
{
x *= e;
y *= e;
z *= e;
return *this;
}
inline Euler &Euler::operator/=(const float &e)
{
x /= e + M_FLT_EPSILON;
y /= e + M_FLT_EPSILON;
z /= e + M_FLT_EPSILON;
return *this;
}
inline Euler Euler::operator+(const Euler &e) const
{
return Euler(x + e.x, y + e.y, z + e.z);
}
inline Euler Euler::operator-(const Euler &e) const
{
return Euler(x - e.x, y - e.y, z - e.z);
}
inline Euler Euler::operator*(const float &f) const
{
return Euler(x * f, y * f, z * f);
}
inline Euler Euler::operator/(const float &f) const
{
return Euler(x / (f + M_FLT_EPSILON), y / (f + M_FLT_EPSILON), z / (f + M_FLT_EPSILON));
}
inline bool Euler::operator==(const Euler &e) const
{
return e.x == x && e.y == y && e.z == z;
}
inline bool Euler::operator!=(const Euler &e) const
{
return e.x != x || e.y != y || e.z != z;
}
inline bool Euler::IsValid() const
{
using namespace std;
return isfinite(x) && isfinite(y) && isfinite(z);
}
inline void Euler::Clear()
{
x = y = z = 0.f;
}
class Vector : public Euler
{
public:
using Euler::Euler;
void Rotate(const Angle &);
void Rotate2D(const float &);
float Length() const;
float LengthSqr() const;
float Length2D() const;
float Length2DSqr() const;
float DistTo(const Vector &) const;
float DistToSqr(const Vector &) const;
};
inline float Vector::Length() const
{
return Sqrt((x * x) + (y * y) + (z * z));
}
inline float Vector::LengthSqr() const
{
return (x * x) + (y * y) + (z * z);
}
inline float Vector::Length2D() const
{
return Sqrt((x * x) + (y * y));
}
inline float Vector::Length2DSqr() const
{
return (x * x) + (y * y);
}
inline float Vector::DistTo(const Vector &v) const
{
return (*this - v).Length();
}
inline float Vector::DistToSqr(const Vector &v) const
{
return (*this - v).LengthSqr();
}
The code shown below contains an error in the distto and DistToSqr function wherein it calculates (*this - v) as the superclass Euler and therefore cannot find the length function.
I was wondering why this would be as this code compiles on my laptop and not my desktop.
I'd be grateful if anyone could show me why this code doesn't work and what is the best course in fixing it.
It seems like doing this is a plausible way to fix it.
inline float Vector::DistTo(const Vector &v) const
{
Vector tmp = (*this - v);
return tmp.Length();
}
Still wondering if this is the best option to fix it though.
I'm going to assume that it is likely that Euler is always used as a base type of a more specific type? If so, you can might be able to solve this using the CRTP pattern. Here is a subset of your code in this style:
#include <cmath>
template <typename Derived>
class Euler
{
public:
float x, y, z;
Euler();
Euler(const float &, const float &, const float &);
template <typename T>
Derived & operator-=(Euler<T> const &);
template <typename T>
Derived operator-(Euler<T> const &) const;
private:
Derived & derived() const {
return static_cast<Derived &>(*this);
}
Derived const & derived() {
return static_cast<Derived const &>(*this);
}
};
template <typename Derived>
Euler<Derived>::Euler() : x(0), y(0), z(0)
{}
template <typename Derived>
Euler<Derived>::Euler(const float &_x, const float &_y, const float &_z)
: x(_x), y(_y), z(_z)
{}
template <typename Derived>
template <typename T>
Derived & Euler<Derived>::operator-=(Euler<T> const & e)
{
x -= e.x;
y -= e.y;
z -= e.z;
return derived();
}
template <typename Derived>
template <typename T>
Derived Euler<Derived>::operator-(Euler<T> const & e) const
{
return Derived(x - e.x, y - e.y, z - e.z);
}
class Vector : public Euler<Vector>
{
public:
using Euler<Vector>::Euler;
float Length() const;
float DistTo(const Vector &) const;
};
inline float Vector::Length() const
{
return std::sqrt(x * x + y * y + z * z);
}
inline float Vector::DistTo(const Vector & v) const
{
return (*this - v).Length();
}
I have a derived class Circle of base class Shape, where each class has its own print, collide, merge, type, etc functions. I instantiate a bunch of Circle objects and put them into a container (its a container of pointers since I was running into trouble with object splicing). In this method I compare objects to each other and update properties. All of my derived member functions are called except for collide, which calls the base function. I print out the types of the objects before collide, and they are both circles. I have no idea why the derived collide is not being called like the other methods.
In the code directly below, the output to the type() methods are Circle.
The function where collide and other methods are called.
void calculateGravitationalAttractions(ShapeContainer &shapeContainer) {
double G = constants::gravitationalConstant;
double distance, diffX, diffY, tempAx, tempAy;
double Fnet; //Net Force on body
double theta; //Angle between two points in 2-D space
double accel; //Net acceleration of body
double distanceBetweencb, collisionDistance;
std::list<Shape*>::iterator ii;
std::list<Shape*>::iterator jj;
std::list<Shape*> container = shapeContainer.container;
//int callCount = 0;
for(ii = container.begin(); ii != container.end(); ++ii) {
tempAx = tempAy = 0;
for(jj = container.begin(); jj != container.end(); ++jj) {
if((*ii) != (*jj)) {
//callCount++;
(*ii)->type();
(*jj)->type();
if (!(*ii)->collide(*(*jj))) {
diffX = (*ii)->pos[0] - (*jj)->pos[0];
diffY = (*ii)->pos[1] - (*jj)->pos[1];
distance = sqrt((diffX * diffX) + (diffY * diffY));
Fnet = ((G * (*ii)->mass * (*jj)->mass)) / distance;
theta = atan2(diffY, diffX);
accel = Fnet / (*ii)->mass;
tempAx += -(accel * cos(theta));
tempAy += -(accel * sin(theta));
} else { //if they collide
if((*ii)->mass > (*jj)->mass) {
(*ii)->merge(*(*jj));
jj = container.erase(jj);
} else {
(*jj)->merge(*(*ii));
ii = container.erase(ii);
}
}
}
}
//printf("\n %f, %f, \n", tempAx, tempAy);
(*ii)->accel[0] = tempAx;
(*ii)->accel[1] = tempAy;
}
//printf("Container size is %d\n", container.size());
//printf("Callcount is %d\n\n", callCount);
}
My Shape and Circle classes.
typedef array<double, 2> Vector;
class Shape {
public:
Vector pos;
Vector vel;
Vector accel;
double mass;
bool move;
SDL_Color color;
Shape() {}
Shape(Vector Pos, Vector Vel, Vector Accel, double Mass, bool Move, SDL_Color Color) {
pos = Pos;
vel = Vel;
accel = Accel;
mass = Mass;
move = true;
color = Color;
}
virtual void print() {
printf("Type: Shape\n");
printf("xPos: %f, yPos: %f\n", pos[0], pos[1]);
printf("xVel: %f, yVel: %f\n", vel[0], vel[1]);
printf("xAccel: %f, yAccel: %f\n", accel[0], accel[1]);
printf("mass: %f\n\n", mass);
}
virtual void render(SDL_Renderer* renderer) {
//printf("Rendering shape.\n");
}
virtual bool collide(Shape &a) { //true if the shapes collide
printf("Checking collision of shape.\n");
double xDiff = pos[0] - a.pos[0];
double yDiff = pos[1] - a.pos[1];
if (sqrt((xDiff * xDiff) + (yDiff * yDiff) < 100)) {
return true;
} else {
return false;
}
}
virtual void merge(Shape &a) {
color.r = (color.r * mass + a.color.r * a.mass) / (mass + a.mass);
color.g = (color.g * mass + a.color.g * a.mass) / (mass + a.mass);
color.b = (color.b * mass + a.color.b * a.mass) / (mass + a.mass);
mass += a.mass;
printf("Merging shapes.");
}
virtual void type() {
cout << "Type: Shape\n";
}
};
class Circle: public Shape {
public:
double radius;
Circle() {}
Circle(Vector Pos, Vector Vel, Vector Accel, double Mass, bool Move, SDL_Color Color) {
pos = Pos;
vel = Vel;
accel = Accel;
mass = Mass;
radius = sqrt(mass) * constants::radiusFactor;
move = true;
color = Color;
}
void print() {
printf("Type: Circle\n");
printf("xPos: %f, yPos: %f\n", pos[0], pos[1]);
printf("xVel: %f, yVel: %f\n", vel[0], vel[1]);
printf("xAccel: %f, yAccel: %f\n", accel[0], accel[1]);
printf("mass: %f\n", mass);
printf("radius: %f\n\n", radius);
}
void render(SDL_Renderer* renderer) {
//printf("Rendering circle.\n");
int success = filledCircleRGBA(renderer, (int) pos[0], (int) pos[1],
(int) radius, color.r, color.g, color.b, 255);
}
bool collide(Circle &a) { //true if the shapes collide
printf("Checking collision of circle.\n");
double xDiff = pos[0] - a.pos[0];
double yDiff = pos[1] - a.pos[1];
if (sqrt((xDiff * xDiff) + (yDiff * yDiff) < radius + a.radius)) {
return true;
} else {
return false;
}
}
void merge(Circle &a) {
printf("Merging circles.");
//momentum calculations
double xVel = vel[0]*mass + a.vel[0]*a.mass;
double yVel = vel[1]*mass + a.vel[1]*a.mass;
double totalMass = mass + a.mass ;
vel[0] = xVel / mass * constants::frictionFactor;
vel[1] = yVel / mass * constants::frictionFactor;
//merge colors
color.r = (color.r * mass + a.color.r * a.mass) / (mass+a.mass);
color.g = (color.g * mass + a.color.g * a.mass) / (mass+a.mass);
color.b = (color.b * mass + a.color.b * a.mass) / (mass+a.mass);
mass += a.mass;
}
void type() {
cout << "Type: Circle\n";
}
All of my derived member functions are called except for collide
That would be because you don't actually override the collide method in your Circle subclass:
class Shape {
virtual bool collide(Shape &a) { ...
class Circle: public Shape {
bool collide(Circle &a) { ...
Different signature, different method.
I am using a class to represent a rotation angle...
class RotationAngle
{
protected:
float cosval;
float sinval;
__forceinline RotationAngle(float c, float s) { cosval = c; sinval = s; }
public:
__forceinline RotationAngle(float radians) { Set(radians); }
__forceinline RotationAngle(const RotationAngle& r) { Set(r); }
__forceinline void Set(float radians) { cosval = cos(radians); sinval = sin(radians); }
__forceinline void Set(const RotationAngle& r) { cosval = r.cosval; sinval = r.sinval; }
__forceinline float Cos() const { return cosval; }
__forceinline float Sin() const { return sinval; }
__forceinline RotationAngle& operator = (float radians) { Set(radians); return *this; }
__forceinline int operator == (const RotationAngle& r) const { return (r.cosval == cosval) && (r.sinval == sinval); }
__forceinline int operator != (const RotationAngle& r) const { return (r.cosval != cosval) || (r.sinval != sinval); }
};
I use this so I can add an angle to a point or line using an operator, and have the sine and cosine pre-calculated. It would be redundant to recalculate the sine and cosine of the angles every time the point was rotated by the same angle.
class Point
{
public:
float x;
float y;
__forceinline void Set(float sx, float sy) { x = sx; y = sy; }
__forceinline void Rotate(const RotationAngle& a) { Set(x * a.Cos() - y * a.Sin(), x * a.Sin() + y * a.Cos()); }
__forceinline void operator += (const RotationAngle& a) { Rotate(a); }
};
I would like to include a -= operator to use the negative representation of a RotationAngle (ie counterclockwise rotation). Will simply using -cos and -sin work? I'm not sure considering the formula for adding sin/cos is not as straightforward. Is there a quick way to accomplish this?
Negating an angle will negate its sine, but leave its cosine unchanged. So it might make sense to define a unary negation:
RotationAngle operator-() const {return RotationAngle(cosval, -sinval);}
and then define -= in terms of that
void operator -= (const RotationAngle& a) { Rotate(-a); }