Code about a particle bouncing on a curved surface - c++

I'm supposed to write a code that simulates an inelastic particle bouncing within a wall and a semicircle (radius 30, center # (50,0). The particle loses 3% of its original velocity every time it hits a wall and/or the semicircle.
I'm also using graphics.h library
I have made most of the program already, but the particle does not properly bounce on the semicircle.
I used the reflection matrix:
\begin{bmatrix}
cos 2\theta & sin2\theta \
sin2 \theta & -cos2\theta
\end{bmatrix}
here is the this snippet of the code containing the conditions when the particle hits the semicircle:
//initial conditions
x = 0;
y = 100;
Vx = 15.0;
Vy = 0.0;
double dt = 0.0001; //initial time step and increment
for(double t = 0; t < 50; t += dt)
{
Vy = Vy + grav*dt;
//Conditions when the particle hits a wall or the floor and retaining only 97% of its speed
if (y<0.0)
{
Vy = -Vy + grav*dt;
}
if(x >100.0 || x < 0.0)
{
Vx = -Vx;
}
//condition when the particle hits the semicircle
//semicircle equation: y = sqrt(30^2 - (x-50)^2)
if(y < sqrt((30*30)-((x-50)*(x-50))) )
{
Vxnew = ((Vx)*(cos(2.0*theta)) + (Vy*(sin(2.0*theta))));
Vy = (Vy*(cos(2.0*theta)) - ((Vx)*(sin(2.0*theta))));
Vx = Vxnew;
}
x = x + Vx*dt;
y = y + Vy*dt;
putpixel(conx(x), cony(y), 15);
}
I'm not sure if this reflection matrix applies on curved surfaces and I should use something else or my implementation is wrong.
For the losing the velocity part, I can probably just multiply the new x and y velocities by 0.97.
For context, this function that I made converts the calculated value in the loop to pixel values
//convert to pixel value (scale of 6)
double conx(double x)
{
return x * (600/100) + 50;
}
double cony(double y)
{
return -y * (600/100) + 650;
}

Related

Is there a method to either recalculate and equation in terms of a different variable?

I am currently a senior in AP Calculus BC and have taken the challenge of replicating a topic in C++ Qt. This topic covers integrals as area beneath a curve, and rotations of said areas to form a solid model with a definite volume.
I have successfully rotated a custom equation defined as:
double y = abs(qSin(qPow(graphXValue,graphXValue))/qPow(2, (qPow(graphXValue,graphXValue)-M_PI/2)/M_PI))
OR
My question is how to rotate such an equation around the Y-Axis instead of the X-Axis. Are there any methods to approximate the solving of this equation in terms of y instead of x? Are there any current implementations of such a task?
Keep in mind, I am calculating each point for the transformation in a 3D coordinate system:
for (float x = 0.0f; x < t_functionMaxX - t_projectionStep; x+=t_projectionStep)
{
currentSet = new QSurfaceDataRow;
nextSet = new QSurfaceDataRow;
float x_pos_mapped = x;
float y_pos_mapped = static_cast<float>(ui->customPlot->graph(0)->data()->findBegin(static_cast<double>(x), true)->value);
float x_pos_mapped_ahead = x + t_projectionStep;
float y_pos_mapped_ahead = static_cast<float>(graph1->data()->findBegin(static_cast<double>(x + t_projectionStep), true)->value);
QList<QVector3D> temp_points;
for (float currentRotation = static_cast<float>(-2*M_PI); currentRotation < static_cast<float>(2*M_PI); currentRotation += static_cast<float>((1) * M_PI / 180))
{
float y_pos_calculated = static_cast<float>(qCos(static_cast<qreal>(currentRotation))) * y_pos_mapped;
float z_pos_calculated = static_cast<float>(qSin(static_cast<qreal>(currentRotation))) * y_pos_mapped;
float y_pos_calculated_ahead = static_cast<float>(qCos(static_cast<qreal>(currentRotation))) * y_pos_mapped_ahead;
float z_pos_calculated_ahead = static_cast<float>(qSin(static_cast<qreal>(currentRotation))) * y_pos_mapped_ahead;
QVector3D point(x_pos_mapped, y_pos_calculated, z_pos_calculated);
QVector3D point_ahead(x_pos_mapped_ahead, y_pos_calculated_ahead, z_pos_calculated_ahead);
*currentSet << point;
*nextSet << point_ahead;
temp_points << point;
}
*data << currentSet << nextSet;
points << temp_points;
}
Essentially, you rotate the vector (x,f(x),0) around the Y axis, so the Y value remains the same but the X and Y parts vary according to rotation.
I also replaced all the static_cast<float> parts by explicit invocations of the float constructor, which (I find) reads a bit better.
// Render the upper part, grow from the inside
for (float x = 0.0f; x < t_functionMaxX - t_projectionStep; x+=t_projectionStep)
{
currentSet = new QSurfaceDataRow;
nextSet = new QSurfaceDataRow;
float x_pos_mapped = x;
float y_pos_mapped = float(ui->customPlot->graph(0)->data()->findBegin(double(x), true)->value);
float x_pos_mapped_ahead = x + t_projectionStep;
float y_pos_mapped_ahead = float(graph1->data()->findBegin(double(x + t_projectionStep), true)->value);
QList<QVector3D> temp_points;
for (float currentRotation = float(-2*M_PI); currentRotation < float(2*M_PI); currentRotation += float((1) * M_PI / 180))
{
float x_pos_calculated = float(qCos(qreal(currentRotation))) * x_pos_mapped;
float z_pos_calculated = float(qSin(qreal(currentRotation))) * x_pos_mapped;
float x_pos_calculated_ahead = float(qCos(qreal(currentRotation))) * x_pos_mapped_ahead;
float z_pos_calculated_ahead = float(qSin(qreal(currentRotation))) * x_pos_mapped_ahead;
QVector3D point(x_pos_calculated, y_pos_mapped, z_pos_calculated);
QVector3D point_ahead(x_pos_calculated_ahead, y_pos_mapped_ahead, z_pos_calculated_ahead);
*currentSet << point;
*nextSet << point_ahead;
temp_points << point;
}
*data << currentSet << nextSet;
points << temp_points;
}
Next, you need to add the bottom "plate". This is simply a bunch of triangles that connect (0,0,0) with two adjacent points of the rotation of (1,0,0) around the Y axis, just like we did above.
Finally, if f(t_functionmaxX) is not zero, you need to add a side that connects (t_functionmaxX, f(t_functionmaxX), 0) to (t_functionmaxX, 0, 0), again rotating in steps around the Y axis.
Note that this will do weird things if y < 0. How you want to solve that is up to you.

How to scale the rotation of a quaternion

I am trying to do the equivalent of multiplying the velocity by the time between frames. I would imagine that doing this for quaternions would be done by raising them to a power. I have code to rotate an object based on my mouse movements. It has a main loop running at one frame rate and a physics loop running at a fixed frame rate. Here is the relevant part of the main loop:
glfwPollEvents();
Input::update();
window.clear(0,0,0,1);
rigidBody.angularVelocity *= glm::angleAxis(0.001f * Input::deltaMouse().x, glm::vec3(0,1,0));
rigidBody.angularVelocity *= glm::angleAxis(0.001f * Input::deltaMouse().y, glm::vec3(1,0,0));
if(Input::getKey(Input::KEY_A))
{
rigidBody.velocity -= float(Time::getDelta()) * glm::vec3(1,0,0);
}
if(Input::getKey(Input::KEY_D))
{
rigidBody.velocity += float(Time::getDelta()) * glm::vec3(1,0,0);
}
if(Input::getKey(Input::KEY_W))
{
rigidBody.velocity -= float(Time::getDelta()) * glm::vec3(0,0,1);
}
if(Input::getKey(Input::KEY_S))
{
rigidBody.velocity += float(Time::getDelta()) * glm::vec3(0,0,1);
}
if(Input::getKey(Input::KEY_LCONTROL))
{
rigidBody.velocity -= float(Time::getDelta()) * glm::vec3(0,1,0);
}
if(Input::getKey(Input::KEY_LSHIFT))
{
rigidBody.velocity += float(Time::getDelta()) * glm::vec3(0,1,0);
}
Here is the relevant part of the physics loop:
for(int i = 0; i < *numRigidBodies; i++)
{
rigidBodies[i].transform->getPos() += rigidBodies[i].velocity;
rigidBodies[i].transform->getRot() *= rigidBodies[i].angularVelocity;
}
rigidBodies[0].angularVelocity = glm::quat();
rigidBodies[0].velocity = glm::vec3();
This works fine, but when I try raising angular velocity to a power with glm::pow, the object rotates randomly and does not follow my mouse. I realize I could do this with a line of code like
rigidBodies[i].transform->getRot() *= glm::angleAxis((float)Time::getFixedDelta() * glm::angle(rigidBodies[i].angularVelocity), glm::axis(rigidBodies[i].angularVelocity));
but this seems needlessly complicated for the task. What is causing this issue, and how can I fix it?
Not sure exactly how to do it with the API you're using, but basically, you would use Quaternion::Slerp(). Slerp means "spherical linear interpolation".
Something like this(pseudocode) should work:
auto& rot = rigidBodies[i].transform->getRot();
auto goal = rigidBodies[i].angularVelocity * rot;
rot = rot.slerp(rot, goal, Time::deltaTime);
Edit:
I should note that this is not how I would approach this problem. I would just store the rotation around the X and Y axis as scalars and construct a new quaternion from them each frame.
Please excuse the sloppy pseudo code:
// previous x and y positions, could probably be set in MouseDown event
float lastX = ...;
float lastY = ...;
float xRotation = 0;
float yRotation = 0;
float rotationSpeed = 1.0;
void OnMouseMove(float x, float y) {
float dx = x - lastX;
float dy = y - lastY;
lastX = x;
lastY = y;
xRotation += dy * rotationSpeed * Time::deltaTime;
yRotation += dx * rotationSpeed * Time::deltaTime;
rigidBodies[i].transform->getRot() = eulerQuat(xRotation, yRotation, 0);
}
Turns out angular velocity is usually represented as a 3d vector where the direction is the axis and the magnitude is the angular speed. Replace this line of code:
rigidBodies[i].transform->getRot() *= rigidBodies[i].angularVelocity;
with this:
if(rigidBodies[i].angularVelocity != glm::vec3())
rigidBodies[i].transform->getRot() *= glm::quat(rigidBodies[i].angularVelocity * float(Time::getFixedDelta()));
and the physics system works as expected. The if check makes sure that angular speed is not 0.

Rotating around a sphere using OpenGL and gluLookAt

Alright, so I'm trying to click and drag to rotate around an object using C++ and OpenGL. The way I have it is to use gluLookAt centered at the origin and I'm getting coordinates for the eye by using parametric equations for a sphere (eyex = 2* cos(theta) * sin(phi); eyey = 2* sin(theta) * sin(phi); eyez = 2* cos(phi);). This works mostly, as I can click and rotate horizontally, but when I try to rotate vertically it makes tight circles instead of rotating vertically. I'm trying to get the up vector by using the position of the camera and a vecter at a 90 degree angle along the x-z plane and taking the cross product of that.
The code I have is as follows:
double dotProduct(double v1[], double v2[]) {
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void mouseDown(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
xpos = x;
ypos = y;
}
}
void mouseMovement(int x, int y) {
diffx = x - xpos;
diffy = y - ypos;
xpos = x;
ypos = y;
}
void camera (void) {
theta += 2*PI * (-diffy/glutGet(GLUT_SCREEN_HEIGHT));
phi += PI * (-diffx/glutGet(GLUT_WINDOW_WIDTH));
eyex = 2* cos(theta) * sin(phi);
eyey = 2* sin(theta) * sin(phi);
eyez = 2* cos(phi);
double rightv[3], rightt[3], eyes[3];
rightv[0] = 2* cos(theta + 2/PI) * sin(phi);
rightv[1] = 0;
rightv[2] = 2* cos(phi);
rightt[0] = rightv[0];
rightt[1] = rightv[1];
rightt[2] = rightv[2];
rightv[0] = rightv[0] / sqrt(dotProduct(rightt, rightt));
rightv[1] = rightv[1] / sqrt(dotProduct(rightt, rightt));
rightv[2] = rightv[2] / sqrt(dotProduct(rightt, rightt));
eyes[0] = eyex;
eyes[1] = eyey;
eyes[2] = eyez;
upx = (eyey/sqrt(dotProduct(eyes,eyes)))*rightv[2] + (eyez/sqrt(dotProduct(eyes,eyes)))*rightv[1];
upy = (eyez/sqrt(dotProduct(eyes,eyes)))*rightv[0] + (eyex/sqrt(dotProduct(eyes,eyes)))*rightv[2];
upz = (eyex/sqrt(dotProduct(eyes,eyes)))*rightv[1] + (eyey/sqrt(dotProduct(eyes,eyes)))*rightv[0];
diffx = 0;
diffy = 0;
}
I am somewhat basing things off of this but it doesn't work, so I tried my way instead.
This isn't exactly a solution for the way you are doing it but I did something similar the other day. I did it by using DX's D3DXMatrixRotationAxis and D3DXVec3TransformCoord The math behind the D3DXMatrixRotationAxis method can be found at the bottom of the following page: D3DXMatrixRotationAxis Math use this if you are unable to use DX. This will allow you to rotate around any axis you pass in. In my object code I keep track of a direction and up vector and I simply rotate each of these around the axis of movement(in your case the yaw and pitch).
To implement the fixed distance camera like this I would simply do the dot product of the current camera location and the origin location (if this never changes then you can simply do it once.) and then move the camera to the origin rotate it the amount you need then move it back with its new direction and up values.

Bullet algorithm having trouble with rotation on the X

Here is what I'm trying to do. I'm trying to make a bullet out of the center of the screen. I have an x and y rotation angle. The problem is the Y (which is modified by rotation on the x) is really not working as intended. Here is what I have.
float yrotrad, xrotrad;
yrotrad = (Camera.roty / 180.0f * 3.141592654f);
xrotrad = (Camera.rotx / 180.0f * 3.141592654f);
Vertex3f Pos;
// get camera position
pls.x = Camera.x;
pls.y = Camera.y;
pls.z = Camera.z;
for(float i = 0; i < 60; i++)
{
//add the rotation vector
pls.x += float(sin(yrotrad)) ;
pls.z -= float(cos(yrotrad)) ;
pls.y += float(sin(twopi - xrotrad));
//translate camera coords to cube coords
Pos.x = ceil(pls.x / 3);
Pos.y = ceil((pls.y) / 3);
Pos.z = ceil(pls.z / 3);
if(!CubeIsEmpty(Pos.x,Pos.y,Pos.z)) //remove first cube that made contact
{
delete GetCube(Pos.x,Pos.y,Pos.z);
SetCube(0,Pos.x,Pos.y,Pos.z);
return;
}
}
This is almost identical to how I move the player, I add the directional vector to the camera then find which cube the player is on. If I remove the pls.y += float(sin(twopi - xrotrad)); then I clearly see that on the X and Z, everything is pointing as it should. When I add pls.y += float(sin(twopi - xrotrad)); then it almost works, but not quite, what I observed from rendering out spheres of the trajector is that the furthur up or down I look, the more offset it becomes rather than stay alligned to the camera's center. What am I doing wrong?
Thanks
What basically happens is very difficult to explain, I'd expect the bullet at time 0 to always be at the center of the screen, but it behaves oddly. If i'm looking straight at the horizon to +- 20 degrees upward its fine but then it starts not following any more.
I set up my matrix like this:
void CCubeGame::SetCameraMatrix()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(Camera.rotx,1,0,0);
glRotatef(Camera.roty,0,1,0);
glRotatef(Camera.rotz,0,0,1);
glTranslatef(-Camera.x , -Camera.y,-Camera.z );
}
and change the angle like this:
void CCubeGame::MouseMove(int x, int y)
{
if(!isTrapped)
return;
int diffx = x-lastMouse.x;
int diffy = y-lastMouse.y;
lastMouse.x = x;
lastMouse.y = y;
Camera.rotx += (float) diffy * 0.2;
Camera.roty += (float) diffx * 0.2;
if(Camera.rotx > 90)
{
Camera.rotx = 90;
}
if(Camera.rotx < -90)
{
Camera.rotx = -90;
}
if(isTrapped)
if (fabs(ScreenDimensions.x/2 - x) > 1 || fabs(ScreenDimensions.y/2 - y) > 1) {
resetPointer();
}
}
You need to scale X and Z by cos(xradrot). (In other words, multiply by cos(xradrot)).
Imagine you're pointing straight down the Z axis but looking straight up. You don't want the bullet to shoot down the Z axis at all, this is why you need to scale it. (It's basically the same thing that you're doing between X and Z, but now doing it on the XZ vector and Y.)
pls.x += float(sin(yrotrad)*cos(xrotrad)) ;
pls.z -= float(cos(yrotrad)*cos(xrotrad)) ;
pls.y += float(sin(twopi - xrotrad));

moving a sprite causes jerky movement

I've got some jerky movement of my sprite.
Basically, when the user touches a point on the screen, the sprite should move to that point. This is working mostly fine... it's even taking into account a delta - because frame rate may not be consistant.
However, I notice that the y movement usually finishes before the x movement (even when the distances to travel are the same), so it appears like the sprite is moving in an 'L' shape rather than a smooth diagonal line.
Vertical and horizontal velocity (vx, vy) are both set to 300. Any ideas what's wrong? How can I go about getting my sprite to move in a smooth diagonal line?
- (void)update:(ccTime)dt
{
int x = self.position.x;
int y = self.position.y;
//if ball is to the left of target point
if (x<targetx)
{
//if movement of the ball won't take it to it's target position
if (x+(vx *dt) < targetx)
{
x += vx * dt;
}
else {
x = targetx;
}
} else if (x>targetx) //same with x being too far to the right
{
if (x-(vx *dt) > targetx)
{
x -= vx * dt;
}
else {
x = targetx;
}
}
if (y<targety)
{
if (y+(vy*dt)<targety)
{
y += vy * dt;
}
else {
y = targety;
}
} else if (y>targety)
{
if (y-(vy*dt)>targety)
{
y -= vy * dt;
}
else {
y = targety;
}
}
self.position = ccp(x,y);
}
You want to move to (targetx, targety) from any (x,y) and arrive at both coordinates at the same time (to avoid the "dogleg"). So, suppose the x velocity is vx and you get there in t seconds. That means vx = (targetx - x)/t. t must be the same for the y coordinate if you want smooth movement to the same point at the same time, so that means t = (targetx - x)/vx and vy must actually be (targety - y)*vx/(targetx - x).
In other words, you can't set vx and vy separately and get the result you want.