problems with circular movement calculations - c++

Question rescinded by original poster
Hey so when running the following code my square is supposed to travel around in a circle, but there is some kind of issue with the function that calculates the x,y movement that should happen based on the velocity and angle of travel.
It succesfully travels around and around, but not in the right way. the 2nd and 4th quadrant are kind of inversed, and curving inwards towards the center of the circle rather than outward.
I can't figure out what the problem is... anyone wanna help?
#include<SFML/Graphics.hpp>
#include<SFML/System.hpp>
#include<cmath>
#include<vector>
# define M_PI 3.14159265358979323846
sf::RenderWindow Window;
template<typename T>
void CalculateMove(T Time, T Speed, T Angle, T& buffX, T& buffY)
{ //Make the degrees positive
if(Angle<0) Angle= 360-Angle;
//determine what quadrant of circle we're in
unsigned int Quadrant= 1;
if(Angle>90) Quadrant= 2;
if(Angle>180) Quadrant= 3;
if(Angle>270) Quadrant= 4;
//anything above 90 would be impossible triangle
Angle= (float)(Angle-(int)Angle)+(float)((int)Angle%90);
// calculates x and y based on angle and Hypotenuse.02433
if((int)Angle!=0){
buffX= sin(Angle / 180 * M_PI)/ (1.f/(Speed*Time));
buffY= sin((180-Angle-90)/ 180 * M_PI)/ (1.f/(Speed*Time));}
else{// Movement is a straight line on X or Y axis
if(Quadrant==0 || Quadrant==2) buffX= Speed*Time;
if(Quadrant==1 || Quadrant==4) buffY= Speed*Time;}
//Quadrant Factor (positive or negative movement on the axis)
switch(Quadrant){
case 1: break;
case 2: buffX=-buffX; break;
case 3: buffX=-buffX; buffY=-buffY; break;
case 4: buffY=-buffY; break;}
};
///////////////////////////////////////// Mysprite ////////////////////////////////
class mySprite : public sf::Sprite
{
private:
float velocity;
float angle;
public:
// all the values needed by the base class sprite();
mySprite(
const sf::Image& Img,
const sf::Vector2f& Position = sf::Vector2f(0, 0),
const sf::Vector2f& Scale = sf::Vector2f(1, 1),
float Rotation = 0.f,
const float Angle= 0.f,
const float Velocity= 0.f,
const sf::Color& Col = sf::Color(255, 255, 255, 255)):
Sprite(Img, Position, Scale, Rotation, Col){
angle= Angle;
velocity= Velocity;};
float Velocity(){return velocity;};
void SetVelocity(float newVelocity){velocity=newVelocity;};
float Angle(){return angle;};
void SetAngle(float newAngle){angle=(float)(newAngle-(int)newAngle)+(float)((int)newAngle%360);};
void Update(){
float frameTime= Window.GetFrameTime();
float X=0,Y=0;
CalculateMove(frameTime,velocity,angle,X,Y);
Move(X,-Y);
};
void Accelerate(float PPS){velocity+=PPS;};
void Turn(float degrees){
float test= (float)((angle+degrees)- (int)(angle+degrees)); //TODO: Get rid of these test
float test2=(float)((int)(angle+degrees)%360);
float test3=test+test2;
angle=(float)((angle+degrees)-(int)(angle+degrees))+(float)((int)(angle+degrees)%360);};
void Reflect(float CollAngle){
SetRotation(-GetRotation());
angle=-angle;
//TODO: factor in the collision angle
};
};
int main()
{
Window.Create(sf::VideoMode(800, 600), "Pong! by Griffin Howlett");
sf::Image img;
img.Create(30,50,sf::Color(255,0,0));
mySprite box(img, sf::Vector2f(400,200), sf::Vector2f(1,1), 0, 180, 200);
Window.Display();
for(;;){
Window.Clear();
box.Update();
box.Turn(45.0*Window.GetFrameTime());
Window.Draw(box);
Window.Display();
}
}

Your first mistake:
if(Angle<0) Angle= 360-Angle;
should be:
if(Angle<0) Angle= 360+Angle;
I'm not quite sure why you're going to the trouble of dividing the angle into quadrants. Do you think that the sin function is only defined for the range of 0 to 90 degrees?

Not sure all of the problems, but this line of code is wrong:
if(Angle<0) Angle= 360-Angle;
If Angle < 0 then 360 - Angle will be > 360
you can also clean up the quadrant setting code, otherwise when the Angle is > 270, you do the assignment 4 times.
int Quadrant = 1;
if (Angle > 270)
{
Qadrant = 4;
}
else if (Angle > 180)
{
Quadrant = 3;
}
else if (Angle > 90)
{
Quadrant = 2;
}

It seems I was wrong in assuming the triangle formed and used to calculate the movement required to get to the x, y coordinates would always automatically use the Y axis as the side opposite of the 'Angle', and istead the coordinates were backwards for Quadrant 2 and 4, Thanks for the other feedback though!
Here's the updated code:
if((int)Angle!=0){
if(Quadrant==2 || Quadrant==4) Angle=90-Angle; //The unit circle triangle is flipped otherwise, causing x and y to be switched
buffY= sin(Angle / 180 * M_PI)/ (1.f/(Speed*Time));
buffX= sin((180-Angle-90)/ 180 * M_PI)/ (1.f/(Speed*Time));}
by doing 90-Angle i'm switching the angles used to find the X, and Y side of the imaginary triangle....

Related

How to move object towards an angle in degrees? (C, C++)

I'm trying to move a bullet object towards a player position. I found this angle function online, and it seems to convert it to those coordinates in the comments. But i can't make the bullet follow in the direction.
float Angle(int p1x, int p1y, int p2x,int p2y)
{
//Make point1 the origin, make point2 relative to the origin so we do point1 - point1, and point2-point1,
//since we dont need point1 for the equation to work, the equation works correctly with the origin 0,0.
int deltaY = p2y - p1y;
int deltaX = p2x - p1x; //Vector 2 is now relative to origin, the angle is the same, we have just transformed it to use the origin.
float angleInDegrees = atan2(deltaY, deltaX) * 180 / PI;
//float angleInRadians = atan2(deltaY, deltaX);
angleInDegrees *= -1; // Y axis is inverted in computer windows, Y goes down, so invert the angle.
//Angle returned as:
// 90
// 135 45
//
// 180 Origin 0
//
// -135 -45
//
// -90
return angleInDegrees;
}
if (bulletsData[3] == STDEACTIVE){ //bulletData: 0 = x, 1 = y, 2 = dir, 3 = state
bulletsData[2] = Angle(bulletsData[0],bulletsData[1], plData[0], plData[1]);
bulletsData[3] = STACTIVE;
}
if (bulletsData[3] == STACTIVE){
if (ardu.everyXFrames(1)){
bulletsData[0] += cos(bulletsData[2]) * 1; //My attempt to move it towards the direction.
bulletsData[1] += sin(bulletsData[2]) * 1;
}
}
You are explicitly calculating angles in degrees, yet sin and cos expect radians, not degrees.
Without analyzing whether or not the Angle function is correct, your code will make more sense if you change the function to return a value in radians. You even have the required line there commented out.
So, something like this perhaps:
float angleInRadians = atan2(deltaY, deltaX);
return -angleInRadians; // Return negative angle to compensate for Y-down

Function that finds the specified distance from a point to any part of a rectangle

Write a function that tests if a point is within a specified distance of any part of a filled rectangle. The rectangle is specified by its center point, extents and rotation.
struct s_Vector
{
float x;
float y;
};
struct s_Rectangle
{
s_Vector center; // center of the rect in world space
s_Vector localX; // local space X direction vector, normalized
s_Vector localY; // local space Y direction vector, normalized
float fExtentsX; // distance from the rect center to the right edge
float fExtentsY; // distance from the rect center to the top edge
};
bool IsPointWithinDistOfRectangle(s_Rectangle & rect, s_Vector & point, float distance);
So I am so confused on how to use the localX and localy for the rotation of the triangle and then how to use that to fnd if the point is at a specified distance from the rectangle or not.
For an arbitrary rectangle, we can determine if a point is inside the rectangle as follows:
bool IsPointWithinRectangle(s_Rectangle & rect, s_Vector & point) {
s_Vector dist = abs(point - rect.center);
float dist_x = dot(dist, rect.localX);
float dist_y = dot(dist, rect.localY);
return dist_x <= rect.fExtentsX && dist_y <= rect.fExtentsY;
}
This uses the dot function to project the distance onto the local X and Y vectors. The extents of the rectangle are defined in terms of multiples of these local X and Y vectors, so we test against these extents.
If we now want to add the "within distance" constraint as well:
bool IsPointWithinDistOfRectangle(s_Rectangle & rect, s_Vector & point, float distance) {
s_Vector dist = abs(point - rect.center);
float dist_x = dot(dist, rect.localX) - rect.fExtentsX;
float dist_y = dot(dist, rect.localY) - rect.fExtentsY;
if (dist_x <= 0 && dist_y <= 0)
return true; // In the rectangular area
// If one of the two distances is negative (ie in the rectangle),
// put it on the edge by setting distance to 0.
dist_x = max(dist_x, 0);
dist_y = max(dist_y, 0);
// Finally, check if we are within a distance of the rectangle.
// If the point is along one of the sides, one of dist_x and dist_y is 0,
// so compare the (squared) distance to `distance`.
// Otherwise the point must be in a radius around the corner.
return (dist_x * dist_x + dist_y * dist_y) <= distance * distance;
}

Fractal Tree - branches not drawn

Currently, I'm trying to draw a symmetric binary tree through IFS (Iterated Function Systems):
but the result is always only the branch tips:
.
I can't figure out what I'm doing wrong or what I'm missing.
This is the IFS:
This is my code:
RenderWindow window(VideoMode(480, 640), "fractals everywhere");
CircleShape point(1);
int chance;
float x, y, w, h, nx, ny, px, py;
void SymmetricBinaryTrees()
{
float r = 0.57f;
float o = 0.785f;
chance = rand() % 3;
switch (chance)
{
case 0:
nx = r * cos(o) * x + (-1 * r * sin(o) * y);
ny = r * sin(o) * x + r * cos(o) * y + 1;
break;
case 1:
nx = r * cos(o) * x + r * sin(o) * y;
ny = -1 * r * sin(o) * x + r * cos(o) * y + 1;
break;
case 2:
nx = x;
ny = y;
break;
}
}
void nextPoint()
{
SymmetricBinaryTrees();
x = nx; y = ny;
}
void drawPoint()
{
px = _map(x, -1.078, 1.078f, 0, w); py = _map(y, 0.f, 2.078f, h, 0); // maps the position accordingly
point.setPosition(px, py);
window.draw(point);
}
int main()
{
srand(time(NULL));
w = window.getSize().x * 1.f;
h = window.getSize().y * 1.f;
x = 0.f; y = 0.f;
window.setFramerateLimit(60);
while (window.isOpen())
{
Event e;
while (window.pollEvent(e))
if (e.type == Event::Closed) window.close();
for (int i = 1; i <= 500; i++)
{
drawPoint();
nextPoint();
}
window.display();
}
return 0;
}
This is the website that I'm using for my code.
If anyone could help me or has any idea I'd be very grateful, thank you.
I share #beyond opinion, I think you're complicating things too much. It will be easier with a different approach. Let's make things easier.
With a recursive function, we can easily understand what should be done each step.
Consider we start from a initial point, then trace a line on an angle of a given lenght, so we need a function like:
void createTreeRecursive(sf::VertexArray &tree, sf::Vector2f point, float angle, float lenght)
Where tree will be our line set, which compose the tree itself.
First thing we can do, is to set the first point, which is already known:
// Add first point
tree.append(sf::Vertex(point, treeColor));
Now we need to calculate our next point, to form a line. With simple trigonometric functions we can determine that point:
float newX = point.x + (cos((2.f * PI / 360.f) * angle) * lenght);
float newY = point.y - (sin((2.f * PI / 360.f) * angle) * lenght); // Caution here! Minus(-) sign because we're drawing upwards
So we add this second point, and then split the tree into 2 new branches, each one rotated some certain degrees:
// Add second point
tree.append(sf::Vertex(nextPoint, treeColor));
// Create sub-tree from 2nd point, rotating +45 degrees (i.e. counterclockwise), reducing lenght of the new branch by 0.6 factor
createTreeRecursive(tree, nextPoint, angle + O, lenght * R);
// Same with the other sub-tree, but rotating -45 (i.e. clockwise)
createTreeRecursive(tree, nextPoint, angle - O, lenght * R);
We need a base case for our recursive function, in this case, I choose 3 as minimum lenght:
if (lenght < 3)
// End condition, can be modified
return;
this must be out first check.
So we're done, we only need the initial call:
sf::VertexArray createTree(){
// Our tree will be made out of lines
sf::VertexArray ret(sf::PrimitiveType::Lines);
// Initial point at botton-center(250, 450), with a 90 degrees rotation, first branch lenght 200
createTreeRecursive(ret, sf::Vector2f(250, 450), 90, 200);
return ret;
}
And the result is:
Full code
#include <SFML/Graphics.hpp>
const double PI = 3.141592;
const double R = 0.57; // Reduction factor
const double O = 45; // Degree rotation each time
sf::Color treeColor = sf::Color::Blue;
void createTreeRecursive(sf::VertexArray &tree, sf::Vector2f point, float angle, float lenght){
if (lenght < 3)
// End condition, can be modified
return;
// Add first point
tree.append(sf::Vertex(point, treeColor));
float newX = point.x + (cos((2.f * PI / 360.f) * angle) * lenght);
float newY = point.y - (sin((2.f * PI / 360.f) * angle) * lenght); // Caution here! Minus(-) sign because we're drawing upwards
sf::Vector2f nextPoint(newX, newY);
// Add second point
tree.append(sf::Vertex(nextPoint, treeColor));
// Create sub-tree from 2nd point, rotating +45 degrees (i.e. counterclockwise), reducing lenght of the new branch by 0.6 factor
createTreeRecursive(tree, nextPoint, angle + O, lenght * R);
// Same with the other sub-tree, but rotating -45 (i.e. clockwise)
createTreeRecursive(tree, nextPoint, angle - O, lenght * R);
}
sf::VertexArray createTree(){
// Our tree will be made out of lines
sf::VertexArray ret(sf::PrimitiveType::Lines);
// Initial point at bottom-center(250, 450), with a 90 degrees rotation, first branch lenght 200
createTreeRecursive(ret, sf::Vector2f(250, 450), 90, 200);
return ret;
}
int main()
{
RenderWindow window({ 500, 500 }, "SFML Tree", Style::Close);
auto tree = createTree();
while (window.isOpen())
{
for (Event event; window.pollEvent(event);){
if (event.type == Event::Closed)
window.close();
}
window.clear();
window.draw(tree);
window.display();
}
return EXIT_SUCCESS;
}
I would advice you to use recursion with a function that 1) draws the current branch (as a line), and then 2) creates two new branches from the current branch. Using global variables doesn't help you either. Looks like you should rethink your approach.
For Linux is:
#include <SFML/Graphics.hpp>
#include <cmath>
const double PI = 3.141592;
const double R = 0.57;
const double O = 45;
sf::Color treeColor = sf::Color::Blue;
void createTreeRecursive(sf::VertexArray &tree, sf::Vector2f point, float angle, float lenght){
if (lenght < 3)
return;
tree.append(sf::Vertex(point, treeColor));
float newX = point.x + (cos((2.f * PI / 360.f) * angle) * lenght);
float newY = point.y - (sin((2.f * PI / 360.f) * angle) * lenght);
sf::Vector2f nextPoint(newX, newY);
tree.append(sf::Vertex(nextPoint, treeColor));
createTreeRecursive(tree, nextPoint, angle + O, lenght * R);
createTreeRecursive(tree, nextPoint, angle - O, lenght * R);
}
sf::VertexArray createTree(){
sf::VertexArray ret(sf::PrimitiveType::Lines);
createTreeRecursive(ret, sf::Vector2f(250, 450), 90, 200);
return ret;
}
int main()
{
sf::RenderWindow window({ 500, 500 }, "SFML Tree", sf::Style::Close);
auto tree = createTree();
while (window.isOpen())
{
for (sf::Event event; window.pollEvent(event);){
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(tree);
window.display();
}
return EXIT_SUCCESS;
}

LOGO Turtle-like in C++, drawing curves

I am creating a LOGO Turtle-like object in C++ using the CImg library. When attempting to draw a circle, defined as the commands repeat 360[fd 1 rt1] which loops 360 times, moving forward 1 pixel and turning right 1 degree each iteration. With my code though I am getting a more octagonal shape rather than an actual circle.
Code for moving forward:
void turtle::fd(int distance)
{
int endx, endy;
endx = posx-(int)round((distance*sin(heading * PI / 180)));
endy = posy-(int)round((distance*cos(heading * PI / 180)));
if(pen)
window->draw_line(posx, posy, endx, endy, color1, 1);
posx=endx;
posy=endy;
}
In CImg, draw_line() will draw a line from position posx posy to endx endy, the rest is color and opacity.
And for turning right:
void turtle::rt(int degree)
{
heading -= degree;
if(heading < 0)
heading = (360-abs(heading));
}

OpenGL draw circle, weird bugs

I'm no mathematician, but I need to draw a filled in circle.
My approach was to use someone else's math to get all the points on the circumference of a circle, and turn them into a triangle fan.
I need the vertices in a vertex array, no immediate mode.
The circle does appear. However, when I try and overlay circles strange things happen. They appear only a second and then disappear. When I move my mouse out of the window a triangle sticks out from nowhere.
Here's the class:
class circle
{
//every coordinate with have an X and Y
private:
GLfloat *_vertices;
static const float DEG2RAD = 3.14159/180;
GLfloat _scalex, _scaley, _scalez;
int _cachearraysize;
public:
circle(float scalex, float scaley, float scalez, float radius, int numdegrees)
{
//360 degrees, 2 per coordinate, 2 coordinates for center and end of triangle fan
_cachearraysize = (numdegrees * 2) + 4;
_vertices = new GLfloat[_cachearraysize];
for(int x= 2; x < (_cachearraysize-2); x = x + 2)
{
float degreeinRadians = x*DEG2RAD;
_vertices[x] = cos(degreeinRadians)*radius;
_vertices[x + 1] = sin(degreeinRadians)*radius;
}
//get the X as X of 0 and X of 180 degrees, subtract to get diameter. divide
//by 2 for radius and add back to X of 180
_vertices[0]= ((_vertices[2] - _vertices[362])/2) + _vertices[362];
//same idea for Y
_vertices[1]= ((_vertices[183] - _vertices[543])/2) + _vertices[543];
//close off the triangle fan at the same point as start
_vertices[_cachearraysize -1] = _vertices[0];
_vertices[_cachearraysize] = _vertices[1];
_scalex = scalex;
_scaley = scaley;
_scalez = scalez;
}
~circle()
{
delete[] _vertices;
}
void draw()
{
glScalef(_scalex, _scaley, _scalez);
glVertexPointer(2,GL_FLOAT, 0, _vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, _cachearraysize);
}
};
That's some ugly code, I'd say - lots of magic numbers et cetera.
Try something like:
struct Point {
Point(float x, float y) : x(x), y(y) {}
float x, y;
};
std::vector<Point> points;
const float step = 0.1;
const float radius = 2;
points.push_back(Point(0,0));
// iterate over the angle array
for (float a=0; a<2*M_PI; a+=step) {
points.push_back(cos(a)*radius,sin(a)*radius);
}
// duplicate the first vertex after the centre
points.push_back(points.at(1));
// rendering:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2,GL_FLOAT,0, &points[0]);
glDrawArrays(GL_TRIANGLE_FAN,0,points.size());
It's up to you to rewrite this as a class, as you prefer. The math behind is really simple, don't fear to try and understand it.