Simulation of a point mass in a box (3D space) - c++

I would like to simulate a point mass within a closed box. There is no friction and the point mass obeys the impact law. So there are only elastic collisions with the walls of the box. The output of the program is the time, position (rx,ry ,rz) and velocity (vx,vy,vz). I plot the trajectory by using GNUplot.
The problem I have now is, that the point mass gets energy from somewhere. So their jumps get each time more intense.
Is someone able to check my code?
/* Start of the code */
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
struct pointmass
{
double m; // mass
double r[3]; // coordinates
double v[3]; // velocity
};
// Grav.constant
const double G[3] = {0, -9.81, 0};
int main()
{
int Time = 0; // Duration
double Dt = 0; // Time steps
pointmass p0;
cerr << "Duration: ";
cin >> Time;
cerr << "Time steps: ";
cin >> Dt;
cerr << "Velocity of the point mass (vx,vy,vz)? ";
cin >> p0.v[0];
cin >> p0.v[1];
cin >> p0.v[2];
cerr << "Initial position of the point mass (x,y,z)? ";
cin >> p0.r[0];
cin >> p0.r[1];
cin >> p0.r[2];
for (double i = 0; i<Time; i+=Dt)
{
cout << i << setw(10);
for (int j = 0; j<=2; j++)
{
////////////position and velocity///////////
p0.r[j] = p0.r[j] + p0.v[j]*i + 0.5*G[j]*i*i;
p0.v[j] = p0.v[j] + G[j]*i;
///////////////////reflection/////////////////
if(p0.r[j] >= 250)
{
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -p0.v[j];
}
else if(p0.r[j] <= 0)
{
p0.r[j] = -p0.r[j];
p0.v[j] = -p0.v[j];
}
//////////////////////////////////////////////
}
/////////////////////Output//////////////////
for(int j = 0; j<=2; j++)
{
cout << p0.r[j] << setw(10);
}
for(int j = 0; j<=2; j++)
{
cout << p0.v[j] << setw(10);
}
///////////////////////////////////////////////
cout << endl;
}
}

F = ma
a = F / m
a dt = F / m dt
a dt is acceleration over a fixed time - the change in velocity for that frame.
You are setting it to F / m i
it is that i which is wrong, as comments have suggested. It needs to be the duration of a frame, not the duration of the entire simulation so far.

I am a little concerned about the time loop along with other commenters - make sure that it represents an increment of time, not a growing duration.
Still, I think the main problem is you are changing the sign of all three components of velocity
on reflection.
That's not consistent with the laws of physics -conservation of linear momentum and energy - at the boundaries.
To see this, consider the case if your particle is moving in just the x-y plane (velocity in z is zero) and about to hit the wall at x= L.
The collision looks like this:
The force exerted on the point mass by the wall acts perpendicular to the wall. So there is no change in the momentum component of the particle parallel to the wall.
Applying conservation of linear momentum and kinetic energy, and assuming a perfectly elastic collision, you will find that
The component of velocity perpendicular to the wall DOES change sign
The component of velocity parallel to the wall DOES NOT change sign
In three dimensions, to have an accurate simulation, you have to work out the momentum components parallel and perpendicular to the wall on collision and code the resulting velocity changes.
In other words, this code:
///////////////////reflection/////////////////
if(p0.r[j] >= 250)
{
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -p0.v[j];
}
else if(p0.r[j] <= 0)
{
p0.r[j] = -p0.r[j];
p0.v[j] = -p0.v[j];
}
//////////////////////////////////////////////
does not model the physics of reflection correctly. To fix it here is an outline of what to do:
Take the reflection checks out of the loop over x,y,z coordinates (but still within the time loop)
The collision condition for all six walls needs to be checked,
according to the direction of the normal vector to the wall.
For example for the right wall of the cube defined by X=250, 0<=Y<250, 0<=Z<250, the normal vector is in the negative X direction. For the left wall defined by X=0, 0<=Y<250, 0<=Z<250, the normal vector is in the positive X direction.
So on reflection from those two walls, the X component of velocity changes sign because it is normal (perpendicular) to the wall, but the Y and Z components do NOT change sign because they are parallel to the wall.
Apply similar considerations at the top and bottom wall (constant Y), and front and back wall (constant Z), of the cube -left as exercise to work out the normals to those surfaces.
Finally you shouldn't change sign of the position vector components on reflection, just the velocity vector. Instead recompute the next value of the position vector given the new velocity.

OK, so there are a few issues. The others have pointed out the need to use Dt rather than i for the integration step.
However, you are correct in stating that there is an issue with the reflection and energy conservation. I've added an explicit track of that below.
Note that the component wise computation of the reflection is actually fine other than the energy issue.
The problem was that during a reflection the acceleration due to gravity changes. In the case of the particle hitting the floor, it was acquiring kinetic energy equal to that it would have had if it had kept falling, but the new position had higher potential energy. So the energy would increase by exactly twice the potential energy difference between the floor and the new position. A bounce off the roof would have the opposite effect.
As noted below, once strategy would be to compute the actual time of reflection. However, actually working directly with energy is much simpler as well as more robust. However, please note although the the simple energy version below ensures that the speed and position are consistent, it actually does not have the correct position. For most purposes that may not actually matter. If you really need the correct position, I think we need to solve for the bounce time.
/* Start of the code */
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
struct pointmass
{
double m; // mass
double r[3]; // coordinates
double v[3]; // velocity
};
// Grav.constant
const double G[3] = { 0, -9.81, 0 };
int main()
{
// I've just changed the initial values to speed up unit testing; your code worked fine here.
int Time = 50; // Duration
double Dt = 1; // Time steps
pointmass p0;
p0.v[0] = 23;
p0.v[1] = 40;
p0.v[2] = 15;
p0.r[0] = 100;
p0.r[1] = 200;
p0.r[2] = 67;
for (double i = 0; i<Time; i += Dt)
{
cout << setw(10) << i << setw(10);
double energy = 0;
for (int j = 0; j <= 2; j++)
{
double oldR = p0.r[j];
double oldV = p0.v[j];
////////////position and velocity///////////
p0.r[j] = p0.r[j] + p0.v[j] * Dt + 0.5*G[j] * Dt*Dt;
p0.v[j] = p0.v[j] + G[j] * Dt;
///////////////////reflection/////////////////
if (G[j] == 0)
{
if (p0.r[j] >= 250)
{
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -p0.v[j];
}
else if (p0.r[j] <= 0)
{
p0.r[j] = -p0.r[j];
p0.v[j] = -p0.v[j];
}
}
else
{
// Need to capture the fact that the acceleration switches direction relative to velocity half way through the timestep.
// Two approaches, either
// Try to compute the time of the bounce and work out the detail.
// OR
// Use conservation of energy to get the right speed - much easier!
if (p0.r[j] >= 250)
{
double energy = 0.5*p0.v[j] * p0.v[j] - G[j] * p0.r[j];
p0.r[j] = 500 - p0.r[j];
p0.v[j] = -sqrt(2 * (energy + G[j] * p0.r[j]));
}
else if (p0.r[j] <= 0)
{
double energy = 0.5*p0.v[j] * p0.v[j] - G[j] * p0.r[j];
p0.r[j] = -p0.r[j];
p0.v[j] = sqrt(2*(energy + G[j] * p0.r[j]));
}
}
energy += 0.5*p0.v[j] * p0.v[j] - G[j] * p0.r[j];
}
/////////////////////Output//////////////////
cout << energy << setw(10);
for (int j = 0; j <= 2; j++)
{
cout << p0.r[j] << setw(10);
}
for (int j = 0; j <= 2; j++)
{
cout << p0.v[j] << setw(10);
}
///////////////////////////////////////////////
cout << endl;
}
}

Related

Why doesn't my Gradient descent algorithm converge? (For Logistic Regression)

I have an assignment which says to implement logistic regression in c++ using gradient descent. Part of the assignment is to make the gradient descent stop when the magnitude of the gradient is below 10e-07.
I have to minimize: //chart.googleapis.com/chart?cht=tx&chl=L(w)%20%3D%20%5Cfrac%7B1%7D%7BN%7D%5Csum%20log(1%20%2B%20exp(-y_%7Bi%7Dw%5E%7BT%7Dx_%7Bi%7D))
However my gradient descent keeps stopping due to max iterations surpassed. I have tried with various max iteration thresholds, and they all max out. I think there is something wrong with my code, since logistic regression is supposedly an easy task for gradient descent due to the concave nature of its cost function, the gradient descent should easily find the minium.
I am using the armadillo library for matrices and vectors.
#include "armadillo.hpp"
using namespace arma;
double Log_Likelihood(Mat<double>& x, Mat<int>& y, Mat<double>& w)
{
Mat<double> L;
double L_sum = 0;
for (int i = 0; i < x.n_rows; i++)
{
L = log(1 + exp(-y[i] * w * x.row(i).t() ));
L_sum += as_scalar(L);
}
return L_sum / x.n_rows;
}
Mat<double> Gradient(Mat<double>& x, Mat<int>& y, Mat<double>& w)
{
Mat<double> grad(1, x.n_cols);
for (int i = 0; i < x.n_rows; i++)
{
grad = grad + (y[i] * (1 / (1 + exp(y[i] * w * x.row(i).t()))) * x.row(i));
}
return -grad / x.n_rows;
}
void fit(Mat<double>& x, Mat<int>& y, double alpha = 0.05, double threshold = pow(10, -7), int maxiter = 10000)
{
w.set_size(1, x.n_cols);
w = x.row(0);
int iter = 0;
double log_like = 0;
while (true)
{
log_like = Log_Likelihood(x, y, w);
if (iter % 1000 == 0)
{
std::cout << "Iter: " << iter << " -Log likelihood = " << log_like << " ||dL/dw|| = " << norm( Gradient(x, y, w), 2) << std::endl;
}
iter++;
if ( norm( Gradient(x, y, w), 2) < threshold)
{
std::cout << "Magnitude of gradient below threshold." << std::endl;
break;
}
if (iter == maxiter)
{
std::cout << "Max iterations surpassed." << std::endl;
break;
}
w = w - (alpha * Gradient(x, y, w));
}
}
I want the gradient descent to stop because the magnitude of the gradient falls below 10e-07.
My labels are {1, -1}.
Verify that your loglikelihood is increasing towards convergence by recording or plotting the values at every iteration, and also check that the norm of the gradient is going towards 0. You should be doing gradient ascent, so add the gradient instead of subtracting it. If the norm of the gradient consistently increases it means you are not going in a direction towards the optimum. If on the other hand, the norm of the gradient "jumps around" but doesn't go to 0, then you should reduce your stepsize/learning rate alpha and try again.
Plotting and analyzing these values will be helpful to debug and analyze your algorithm.

Calculating 3D cartesian coordinates inside a cone

So what I am essentially trying to do here is arranging the 3D cartesian coordinates of points inside an inverted cone (radius decreases with height). The basic approach I have taken here is to have an integrally reducing height, h, and plotting points (x,y) that fall within a circle formed at height h. Since the radius of this circle is variable, I am using a simple similarity condition to determine that at every iteration. The initial height I have taken is 1000, the radius ought to initially be 3500. Also, these circles as centred at (0,0) [the z-axis passes through the vertex of the cone, and is perpendicular to the base]. Code isn't running properly, showing me an exit status of -1. Can anyone help me figure out if my implementation is off due to some size errors or something?
#include<bits/stdc++.h>
#define ll long long int
using namespace std;
int main(){
float top[1010][9000][3];
ll i = 0;
for(ll h = 999; h >=0; h--){
float r=(h+1)*(3.5);
for (ll x = floor(r) * (-1); x <= floor(r); x++){
for (ll y = floor(r) *(-1); y <= floor(r); y++){
if(pow(x,2) + pow(y,2) <= pow(floor(r),2)){
top[h][i][0] = x;
top[h][i][1] = y;
top[h][i][2] = 9.8;
i++;
}
}
}
i=0;
}
cout << "done";
for (ll m = 0; m < 1000; m++){
for(ll n = 0; n < 7000; n++){
if(top[m][n][2] == 9.8){
cout << top[m][n][0] << top[m][n][1];
}
}
}
}
You don't need to declare ll as long long int. The indexes you are using will fit inside of int.
Here's your problem: Change the code to this to see what's going on:
for(ll h = 999; h >=0; h--){
float r=(h+1)*(3.5);
for (ll x = floor(r) * (-1); x <= floor(r); x++){
for (ll y = floor(r) *(-1); y <= floor(r); y++){
if(pow(x,2) + pow(y,2) <= pow(floor(r),2)){
/* top[h][i][0] = x;
top[h][i][1] = y;
top[h][i][2] = 9.8; //*/
i++; // this gets really big
}
}
}
cout << "max i: " << i << endl;
i=0;
}
i gets really big and is indexing into a dimension that is only 9000.
Criticism of the code...
It looks like you are scanning the entire x,y,z block and 'testing' if the point is inside. If yes, saving the x,y coordinate of the point along with 9.8 (some field value?).
Perhaps you could forgo the float buffer and just print the {x,y} coordinates directly to see how your code works before attempting to save the output. redirect the output to a file and inspect.
cout << "{" << x << "," << y <<"}," << (i % 5 == 0 ? "\n" : " ");
Also, read up on why comparing floats with == doesn't work.

Modeling velocity and height of rocket c++

Hi We are supposed to model the height and velocity of a rocket in c++ for our final project. Having user input the total flight time and delta time for the points during flight that they wish to measure. The following is the code I have written for this project. The velocity is supposed to start positive and after 60 seconds at which point there is no fuel left and thus no thrust the velocity should start becoming negative. However both my height and velocity are coming out as negative from the start and reaching negative infinite by the end.
#include <iostream>
using namespace std;
int main()
{
float *v;
float *h;
float a;
double mass=0.0, thrust, time, dt;
double g = 32.2;
double K = 0.008;
cout << "enter time";
cin >> time;
cout << "enter dt";
cin >> dt;
a = (time/dt);
v = new float[a];
h = new float[a];
v[0] = 0;
h[0] = 0;
float tt = 0;
// for loop to calculate velocity and time
for(int i = 0; i <= (time/dt) ; i++)
{
tt = dt + tt;
if( tt <= 60)
{
mass = (3000-(40*tt)/g);
thrust = 7000;
}
if ( tt > 60)
{
mass = 3000/g;
thrust = 0;
}
// these are the formulas for velocity and height position our prof gave us
v[i+1] = v[i] - (K/mass)*v[i]*v[i-1] * dt + (thrust/mass - g)*dt;
h[i+1] = v[i+1] * dt + h[i];
}
// for loop to output
for(int i = 0; i <= (time/dt); i++)
{
cout << i << " - " << "Velocity:" << v[i+1] << " Position:" << h[i+1] <<endl;
}
return 0;
}
sample output:
enter time120
enter dt.01
0 - Velocity:-0.298667 Position:-0.00298667
1 - Velocity:-0.597333 Position:-0.00896
2 - Velocity:-0.895999 Position:-0.01792
3 - Velocity:-1.19467 Position:-0.0298666
4 - Velocity:-1.49333 Position:-0.0448
5 - Velocity:-1.792 Position:-0.0627199
6 - Velocity:-2.09066 Position:-0.0836266
7 - Velocity:-2.38933 Position:-0.10752
<...i left out a lot of numbers in the middle to not make this post too long...>
11994 - Velocity:-inf Position:-inf
11995 - Velocity:-inf Position:-inf
11996 - Velocity:-inf Position:-inf
11997 - Velocity:-inf Position:-inf
11998 - Velocity:-inf Position:-inf
11999 - Velocity:-inf Position:-inf
12000 - Velocity:-inf Position:-inf
Program ended with exit code: 0
I have compared with my friends who are getting good results and we can not determine a difference between their code and mine. I have the rest of my program complete and working fine I just cannot figure out why my calculations are wrong
Ignoring the out-of-bounds access to v[-1] when i is zero, there is something wrong with your thrust, mass, or g.
thrust is 7000, mass is 3000 at time = 0. That means thrust/mass is just over 2. With g=32 (really? you are doing rocketry calculations in imperial units?), that means the rocket never has enough thrust to counter gravity, and just sits on the pad.
Edit: That would be reality. Because this is a fairly simple simulation, and doesn't include a "pad", in the model the rocket starts free-falling to the centre of the earth.
You are using v[i-1] but i starts out at 0, therefore this calculation is going to use whatever happens to be at v[-1]. I suggest you initialize i to 1 (and then check all the uses of i to ensure that the correct array elements will be used).
I am not 100% convinced about the forumla, I dont understand why it contains a v[i] and a v[i-1] term. Anyhow, even if correct, in the first iteration (i==0) you are accesing out of bounds of the velocity array: v[i-1]. That is undefined behaviour.
To fix this, either review the formula, does it really contain a v[i-1] term? ..or start the iteration at i=1 (and initialize v[0] and v[1]).
Thank you guys for your help I was able to solve it.
#include <iostream>
using namespace std;
int main()
{
double *v;
double *h;
double g = 32.2;
double K = .008;
double mass;
double t;
double dt;
double tt = 0;
double thrust;
cout << "t \n";
cin >> t;
cout << "dt \n";
cin >> dt;
double a = t/dt;
v = new double[a];
h = new double[a];
v[0] = 0;
h[0] = 0;
for (int i = 0; i <= a; i++)
{
tt = tt+dt;
if( tt == 0)
{
thrust = 7000;
mass = (3000 -40*dt)/g;
v[i+1] = v[i] + ((thrust/mass)-g)*dt;
}
else if( tt > 0 && tt < 60)
{
thrust = 7000;
mass = (3000 - 40 *tt)/g;
v[i+1] = v[i] - ((K/mass)*v[i]*v[i-1] * dt) + ((thrust/mass) - g)*dt;
}
else if (tt > 60)
{
thrust = 0;
mass = 600/g;
v[i+1] = v[i] - ((K/mass)*v[i]*v[i-1] * dt) + ((thrust/mass) - g)*dt;
}
h[i+1] = v[i+1] * dt + h[i];
}
cout << " end results \n";
for(int i = 0; i <= a; i++)
{
cout << i << " v - " << v[i] << " h - " << h[i] <<endl;
}
return 0;
}
New results:
t
120
dt
.01
end results
0 v - 0 h - 0
1 v - 0.429434 h - 0.00429434
2 v - 0.858967 h - 0.012884
3 v - 1.2886 h - 0.02577
4 v - 1.71833 h - 0.0429534
5 v - 2.14817 h - 0.064435
6 v - 2.5781 h - 0.090216
7 v - 3.00813 h - 0.120297
You can see below at 60s where the velocity changes due to no more thrust
5997 - Velocity:890.361
5998 - Velocity:890.392
5999 - Velocity:890.422
6000 - Velocity:886.697
6001 - Velocity:882.985
6002 - Velocity:879.302

C++ Collision Detection causing objects to disappear

I am currently working on some basic 2D RigidBody Physics and have run into an issue. I have a function that checks for collision between a Circle and a AABB but sometimes the Circle (in this case the player) will collide then disappear and if I print out the position when this happens I just set "nan".
bool Game::Physics::RigidBody2D::CircleAABB(RigidBody2D& body)
{
sf::Vector2f diff = m_Position - body.m_Position;
sf::Vector2f halfExtents = sf::Vector2f(body.m_Size.x / 2.0f, body.m_Size.y / 2.0f);
sf::Vector2f diffContrained = diff;
if (diff.x > halfExtents.x)
{
diffContrained.x = halfExtents.x;
}
else if (diff.x < -halfExtents.x)
{
diffContrained.x = -halfExtents.x;
}
if (diff.y > halfExtents.y)
{
diffContrained.y = halfExtents.y;
}
else if (diff.y < -halfExtents.y)
{
diffContrained.y = -halfExtents.y;
}
sf::Vector2f colCheck = diff - diffContrained;
sf::Vector2f VDirNorm = NormVector(colCheck);
sf::Vector2f colToPlayer = NormVector(m_Position - (diffContrained + body.m_Position));
float dist = getMagnitude(colCheck) - m_fRadius;
//std::cout << dist << std::endl;
if (dist < 0)
{
OnCollision((diffContrained + body.m_Position) - m_Position);
m_Position += (VDirNorm * abs(dist));
body.m_Position -= (VDirNorm * abs(dist))* (1.0f - body.m_fMass);
return true; //Collision has happened
}
return false;
}
This happens randomly and with almost no clear reason although it seems to happen more often when the circle is moving fast but can happen as well when it is moving slowly or one or two times when it is not moving at all.
An added note is that I apply gravity to the Y velocity and on collision set the velocity of the coordinating axis to 0.
So my question is, is something clearly wrong here to those with more physics experience than me?
Note: Using SFML for drawing and Vector2 class physics code is all mine.
EDIT: The OnCollision function checks the side the collision so that objects that inherit can use this (e.g. check if the collision was below to trigger a "isGrounded" boolean). In the this case the player checks the side and then sets the velocity on that axis to 0 and also trigger a isGrounded boolean when it is below.
void Game::GamePlay::PlayerController::OnCollision(sf::Vector2f vDir)
{
if (abs(vDir.x) > abs(vDir.y))
{
if (vDir.x > 0.0f)
{
//std::cout << "Right" << std::endl;
//Collision on the right
m_Velocity.x = 0.0f;
}
if (vDir.x < 0.0f)
{
//std::cout << "Left" << std::endl;
//Collision on the left
m_Velocity.x = 0.0f;
}
return;
}
else
{
if (vDir.y > 0.0f)
{
//std::cout << "Below" << std::endl;
//Collision below
m_Velocity.y = 0.0f;
if (!m_bCanJump && m_RecentlyCollidedNode != nullptr)
{
m_RecentlyCollidedNode->ys += 3.f;
}
m_bCanJump = true;
}
if (vDir.y < 0.0f)
{
//std::cout << "Above" << std::endl;
//Collision above
m_Velocity.y = 0.0f;
}
}
}
From debugging out velocity and position no real reason has come to the surface.
inline sf::Vector2f NormVector(sf::Vector2f vec)
{
float mag = getMagnitude(vec);
return vec / mag;
}
Solution:
if (colCheck.x == 0 && colCheck.y == 0)
{
std::cout << "Zero Vector" << std::endl;
float impulse = m_Velocity.x + m_Velocity.y;
m_Velocity.x = 0;
m_Velocity.y = 0;
m_Velocity += NormVector(diff)*impulse;
}
else
{
VDirNorm = NormVector(colCheck);
dist = getMagnitude(colCheck) - m_fRadius;
}
One issue I see is NormVector with a zero vector. You'll divide by zero, generating NaNs in your returned vector. This can happen in your existing code when diff and diffContrained are the same, so colCheck will be (0,0) causing VDirNorm to have NaNs in it, which will propagate into m_position.
Typically, a normalized zero length vector should stay a zero length vector (see this post), but in this case, since you're using the normalized vector to offset your bodies after the collision, you'll need to add code to handle it in a reasonable fashion.

Need floating point precision, GUI gui uses int

I have a flow layout. Inside it I have about 900 tables. Each table is stacked one on top of the other. I have a slider which resizes them and thus causes the flow layout to resize too.
The problem is, the tables should be linearly resizing. Their base size is 200x200. So when scale = 1.0, the w and h of the tables is 200.
I resize by a fixed amount each time making them 4% bigger each time. This means I would expect them to grow by 8 pixels each time. What happens is, every few resizes, the tables grow by 9 pixels. I use doubles everywhere. I have tried rounding, floor and ceil but the problem persists. What could I do so that they always grow by the correct amount?
void LobbyTableManager::changeTableScale( double scale )
{
setTableScale(scale);
}
void LobbyTableManager::setTableScale( double scale )
{
scale += 0.3;
scale *= 2.0;
std::cout << scale << std::endl;
agui::Gui* gotGui = getGui();
float scrollRel = m_vScroll->getRelativeValue();
setScale(scale);
rescaleTables();
resizeFlow();
...
double LobbyTableManager::getTableScale() const
{
return (getInnerWidth() / 700.0) * getScale();
}
void LobbyFilterManager::valueChanged( agui::Slider* source,int val )
{
if(source == m_magnifySlider)
{
DISPATCH_LOBBY_EVENT
{
(*it)->changeTableScale((double)val / source->getRange());
}
}
}
void LobbyTableManager::renderBG( GraphicsContext* g, agui::Rectangle& absRect, agui::Rectangle& childRect )
{
int cx, cy, cw, ch;
g->getClippingRect(cx,cy,cw,ch);
g->setClippingRect(absRect.getX(),absRect.getY(),absRect.getWidth(),absRect.getHeight());
float scale = 0.35f;
int w = m_bgSprite->getWidth() * getTableScale() * scale;
int h = m_bgSprite->getHeight() * getTableScale() * scale;
int numX = ceil(absRect.getWidth() / (float)w) + 2;
int numY = ceil(absRect.getHeight() / (float)h) + 2;
float offsetX = m_activeTables[0]->getLocation().getX() - w;
float offsetY = m_activeTables[0]->getLocation().getY() - h;
int startY = childRect.getY() + 1;
if(moo)
{
std::cout << "TS: " << getTableScale() << " Scr: " << m_vScroll->getValue() << " LOC: " << childRect.getY() << " H: " << h << std::endl;
}
if(moo)
{
std::cout << "S=" << startY << ",";
}
int numAttempts = 0;
while(startY + h < absRect.getY() && numAttempts < 1000)
{
startY += h;
if(moo)
{
std::cout << startY << ",";
}
numAttempts++;
}
if(moo)
{
std::cout << "\n";
moo = false;
}
g->holdDrawing();
for(int i = 0; i < numX; ++i)
{
for(int j = 0; j < numY; ++j)
{
g->drawScaledSprite(m_bgSprite,0,0,m_bgSprite->getWidth(),m_bgSprite->getHeight(),
absRect.getX() + (i * w) + (offsetX),absRect.getY() + (j * h) + startY,w,h,0);
}
}
g->unholdDrawing();
g->setClippingRect(cx,cy,cw,ch);
}
void LobbyTable::rescale( double scale )
{
setScale(scale);
float os = getObjectScale();
double x = m_baseHeight * os;
if((int)(x + 0.5) > (int)x)
{
x++;
}
int oldH = getHeight();
setSize(m_baseWidth * os, floor(x));
...
I added the related code. The slider sends a value changed which is multiplied to get a 4 percent increase (or 8 percent if slider moves 2 values etc...) then the tables are rescaled with this.
The first 3 are when the table size increased by 9, the 4th time it increased by 8px. But the scale factor increases by 0.04 each time.
Why is the 4th time inconsistant?
the pattern seems like 8,8,8,9,9,9,8,8,8,9,9,9...
It increases by 1 pixel more for a few and then decreases by 1 ten increases by 1 etc, thats my issue...
I still don't see the "add 4%" code there (in a form I can understand, anyway), but from your description I think I see the problem: adding 4% twice is not adding 8%. It is adding 8.16% (1.04 * 1.04 == 1.0816). Do that a few more times and you'll start getting 9 pixel jumps. Do it a lot more times and your jumps will get much bigger (they will be 16 pixel jumps when the size gets up to 400x400). Which, IMHO is how I like my scaling to happen.