I've read the article from here.
But it seems i can't translate that to Java, and by that I mean this:
double t = 0.0;
const double dt = 0.01;
double currentTime = hires_time_in_seconds();
double accumulator = 0.0;
State previous;
State current;
while ( !quit )
{
double newTime = time();
double frameTime = newTime - currentTime;
if ( frameTime > 0.25 )
frameTime = 0.25; // note: max frame time to avoid spiral of death
currentTime = newTime;
accumulator += frameTime;
while ( accumulator >= dt )
{
previousState = currentState;
integrate( currentState, t, dt );
t += dt;
accumulator -= dt;
}
const double alpha = accumulator / dt;
State state = currentState*alpha + previousState * ( 1.0 - alpha );
render( state );
}
What is the State class he is using? I've downloaded the code and i couldn't find it's declaration? How would the code look like in Java?
State is more an abstract idea. He's just interpolating a number. For example, state could be the x position of an entity.
An example for you:
float x = x*alpha+oldX*(1-alpha);
In my physics game, I passed the alpha value to all my entities during each render. They would use this during the render to calculate the best approximation of their position. I would suggest you do the same. Just have your render routines accept alpha, and have each object track its old state.
So every entity guesses where it really is at the time of rendering using its last position and its current position.
EDIT:
public class Entity{
double oldX;
double oldY;
double x;
double y;
public void render(Graphics g, float alpha){
float estimatedX = x*alpha+oldX*(1-alpha);
float estimatedY = y*alpha+oldY*(1-alpha);
g.drawRect((int)estimatedX,(int)estimatedY,1,1);
}
}
It's a simple structure containing the current position and velocity before each integration step. It's defined in the previous tutorial, and also near the beginning of Timestep.cpp in the code you can download from that page:
struct State
{
float x; // position
float v; // velocity
};
Related
I am writing a small libgdx program in java that was inspired by Kerbal Space Program and I am now writing the class that controls objects that will have forces acted on them. Each of these objects have a velocity vector that is changed by a forces vector.
The program runs around 60 frames per second and every frame the calculations done on the force to change velocity are done 1000 times. ( I have played with this number a lot however). Right now the program is incredibly simple and the only force that is exerted and calculated every iteration is from the planet.
forcedub = ((gravConstanat*parentBody.getMass())/Math.pow(loc.distance(parentBody.getLoc()),2));
force = new Point2D(((-1)*forcedub*Math.cos(a)),((-1)*forcedub*Math.sin(a)));
This changes the velocity sightly, the position is adjusted and the loop continues. The process works very well and seems stable. I haven't run it for days on end, but the orbit even at relatively high eccentricities seems stable. UNFORTUNATELY I need to be able to speed this process up so it doesn't take 2 days real time to get to the moon. So I needed a system that puts the orbit "on rails" and doesn't need to recalculate the forces each iterations. Once the multiplier value there gets set too high the orbit falls apart.
Good news is I already have this system in place, I just can't switch between the two.
I need a few values from the orbit to do this in my system. (I know some values are a bit redundant but it is what it is).
The semi major axis
the semi minor axis
the eccentricity vector
eccentricity
true anomaly
focus information.
To cut to the chase, the biggest issue is the eccentricity vector / eccentricity. My 'bake' function is the one that attempts to compute the values from the state vectors of the orbit every iteration and the value of the eccentricity varies drastically where it should stay the same in a standard orbit.The direction the vector is all over the place as well.
I have hard coded a single object that should have an eccentricity of about .62 and the eccentricity vector should point to pi, but the value wanders between .25 and .88 and the direction wanders between pi and pi / 3 ish.
Here are two versions of how to get the eccvecc from the state vectors, and I have tried them both. They both give the exact same results:
https://space.stackexchange.com/questions/37331/why-does-the-eccentricity-vector-equation-always-equal-1
https://en.wikipedia.org/wiki/Eccentricity_vector
public void bake(){
double velSq = Math.pow(vel.distance(0,0),2);
double r = loc.distance(parentBody.getLoc());
double gm = gravConstanat*parentBody.getMass();
Point2D posr = new Point2D(loc.getX()-parentBody.getX(), loc.getY()-parentBody.getY());
Point2D calc1 = posr.scale((velSq/gm));
Point2D calc2 = vel.scale((dotProd(posr,vel)/gm));
Point2D calc3 = posr.scale(1/r);
Point2D eccVecc = (calc1.minus(calc2)).minus(calc3);
ecc = eccVecc.distance(0,0);
w = Math.toRadians(90)-(Math.atan2(eccVecc.x(),eccVecc.y()));
semiA = (gm*r)/(2*gm - r*velSq);
semiB = semiA*(Math.sqrt((1-Math.pow(ecc,2))));
focus = findFocus(semiA,semiB);
System.out.println("ecc " + ecc + " W " + w + " SEMI A " + semiA);
System.out.println();
}
Here is the entire class:
**initial distance is about 900,000 to the left of the parent body
**parent mass is 5.3*Math.pow(10,22)
public class Klobject {
String name;
TextureAtlas textureAtlas;
Sprite sprite;
Cbody parentBody;
Point2D loc;
Point2D vel;
public boolean acceleration;
double MULTIPLIER;
static double gravConstanat = 6.67*Math.pow(10,-11);
double semiA, semiB, ecc, w;
protected double t;
protected double mass;
protected double rotateRate;
protected double focus;
public Klobject(Cbody cb){
mass = 1;
MULTIPLIER = 1;
rotateRate = 0;
parentBody = cb;
acceleration = false;
cb.addKlob(this);
loc = new Point2D((parentBody.getX() - 900_000f ),
(parentBody.getY()));
vel = new Point2D(0,2526.733);
sprite = textureAtlas.createSprite(name);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
bake();
}
public void update(float dt){
oneXupdate(dt);
bake();
}
private void oneXupdate(float dt){
int timesLooped = 1000;
double a;
double forcedub;
Point2D force;
Point2D velout;
double dx;
double dy;
dt = dt/timesLooped;
for (int i = 0; i < timesLooped; i++){
velout = vel.scale(MULTIPLIER);
dx = (dt*velout.getX());
dy = (dt*velout.getY());
loc = new Point2D(loc.getX()+dx, loc.getY()+dy);
a = Math.atan2(loc.getX()-parentBody.getX(), loc.getY()-parentBody.getY());
a = Math.toRadians(90)-a;
forcedub = ((gravConstanat*parentBody.getMass())/Math.pow(loc.distance(parentBody.getLoc()),2));
force = new Point2D(((-1)*forcedub*Math.cos(a)),((-1)*forcedub*Math.sin(a)));
force = force.scale(MULTIPLIER*MULTIPLIER);
velout = velout.plus(new Point2D(force.getX()*dt,force.getY()*dt));
vel = velout.scale(1/MULTIPLIER);
}
}
public void bake(){
double velSq = Math.pow(vel.distance(0,0),2);
double r = loc.distance(parentBody.getLoc());
double gm = gravConstanat*parentBody.getMass();
Point2D posr = new Point2D(loc.getX()-parentBody.getX(), loc.getY()-parentBody.getY());
Point2D calc1 = posr.scale((velSq/gm));
Point2D calc2 = vel.scale((dotProd(posr,vel)/gm));
Point2D calc3 = posr.scale(1/r);
Point2D eccVecc = (calc1.minus(calc2)).minus(calc3);
ecc = eccVecc.distance(0,0);
w = Math.toRadians(90)-(Math.atan2(eccVecc.x(),eccVecc.y()));
semiA = (gm*r)/(2*gm - r*velSq);
semiB = semiA*(Math.sqrt((1-Math.pow(ecc,2))));
focus = findFocus(semiA,semiB);
System.out.println("ecc " + ecc + " W " + w + " SEMI A " + semiA);
System.out.println();
}
public double findFocus(double a, double b){
return Math.sqrt(a*a - b*b);
}
public double getX(){
return loc.getX();
}
public double getY(){
return loc.getY();
}
public void setRotateRate(double rr){rotateRate = rr;}
public String getName(){
return name;
}
public Sprite getSprite(){
return sprite;
}
public void setMultiplier(double mult){
MULTIPLIER = mult;
}
public Point2D getLoc(){
return loc;
}
public void setLoc(Point2D newLoc){
loc = newLoc;
}
public double dotProd(Point2D a, Point2D b){
return a.x()*b.x() + a.y()+b.y();
}
}
I am trying to map the sun patterns in android to make an app similar to the apple watch face called solar.
I asked around what the best way to do this would be. They said that I would need to calculate the hour and divide that by 24 to get my x access and then take the hour and divid it by the midDay (sun light wise) and that would be my Y.
So thats what I did.
X axis:
public float getXPosition(Date dateTime) {
float time = getTime(dateTime);
float percentageX = time / 24.0f;
float xPosition = percentageX * lineImage.getWidth();
return xPosition;
}
Y axis:
public float getYPosition(Date dateTime) {
float time = getTime(dateTime);
float midDayTime = getTime(globalVariables.czc.getMidDay());
float differeceInTime = 12.0f - time; //reverse order from 0-12 (top down) if >1pm
Log.d("hours: ", "" + time);
Log.d("midDay", "" + midDayTime);
if (time >= midDayTime) {
time %= midDayTime;
differeceInTime = time;
}
float percentageY = differeceInTime / midDayTime;
float yPosition = percentageY * lineImage.getHeight();
return yPosition;
}
Then I just mapped the coordinates as so:
public void moveSun() {
Date dt = new Date();
sunImage.setY(getYPosition(dt) - sunImage.getHeight() / 2.5f);
sunImage.setX(getXPosition(dt) - sunImage.getWidth() / 2.5f);
}
This is for the sun.
I have other dots, representing other point in time for the suns movements that have been placed on the map as well.
As you can see the sun is almost on the line, and some of the dots are on the line. but most are not.
Does anyone know why or how I can fix this?
Maybe a better way to implement the idea.
Is it because this is a wave and not a grid?
Thanks!
EDIT: This is what happened when I change it to /midday
if (time < midday) {
percentageX = time / midday + 0.0f;
xPosition = percentageX * lineImage.getWidth() + 0.0f;
}else{
time -=midday;
percentageX = time / 24.0f- midday;
xPosition = percentageX * lineImage.getWidth()+ 0.0f;
}
So, I don't know whether I've implemented this incorrectly, or whether it's a feature of this kind of filter; but, I'd been trying to apply a peak filter to an audio signal and it wasn't working.
Some testing revealed that it wasn't filtering for the frequency I selected; but a nearby value, some of which are powers of 2, so, eg, filtering 4KHz actually filtered 4096Hz.
Here's the filter (it's from http://dspguide.com/ch19/3.htm):
SAMPLE_RATE is 88*1024
class Coefficients {
double a0=0;
double a1=0;
double a2=0;
double twoCos2piFreq=0;
double b1=0;
double b2=0;
double K=0;
double R=0;
double rSquared=0;
public Coefficients(double freq, double bandwidth)
{
twoCos2piFreq=2*Math.cos(2*Math.PI*freq);
R=1-(3*bandwidth);
rSquared=R*R;
K=(1-(R*twoCos2piFreq)+rSquared)/(2-twoCos2piFreq);
b1=R*twoCos2piFreq;
b2=-rSquared;
}
// ----------------------------------------------------------------
// Source x, result y
// y[i]=a0*x[i] + a1*x[i-1] + a2*x[i-2] + b1*y[i-1] + b2*y[i-2]
private void recursiveFilter(float[] x, float[] y)
{
double x_2 = 0.0f; // delayed x, y samples
double x_1 = 0.0f;
double y_2 = 0.0f;
double y_1 = 0.0f;
for (int i = 0; i < x.length; ++i){
double xi=x[i];
double yi=a0*xi + a1*x_1 + a2*x_2 + b1*y_1 + b2*y_2;
x_2 = x_1; // shift delayed x, y samples
y_2 = y_1;
x_1 = xi;
y_1 = yi;
y[i] = (float)yi;
}
}
// ------------------------------------------------------------
public float[] filtered(float[] signal)
{
float[] result=new float[signal.length];
recursiveFilter(signal,result);
return result;
}
}
// ----------------------------------------------------------------
class BandPassCoefficients extends Coefficients
{
public BandPassCoefficients(double freq, double bandwidth)
{
super(freq/(double)SAMPLE_RATE,bandwidth/(double)SAMPLE_RATE);
a0=1-K;
a1=(K-R)*twoCos2piFreq;
a2=rSquared-K;
}
}
and to test it, I fill a buffer with a sine wave of a range of frequencies, one at a time, apply the filter and measure the highest amplitude in the result.
Fairly obvious code, but here it is:
// ----------------------------------------------------------------
private void genTestSignal(float freq)
{
float[] leftSignal=createSinWaveBuffer(freq,ONE_SECOND);
float[] rightSignal=createSinWaveBuffer(freq,ONE_SECOND);
denormalise( leftSignal ,inputSignal, LEFT_CHANNEL);
denormalise(rightSignal,inputSignal,RIGHT_CHANNEL);
}
The denormalise and normalise functions just convert to and from interleaved signed 16-bit values to single channel floats.
This samples the start of the signal, to find the largest absolute magnitude:
private void findOptimalFreq(float[] signal, float freq)
{
float maxAmplitude=0;
int peak=0;
for(int i=(int)freq/2; i<(int)freq*3/2; i+=2){
BandPassCoefficients signalFilter=new BandPassCoefficients(i,10);
float[] normalised=signalFilter.filtered(signal);
float loudest=0;
// only scan the first part, since it's all the same
for(int j=1; j<10000; ++j){
float s=Math.abs(normalised[j]);
if(s>loudest) loudest=s;
}
if(loudest>maxAmplitude){
maxAmplitude=loudest;
peak=i;
}
}
log("freq,"+freq+","+peak);
}
And, for completion, the code which steps through the audio range, testing each frequency.
for(workingFreq=100; workingFreq<20000; workingFreq+=100){
genTestSignal(workingFreq);
inputShorts=new short[inputSignal.length/2];
ByteBuffer.wrap(inputSignal).order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(inputShorts);
findOptimalFreq(normalised(inputShorts,RIGHT_CHANNEL),workingFreq);
}
The output is logged to System.out, and copied to a spreadsheet, since it's CSV format.
Here's some of it, the left is the target frequency, the right is the actual frequency which the peak is at:
6200,6436
6300,6436
6400,6436
6500,6932
6600,6932
6700,6932
6800,6932
6900,6932
7000,7510
7100,7510
7200,7510
7300,7510
7400,7510
7500,7510
7600,8192
7700,8192
7800,8192
7900,8192
8000,8192
8100,8192
8200,9012
8300,9012
Any thoughts?
I've gone through the filter code over and over, and I'm fairly sure it's right; but there's no mention anywhere I've seen of this kind of "feature", so I don't know what to do next.
Didn't solve the problem; but was able to replace it with a BiQuadratic filter from this site: BiQuadDesigner
There is a link to java source:
HTH anyone else struggling with this.
I'm using JFreeChart to draw chart. I have XYSeries with points (0, 0), (1, 2), (2, 5) and I want to read Y value for let's say x=1.5.
Is it possible to read value for points which are not in XYSeries? I couldn't find similar topic.
This is not supported directly. It does not make sense in many cases: There simply is no data available for x=1.5. The value there could be 1000.0, or -3.141. You don't know.
However, you're most likely looking for a linear interpolation. The pragmatic approach is thus to find the interval that contains the respective x-value, and interpolate the y-values linearly.
There are some technical caveats. E.g. the XYSeries may be not sorted, or may contain duplicate x-values, in which case there is no unique y-value for a given x-value. But for now, we can assume that the data set does not have these properties.
The following is an example of how this could be implemented. Note that this is not very efficient. If you have to compute many intermediate values (that is, if you intend to call the interpolate method very often), it would be beneficial to create a tree-based data structure that allows looking up the interval in O(logn).
However, if this is not time critical (e.g. if you only intend to show the value in a tooltip or so), you may interpolate the values like this:
import java.util.List;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
public class XYInterpolation
{
public static void main(String[] args)
{
XYSeries s = new XYSeries("Series");
s.add(0,0);
s.add(1,2);
s.add(2,5);
double minX = -0.5;
double maxX = 3.0;
int steps = 35;
for (int i=0; i<=steps; i++)
{
double a = (double)i / steps;
double x = minX + a * (maxX - minX);
double y = interpolate(s, x);
System.out.printf("%8.3f : %8.3f\n", x, y);
}
}
private static double interpolate(XYSeries s, double x)
{
if (x <= s.getMinX())
{
return s.getY(0).doubleValue();
}
if (x >= s.getMaxX())
{
return s.getY(s.getItemCount()-1).doubleValue();
}
List<?> items = s.getItems();
for (int i=0; i<items.size()-1; i++)
{
XYDataItem i0 = (XYDataItem) items.get(i);
XYDataItem i1 = (XYDataItem) items.get(i+1);
double x0 = i0.getXValue();
double y0 = i0.getYValue();
double x1 = i1.getXValue();
double y1 = i1.getYValue();
if (x >= x0 && x <= x1)
{
double d = x - x0;
double a = d / (x1-x0);
double y = y0 + a * (y1 - y0);
return y;
}
}
// Should never happen
return 0;
}
}
(This implementation clamps at the limits. This means that for x-values that are smaller than the minimum x-value or larger than the maximum x-value, the y-value of the minimum/maximum x-value will be returned, respectively)
You can use DatasetUtils.findYValue() from package org.jfree.data.general
I was studying a jquery easing function to use in a java application and ended with this:
// t: current time, b: begInnIng value, c: change In value, d: duration
float easeInOutQuad (float x, float t, float b, float c, float d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
}
can someone teach me how do i plug this into my animated sphere movement?
EDIT: I wont put here unnecessary code describing my sphere movement. Imagine a sphere, with X position named X and it will go from 0 to 1000, using this easing function. How do i feed the function?
This is basically psuedo-java code, but I tested it and it works. I drew a small circle instead of using a sphere:
Sphere sphere = new Sphere();
// you might want these to be in the sphere class
float begin;
float change;
float time;
long start;
float duration;
float destX = 200;
// setup, do this when you want to start the animation
void init(){
begin = sphere.x;
change = destX - begin;
time = 0;
start = System.currentTimeMillis();
duration = 1000;
}
// loop code, may also be where you render the sphere
void loop(){
if (time <= duration){
sphere.x = easeInOutQuad(time, begin, change, duration);
}else{
// animation is over, stop the loop
}
time = System.currentTimeMillis() - start;
sphere.render();
}
float easeInOutQuad (float t, float b, float c, float d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
}
class Sphere{
float x = 0;
void render(){
ellipse(x, 100, 10, 10);
}
}
You'll probably want to move things around depending on your set up, but this is how you can use this style of easing equation.