Animating along an elliptical path in OpenGL - c++

I am trying to make a red circle follow the path of a semi-circle using the DDA algorithm in OpenGL. I almost have it, though the circle is slightly offset on its X-axis, which increases as the angle of the semi-circle increases.
Any assistance would be greatly appreciated! Here's my code:
scrPt movecircle (scrPt p1, scrPt p2)
{
scrPt circlePos;
float angle, x = p1.x, y = p1.y, vectorX, vectorY;
// Get tahe x distance between the two points
int dx = p2.x - p1.x, steps;
// Get the y distance between the two points
int dy = p2.y - p1.y;
// Get the length between the points
float length = sqrt(dx*dx + dy*dy);
if (fabs (dx) > fabs (dy))
steps = fabs (dx);
else
steps = fabs (dy);
// calculate the direction
float xIncrement = float (dx) / float (steps);
float yIncrement = float (dy) / float (steps);
if (nextPos == 0)
{
for(int i = 0; i < steps; i++)
{
glClear(GL_COLOR_BUFFER_BIT);
angle = PI * i / steps;
vectorX = x + (length / 2) * cos(angle + theta);
vectorY = y + dy / 2 + (length / 2) * sin(angle + theta);
circlePos.x = round(vectorX - length / 2);
circlePos.y = round(vectorY);
drawCircle (circlePos.x, circlePos.y);
drawArch();
glFlush();
usleep(3000);
}
}
else
{
for (int i = 0; i < steps; i++)
{
glClear(GL_COLOR_BUFFER_BIT);
drawCircle (round(x),round(y));
glFlush();
usleep(3000);
x += xIncrement;
y += yIncrement;
}
}
return circlePos;
}

There were a couple of errors in the for-loop that were causing the issue. I needed to change
this:
vectorX = x + (length / 2) * cos(angle + theta);
to this:
vectorX = x + (dx / 2) + (length / 2) * cos(angle + theta);
and this:
circlePos.x = round(vectorX - (length / 2));
to this:
circlePos.x = round(vectorX);

Related

Cubic Interpolation with the official formula fails

I am trying to implement the Cubic Interpolation method using the next formula when a=-0.5 as usual.
My Linear Interpolation and Nearest Neighbor interpolation is working great but for some reason the Cubic interpolation fails with white pixels and turn them sometimes to turquoise color and sometimes messing around with another colors.
for example using rotation: (NOTE: please look carefully on the right image and you will notice the problems)
Another Example with much more black pixels. It almost seems to work perfectly but look on the dog's tongue. (strong white pixels turn to turquoise again)
you can see that my implementation of the Linear Interpolation is working great:
Since the actual rotation worked, I think I have a small mistake in the code that I did not notice, or maybe it's a numeric error or a double / float error.
It is important to note that I read the image normally and store the destination image as follows:
cv::Mat img = cv::imread("../dogfails.jpeg");
cv::Mat rotatedImageCubic(img.rows,img.cols,CV_8UC3);
Clarifications:
Inside my cubic interpolation function, srcPoint (newX and newY) is the "landing point" from the inverse transformation.
In my inverse transformations I am not using matrix multiplication with the pixels, right now I am just using the formulas for rotation. It might be important for the "numerical errors". For example:
rotatedX = x * cos(angle * toRadian) + y * sin(angle * toRadian);
rotatedY = x * (-sin(angle * toRadian)) + y * cos(angle * toRadian);
Here is my code for the Cubic Interpolation
double cubicEquationSolver(double d,double a) {
d = abs(d);
if( 0.0 <= d && d <= 1.0) {
double score = (a + 2.0) * pow(d, 3.0) - ((a + 3.0) * pow(d, 2.0)) + 1.0;
return score;
}
else if(1 < d && d <= 2) {
double score = a * pow(d, 3.0) - 5.0*a * pow(d, 2.0) + 8.0*a * d - 4.0*a;
return score;
}
else
return 0.0;
}
void Cubic_Interpolation_Helper(const cv::Mat& src, cv::Mat& dst, const cv::Point2d& srcPoint, cv::Point2i& dstPixel) {
double newX = srcPoint.x;
double newY = srcPoint.y;
double dx = abs(newX - round(newX));
double dy = abs(newY - round(newY));
double sumCubicBValue = 0;
double sumCubicGValue = 0;
double sumCubicRValue = 0;
double sumCubicGrayValue = 0;
double uX = 0;
double uY = 0;
if (floor(newX) - 1 < 0 || floor(newX) + 2 > src.cols - 1 || floor(newY) < 0 || floor(newY) > src.rows - 1) {
if (dst.channels() > 1)
dst.at<cv::Vec3b>(dstPixel) = cv::Vec3b(0, 0,0);
else
dst.at<uchar>(dstPixel) = 0;
}
else {
for (int cNeighbor = -1; cNeighbor <= 2; cNeighbor++) {
for (int rNeighbor = -1; rNeighbor <= 2; rNeighbor++) {
uX = cubicEquationSolver(rNeighbor + dx, -0.5);
uY = cubicEquationSolver(cNeighbor + dy, -0.5);
if (src.channels() > 1) {
sumCubicBValue = sumCubicBValue + (double) src.at<cv::Vec3b>(
cv::Point2i(round(newX) + rNeighbor, cNeighbor + round(newY)))[0] * uX * uY;
sumCubicGValue = sumCubicGValue + (double) src.at<cv::Vec3b>(
cv::Point2i(round(newX) + rNeighbor, cNeighbor + round(newY)))[1] * uX * uY;
sumCubicRValue = sumCubicRValue + (double) src.at<cv::Vec3b>(
cv::Point2i(round(newX) + rNeighbor, cNeighbor + round(newY)))[2] * uX * uY;
} else {
sumCubicGrayValue = sumCubicGrayValue + (double) src.at<uchar>(
cv::Point2i(round(newX) + rNeighbor, cNeighbor + round(newY))) * uX * uY;
}
}
}
if (dst.channels() > 1)
dst.at<cv::Vec3b>(dstPixel) = cv::Vec3b((int) round(sumCubicBValue), (int) round(sumCubicGValue),
(int) round(sumCubicRValue));
else
dst.at<uchar>(dstPixel) = sumCubicGrayValue;
}
I hope someone here will be able to help me, Thanks!

How do I resolve a collision's position properly in 2D collision detection?

My current implementation looks like this:
if (shapesCollide) {
if (velocity.y > 0) entity.position.y = other.position.y - entity.size.y;
else entity.position.y = other.position.y + other.size.y;
velocity.y = 0;
if (velocity.x > 0) entity.position.x = other.position.x - entity.size.x;
else entity.position.x = other.position.x + other.size.x;
velocity.x = 0;
}
However, this leads to weird handling when movement is happening on both axes - for example, having entity moving downward to the left of object, and then moving it to collide with object, will correctly resolve the horizontal collision, but will break the vertical movement.
I previously simply went
if (shapesCollide) {
position = oldPosition;
velocity = { 0, 0 };
}
But this lead to another multi-axis issue: if I have my entity resting atop the object, it will be unable to move, as the gravity-induced movement will constantly cancel out both velocities. I also tried considering both axes separately, but this lead to issues whenever the collision only occurs when both velocities are taken into account.
What is the best solution to resolving collision on two axes?
I assume that the entities can be considered to be more or less round and that size is the radius of the entities?
We probably need a little vector math to resolve this. (I don't know the square-root function in c++, so be aware at sqrt.) Try replacing your code inside if(shapesCollide) with this and see how it works for you.
float rEntity = sqrt(entity.size.x * entity.size.x + entity.size.y * entity.size.y);
float rOther = sqrt(other.size.x * other.size.x + other.size.y * other.size.y);
float midX = (entity.position.x + other.position.x) / 2.0;
float midY = (entity.position.y + other.position.y) / 2.0;
float dx = entity.position.x - midX;
float dy = entity.position.y - midY;
float D = sqrt(dx * dx + dy * dy);
rEntity and rOther are the radii of the objects, and midX and midY are their center coordinates. dx and dy are the distances to the center from the entity.
Then do:
entity.position.x = midX + dx * rEntity / D;
entity.position.y = midY + dy * rEntity / D;
other.position.x = midX - dx * rOther / D;
other.position.y = midY - dy * rOther / D;
You should probably check that D is not 0, and if it is, just set dx = 1, dy = 0, D = 1 or something like that.
You should also still do:
velocity.x = 0;
velocity.y = 0;
if you want the entities to stop.
For more accurate modelling, you could also try the following:
float rEntity = sqrt(entity.size.x * entity.size.x + entity.size.y * entity.size.y);
float rOther = sqrt(other.size.x * other.size.x + other.size.y * other.size.y);
float midX = (entity.position.x * rOther + other.position.x * rEntity) / (rEntity + rOther);
float midY = (entity.position.y * rOther + other.position.y * rEntity) / (rEntity + rOther);
float dxEntity = entity.position.x - midX;
float dyEntity = entity.position.y - midY;
float dEntity = sqrt(dxEntity * dxEntity + dyEntity * dyEntity);
float dxOther = other.position.x - midX;
float dyOther = other.position.y - midY;
float dOther = sqrt(dxOther * dxOther + dyOther * dyOther);
entity.position.x = midX + dxEntity * rEntity / dEntity;
entity.position.y = midY + dyEntity * rEntity / dEntity;
other.position.x = midX + dxOther * rOther / dOther;
other.position.y = midY + dyOther * rOther / dOther;
which finds the midpoints when the radii are taken into account. But I won't guarantee that that works. Also, the signs on the last additions are important.
I hope this helps (and works). Let me know if something is unclear.

C++ Angles between a vector and a point

I got 2 points own=(x, y, z) and en=(x, y, z) which represents my own position in the world and some other player position. the other player also got pitch (from 90 degrees to -90) and yaw (0 to 360). I want to calculate the angles between the other player look and my own position.
In 2D, alpha is what I'm trying to calculate:
int main()
{
float own_x = 1, own_y = 1, own_z = 1;
float en_x = 10, en_y = 1, en_z = 10;
float pi = 3.14159265;
float pitch = 0.f * (pi / 180), yaw = 45.f * (pi / 180);
float x = sin(yaw) * cos(pitch);
float y = sin(pitch);
float z = cos(pitch) * cos(yaw);
float vec_length = sqrt(pow(en_x - own_x, 2) + pow(en_y - own_y, 2) + pow(en_y - own_y, 2));
x /= vec_length;
y /= vec_length;
z /= vec_length;
float cos_t = ((en_x - own_x)*x + (en_y - own_y)*y + (en_z - own_z)*z) / sqrt(pow(en_x - own_x, 2) + pow(en_y - own_y, 2) + pow(en_y - own_y, 2));
float arc = acos(cos_t) * (180 / pi);
return 0;
}
you divide twice with the length of en-own: You should remove
vec_length, and xyz /= vec_length.
your division at cos_t is buggy, you use _y twice in the
expression instead of _y and _z
Note: instead of pow(x, 2), use x*x, it is faster usually (compilers may not optimize pow(x, 2) to x*x).

Half of my ellipse drawn in the wrong place

Here is the code for an oval drawing method I am working on. I am applying the Bresenham method to plot its co-ordinates, and taking advantage of the ellipse's symmetrical properties to draw the same pixel in four different places.
void cRenderClass::plotEllipse(int xCentre, int yCentre, int width, int height, float angle, float xScale, float yScale)
{
if ((height == width) && (abs(xScale - yScale) < 0.005))
plotCircle(xCentre, yCentre, width, xScale);
std::vector<std::vector <float>> rotate;
if (angle > 360.0f)
{
angle -= 180.0f;
}
rotate = maths.rotateMatrix(angle, 'z');
//rotate[0][0] = cos(angle)
//rotate[0][1] = sin(angle)
float theta = atan2(-height*rotate[0][1], width*rotate[0][0]);
if (angle > 90.0f && angle < 180.0f)
{
theta += PI;
}
//add scalation in at a later date
float xShear = (width * (cos(theta) * rotate[0][0])) - (height * (sin(theta) * rotate[0][1]));
float yShear = (width * (cos(theta) * rotate[0][1])) + (height * (sin(theta) * rotate[0][0]));
float widthAxis = abs(sqrt(((rotate[0][0] * width) * (rotate[0][0] * width)) + ((rotate[0][1] * height) * (rotate[0][1] * height))));
float heightAxis = (width * height) / widthAxis;
int aSquared = widthAxis * widthAxis;
int fourASquared = 4*aSquared;
int bSquared = heightAxis * heightAxis;
int fourBSquared = 4*bSquared;
x0 = 0;
y0 = heightAxis;
int sigma = (bSquared * 2) + (aSquared * (1 - (2 * heightAxis)));
while ((bSquared * x0) <= (aSquared * y0))
{
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
if (sigma >= 0)
{
sigma += (fourASquared * (1 - y0));
y0--;
}
sigma += (bSquared * ((4 * x0) + 6));
x0++;
}
x0 = widthAxis;
y0 = 0;
sigma = (aSquared * 2) + (bSquared * (1 - (2 * widthAxis)));
while ((aSquared * y0) <= (bSquared * x0))
{
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
if (sigma >= 0)
{
sigma += (fourBSquared * (1 - x0));
x0--;
}
sigma += (aSquared * (4 * y0) + 6);
y0++;
}
//the above algorithm hasn't been quite completed
//there are still a few things I want to enquire Andy about
//before I move on
//this other algorithm definitely works
//however
//it is computationally expensive
//and the line drawing isn't as refined as the first one
//only use this as a last resort
/* std::vector<std::vector <float>> rotate;
rotate = maths.rotateMatrix(angle, 'z');
float s = rotate[0][1];
float c = rotate[0][0];
float ratio = (float)height / (float)width;
float px, py, xNew, yNew;
for (int theta = 0; theta <= 360; theta++)
{
px = (xCentre + (cos(maths.degToRad(theta)) * (width / 2))) - xCentre;
py = (yCentre - (ratio * (sin(maths.degToRad(theta)) * (width / 2)))) - yCentre;
x0 = (px * c) - (py * s);
y0 = (px * s) + (py * c);
drawPixel(x0 + xCentre, y0 + yCentre);
}*/
}
Here's the problem. When testing the rotation matrix on my oval drawing function, I expect it to draw an ellipse at a slant from its original horizontal position as signified by 'angle'. Instead, it makes a heart shape. This is sweet, but not the result I want.
I have managed to get the other algorithm (as seen in the bottom part of that code sample) working successfully, but it takes more time to compute, and doesn't draw lines quite as nicely. I only plan to use that if I can't get this Bresenham one working.
Can anyone help?

Cairo Matrix equivillant of GlOrtho Matrix?

Given that I do something like this:
void glOrtho( GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble nearVal,
GLdouble farVal);
and the result is: http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xmlw could I achieve a matrix like this:
http://cairographics.org/manual/cairo-matrix.html
I tried this:
cairo_matrix_t mat;
mat.xx = 2 / (right - left);
mat.yx = 0;
mat.xy = 2 / (top - bottom);
mat.yy = 0;
mat.x0 = 0;
mat.y0 = 0;
cairo_set_matrix(cr,&mat);
But it did not work. How could I acheive the same matrix that GlOrtho makes in Cairo?
Thanks
I don't know Cairo so I'll delete my answer if a better one comes.
According to the docs of Cairo:
x_new = xx * x + xy * y + x0;
y_new = yx * x + yy * y + y0;
When you use OpenGL, the formula is like: (m being the matrix)
x_new = m(1,1) * x + m(1,2) * y + m(1,3) * z + m(1,4)
y_new = m(2,1) * x + m(2,2) * y + m(2,3) * z + m(2,4)
z_new = m(3,1) * x + m(3,2) * y + m(3,3) * z + m(3,4)
(note that for the sake of simplicity I did not mention the fourth coordinate)
So what you have to do is simply match the two formulas:
mat.xx = 2 / (right - left);
mat.yy = 2 / (top - bottom);
mat.xy = 0;
mat.yx = 0;
mat.x0 = -(right + left) / (right - left);
mat.y0 = -(top + bottom) / (top - bottom);
Please try this