I have been working on a particle simulation in Java, and I'm a bit confused about leapfrog integration.
I read that it "conserves energy" and took that to mean that my particles would no longer sling-shot off at absurd speeds when their separation distance is near zero. However it still happens. Am I misunderstanding the point of leapfrog integration or did I implement it wrong?
Here is what happens: http://screencast.com/t/UcMNxucKVwn
I don't see any difference in results between updating velocity based on force at current position alone versus an average.
I won't post my whole project unless I need to because it is pretty long. The simulation is run using a Java swing timer that just runs updatePosition and then updateVelocity on each body and then draws them all.
Here is the body class:
public class Body {
private final double G = 100; // Gravity strength
private double xPos, yPos;
private double xVel, yVel;
private double radius;
private double mass;
private double oldFx;
private double oldFy;
public Body(double xPos, double yPos, double xVel, double yVel, double radius) {
this.xPos = xPos;
this.yPos = yPos;
this.xVel = xVel;
this.yVel = yVel;
this.radius = radius;
this.mass = Math.PI * radius * radius;
this.oldFx = 0;
this.oldFy = 0;
}
void updatePosition() {
xPos += xVel;
yPos += yVel;
}
void updateVelocity(Body b) {
double DT = BHMain.DT/1000.0; // Time step
// Force on this body
double dx = xPos - b.xPos;
double dy = yPos - b.yPos;
double r = Math.sqrt((dx*dx + dy*dy));
double newF = - G * mass * b.mass / (r*r);
double angle = Math.atan2(dy, dx);
double newFx = newF*Math.cos(angle);
double newFy = newF*Math.sin(angle);
double Fx = (oldFx + newFx) / 2;
double Fy = (oldFy + newFy) / 2;
// Update velocity. a = F / m. v = v0 + a*t
xVel += DT * Fx / mass;
yVel += DT * Fy / mass;
oldFx = newFx;
oldFy = newFy;
}
void drawBody(Graphics g) {
int diameter = (int) (2 * radius);
int x = (int) (xPos - radius);
int y = (int) (yPos - radius);
g.fillOval(x, y, diameter, diameter);
}
}
Related
I am making a game in libGDX and I am having trouble setting up the Bullet class. I am unable to get the projectiles to go to the mouse location.
I have tried to use Math.atan() to find the angle that I need to fire at but I couldn't get that to work. right now I am just using the distance to find velocity on the x and y-axis.
private static final int SPEED = 500;
private static Texture texture;
String path = "C:\\Users\\minicodcraft\\Downloads\\game\\core\\assets\\";
private float x, y; // starting position
private float xVelocity, yVelocity;
private float yPos; // the y position of the mouse input
private float xPos; // the x position of the mouse input
public Bullet(float x, float y, float yPos, float xPos) {
this.x = x;
this.y = y;
this.xPos = xPos;
this.yPos = yPos;
this.xVelocity = 0f;
this.yVelocity = 0f;
calcDirection();
if (texture == null) {
texture = new Texture(path + "Bullet.png");
}
}
private void calcDirection() {
float xDistanceFromTarget = Math.abs(xPos - x);
float yDistanceFromTarget = Math.abs(yPos - y);
float totalDistanceFromTarget = xDistanceFromTarget + yDistanceFromTarget;
xVelocity = xDistanceFromTarget / totalDistanceFromTarget;
yVelocity = yDistanceFromTarget / totalDistanceFromTarget;
if (xPos < x) {
xVelocity *= -1;
}
if (yPos < y) {
yVelocity *= -1;
}
}
public void update(float deltaTime) {
if (x > 0 && y > 0) {
x += xVelocity * SPEED * deltaTime;
y += yVelocity * SPEED * deltaTime;
} else if (x < 0 && y > 0) {
x -= xVelocity * SPEED * deltaTime;
y += yVelocity * SPEED * deltaTime;
} else if (x > 0 && y < 0) {
x += xVelocity * SPEED * deltaTime;
y -= yVelocity * SPEED * deltaTime;
} else if (x < 0 && y < 0) {
x -= xVelocity * SPEED * deltaTime;
y -= yVelocity * SPEED * deltaTime;
}
}
public void render(SpriteBatch batch) {
batch.draw(texture, x, y);
}
The following code gives a velocity towards the mouse position from the player's position:
float diffX = mouse.x - player.x;
float diffY = mouse.y - player.y;
float angle = (float) Math.atan2(diffY, diffX);
float velX = (float) (Math.cos(angle));
float velY = (float) (Math.sin(angle));
Vector2 velocity = new Vector2(velX, -velY);
velocity.nor();
velocity.scl(magnitudeSpeed);
velocity.scl(deltaTime);
Then velocity.x is the x component of the velocity. Respective for y. No need to multiply by speed and deltaTime again, already done above.
I am unable to create several instances of the waveClock object even though I have put it in an array and marked the centre positions for each object. I would like to create 4 objects in one window, all responding to different sound frequencies/beat onsets etc
Could someone shed some light on how to go about this? I believe it may be an issue with the centerX and centerY variables in the waveClock class
ArrayList<waveClock> waveClocks = new ArrayList<waveClock>();
//global variables
float angnoise, radiusnoise;
float xnoise, ynoise;
float angle = -PI/6;
float radius;
float strokeCol = 254;
int strokeChange = -1;
int speed; //changes speed of visualisation once beat is detected?
void setup()
//for every waveClock we need 180 pixels width, then add 20 pixels for first gap
size(740, 650);
background(255);
//code is called
waveClocks.add(new waveClock(100, height/2, minRadius, bassColour, lowBassBand, highBassBand, numberOfLowOnsetsThreshold));
waveClocks.add(new waveClock(280, height/2, minRadius, midColour, lowMidBand, highMidBand, numberOfMidOnsetsThreshold));
waveClocks.add(new waveClock(460, height/2, minRadius, highColour, lowHighBand, highHighBand, numberOfHighOnsetsThreshold));
waveClocks.add(new waveClock(640, height/2, minRadius, veryHighColour, lowVeryHighBand, highVeryHighBand, numberOfVeryHighOnsetsThreshold));
//set the min and max radius of each of the viz circles
/* for (int i = 0; i < waveClocks.size(); i++) {
//go through the arraylist of waveClocks and set the min and max radius of each circle
waveClocks.get(i).setMinMaxRadius(minRadius, maxRadius);
}*/
song.play();
beat = new BeatDetect(song.bufferSize(), song.sampleRate());
bl = new BeatListener(beat, song);
}
void draw() {
//clear the screen by painting it black
//background(0);
for (int i = 0; i < waveClocks.size(); i++) {
//has there been a beat in the range? get(circle ID).low band, high band etc.
if (beat.isRange(waveClocks.get(i).getLowBand(), waveClocks.get(i).getHighBand(), waveClocks.get(i).getOnsetThreshold())) {
waveClocks.get(i).setMaxRadius();
}
//waveClocks.get(i).drawCircle();
waveClocks.get(i).drawWaveClock();
}
}
waveClock class in a separate tab
//class is an architecture blueprint
//objects are the actual buildings built from the methods (can make as many as you like)
//constructor is the builder/constructor literally
class waveClock {
float centerX; //co-ordinates of circle's position
float centerY; //co-ordinates of circle's position
float radius; //avg radius
// float minRadius; //smallest size it can be
// float maxRadius; //biggest size it can be
color col; //colour
int onsetThreshold; //
int lowBand; //looks at lowest band of frequency and makes circle sensitive to it
int highBand; //looks at highest band of frequency and makes circle sensitive to it
boolean onset; //has there been an onset (beat has occurred or not?)
//the constructor
waveClock(float x, float y, float r, color c, int lb, int hb, int t) {
centerX = x;
centerY = y;
radius = r;
col = c;
lowBand = lb;
highBand = hb;
onsetThreshold = t;
}
void drawWaveClock() {
radiusnoise += 0.005;
radius = (noise(radiusnoise)*350) + 1;
angnoise += 0.005;
angle += (noise(angnoise)*6) - 3;
if (angle > 360) {
angle -= 360;
} else if (angle < 0) {
angle += 360;
}
xnoise += 0.01;
ynoise =+ 0.01;
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
float rad = radians(angle);
float x1 = centerX + (radius*cos(rad));
float y1 = centerY + (radius*sin(rad));
float opprad = rad + PI;
float x2 = centerX + (radius*cos(opprad));
float y2 = centerY + (radius*sin(opprad));
strokeCol += strokeChange;
if (strokeCol > 354) {
strokeChange = -1;
} else if (strokeCol < 0) {
strokeChange = 1;
}
stroke(strokeCol, 60);
strokeWeight(1);
line(x1, y1, x2, y2);
}
}
You aren't ever using the class-level centerX and centerY variables. Instead, you're recalculating a new centerX and centerY in the drawWaveClock() function.
float centerX = width/2 + (noise(xnoise)*100) - 50;
float centerY = height/2 + (noise(ynoise)*100) - 50;
These are all drawn from the center of the screen, so the waves will end up in the same position.
In the future, please try to narrow your problem down to a MCVE that demonstrates the problem. Also please use proper naming conventions- classes start with an upper-case letter, for example. Good luck.
I want to find out if the user in specific region using GPS data and consider with accuracy info to reduce error, because the program will prompt an alert if user definitely out of the region.
GPS sensor return latitude, longitude and accuracy(in meter), I can draw a circle using those data:
135.500908,34.661964,30.0
There're array of coordinates in sequence represent the specific region:
135.500350,34.667011
135.506101,34.666853
135.505972,34.663076
135.505135,34.663111
135.504942,34.662387
135.504084,34.662440
135.504062,34.663146
135.502968,34.663217
135.502689,34.663764
135.502431,34.664205
135.502110,34.664646
135.501680,34.665105
135.501509,34.665246
135.500844,34.665229
135.500371,34.665511
My idea is to find out if any collisions of the polygon with the circle by using line-circle collisions detection algorithm, but it looks something wrong in my code, and seems I can't directly use that info due to radius/degree, could anyone help me out? Or let me know if any more simple solution?
public static boolean possiblyInside(List<Double> arrayX, List<Double> arrayY, double locationX, double locationY, double locationAccuracy) {
if (arrayX.size() != arrayY.size()) {
throw new IllegalArgumentException("Array length not equal");
}
boolean anyCircleLineIntersection = false;
if (arrayX.size() > 1) {
for (int i = 0; i < arrayX.size(); i++) {
double p1x = i == 0 ? arrayX.get(arrayX.size() - 1) : arrayX.get(i - 1);
double p1y = i == 0 ? arrayY.get(arrayY.size() - 1) : arrayY.get(i - 1);
double p2x = arrayX.get(i);
double p2y = arrayY.get(i);
if (circleLineIntersection(p1x, p1y, p2x, p2y, locationX, locationY, locationAccuracy)) {
anyCircleLineIntersection = true;
break;
}
}
}
return anyCircleLineIntersection;
}
private static boolean circleLineIntersection(double p1X, double p1Y, double p2X, double p2Y, double centerX, double centerY, double locationAccuracy) {
double rad = (180 / Math.PI);
double r = (locationAccuracy / 1000);
p1X = p1X * rad;
p1Y = p1Y * rad;
p2X = p2X * rad;
p2Y = p2Y * rad;
centerX = centerX * rad;
centerY = centerY * rad;
// Transform to local coordinates
double localP1X = p1X - centerX;
double localP1Y = p1Y - centerY;
double localP2X = p2X - centerX;
double localP2Y = p2Y - centerY;
// Pre-calculate this value. We use it often
double pDiffX = localP2X - localP1X;
double pDiffY = localP2Y - localP1Y;
double a = (pDiffX) * (pDiffX) + (pDiffY) * (pDiffY);
double b = 2 * ((pDiffX * localP1X) + (pDiffY * localP1Y));
double c = (localP1X * localP1X) + (localP1Y * localP1Y) - (r * r);
double delta = b * b - (4 * a * c);
return delta >= 0.0;
}
There is a method called Geofencing. Google already provides such functionality for you. And you don't have to deal with all these complex calculations.
You can fire events when the user entered a specific area / exited a specific area / after staying for some time in a specific area. Or you can make different combinations.
Here is an article of how you can use Geofencing. It consists of 4 separated articles.
Thank you for Todor Kostov's answer.
I know Android has provided Geofencing API, but it is not a perfect fit for my situation due to its implementation and limitations, and I would like to sync the algorithm with iOS version app as well. (Even I know the algorithm are not good as iOS or Android provided, and it also looks a bit silly).
Finally, I solved the problem in this way:
Ensure current location not inside the polygon (use point-in-polygon algorithm)
Loop through all line segment of the region polygon, find out the
closest coordinate(PointA) to the current location(PointB)
Calculate the distance between PointA and PointB, convert it to meter(X)
If X > location accuracy (also in meter), the user is definitely out of the particular region
p.s. I'm not good at math and geolocation, point out if any incorrect
public static boolean possiblyInside(List<Double> arrayX, List<Double> arrayY, double locationX, double locationY, double locationAccuracy) {
if (arrayX.size() != arrayY.size()) {
throw new IllegalArgumentException("Array length not equal");
}
if (arrayX.size() < 3) {
return false;
}
double minimumDistance = Double.MAX_VALUE;
for (int i = 0; i < arrayX.size(); i++) {
double p1x = i == 0 ? arrayX.get(arrayX.size() - 1) : arrayX.get(i - 1);
double p1y = i == 0 ? arrayY.get(arrayY.size() - 1) : arrayY.get(i - 1);
double p2x = arrayX.get(i);
double p2y = arrayY.get(i);
Coordinate closest = getClosestPointOnLine(p1x, p1y, p2x, p2y, locationX, locationY);
double currentDistance = distanceMeterBetweenPoints(closest.latitude, closest.longitude, locationX, locationY);
if (currentDistance < minimumDistance) {
minimumDistance = currentDistance;
}
}
return (minimumDistance <= locationAccuracy);
}
private static Coordinate getClosestPointOnLine(double sx1, double sy1, double sx2, double sy2, double px, double py) {
double xDelta = sx2 - sx1;
double yDelta = sy2 - sy1;
if ((xDelta == 0) && (yDelta == 0)) {
throw new IllegalArgumentException("Line start equals line end");
}
double u = ((px - sx1) * xDelta + (py - sy1) * yDelta) / (xDelta * xDelta + yDelta * yDelta);
final Coordinate closestPoint;
if (u < 0.0) {
closestPoint = new Coordinate(sx1, sy1);
} else if (u > 1.0) {
closestPoint = new Coordinate(sx2, sy2);
} else {
closestPoint = new Coordinate((int) Math.round(sx1 + u * xDelta), (int) Math.round(sy1 + u * yDelta));
}
return closestPoint;
}
public static double distanceMeterBetweenPoints(double aX, double aY, double bX, double bY) {
double rad = Math.PI / 180;
int r = 6371;
double dLat = (aX - bX) * rad;
double dLng = (aY - bY) * rad;
double x = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(aX * rad) * Math.cos(bX * rad) * Math.pow(Math.sin(dLng / 2), 2);
double y = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));
return r * y * 1000;
}
Currently I have an ArrayList of vertices in a 3-dimensional cartesian coordinates system. The polygon is random. It can be a car, a cup or even a dragon.
Assuming the density does not change, how to calculate the centre of mass (x,y,z) of this 3D object?
I am storing the faces and vertices in ArrayList.
public ArrayList<stlFace> StlFaces = new ArrayList<stlFace>();
public ArrayList<VertexGeometric> VertexList = new ArrayList<VertexGeometric>();
I was using this for calculating surface which is proportional to mass of each face or triangle. And to calculate center off mass of each triangle and center of mass of whole object I was using this. I added helper methods getCenter() and getSurface() to Face class to encapsulate calculations specific to just one face/triangle.
public static class Vertex {
public float x = 0;
public float y = 0;
public float z = 0;
public Vertex(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
}
public static class Face {
public Vertex v1;
public Vertex v2;
public Vertex v3;
public Face(Vertex v1, Vertex v2, Vertex v3) {
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}
public Vertex getCenter() {
Vertex triangleCenter = new Vertex(0, 0, 0);
triangleCenter.x += v1.x;
triangleCenter.x += v2.x;
triangleCenter.x += v3.x;
triangleCenter.y += v1.y;
triangleCenter.y += v2.y;
triangleCenter.y += v3.y;
triangleCenter.z += v1.z;
triangleCenter.z += v2.z;
triangleCenter.z += v3.z;
triangleCenter.x /= 3;
triangleCenter.y /= 3;
triangleCenter.z /= 3;
return triangleCenter;
}
public float getSurface() {
float x1 = v1.x - v2.x;
float x2 = v1.y - v2.y;
float x3 = v1.z - v2.z;
float y1 = v1.x - v3.x;
float y2 = v1.y - v3.y;
float y3 = v1.z - v3.z;
return (float) Math.sqrt(
Math.pow(x2 * y3 - x3 * y2, 2) +
Math.pow(x3 * y1 - x1 * y3, 2) +
Math.pow(x1 * y2 - x2 * y1, 2)
) / 2f;
}
}
public static Vertex calculateMassCenter(List<Face> faces) {
Vertex massCenter = new Vertex(0, 0, 0);
float mass = 0;
for (Face face : faces) {
Vertex triangleCenter = face.getCenter();
float faceMass = face.getSurface();
mass += faceMass;
massCenter.x += faceMass * triangleCenter.x;
massCenter.y += faceMass * triangleCenter.y;
massCenter.z += faceMass * triangleCenter.z;
}
massCenter.x /= mass;
massCenter.y /= mass;
massCenter.z /= mass;
return massCenter;
}
I would like to add a zooming function in my graph.
For exemple, if the maxY of my graph is 5000, and i zoom a distance of 200 meters around the center, my axis should represent values from 2400 to 2600, the center at being 2500.
private class ZoomHandler implements MouseWheelListener {
public void mouseWheelMoved(MouseWheelEvent e) {
double distanceY = maxY;
double cursorY = maxY / 2.0;
int rotation = e.getWheelRotation();
if (rotation < 0) {
distanceY = 200 / 2;
} else {
distanceY = 200 * 2;
}
maxY = cursorY + distanceY;
repaint();
}
}
Can somebody help with math operation ?
Thank you.
The graph is draw this way:
private void drawAxis(Graphics2D g2) {
FontMetrics metrics = g2.getFontMetrics();
double axisH = yPositionToPixel(originY);
double axisV = xPositionToPixel(originX);
g2.drawLine(0 + V_BORDER, (int) axisH, getWidth(), (int) axisH);
g2.drawLine((int) axisV, (int) axisH, (int) axisV, getHeight() - H_BORDER);
}
protected double yPositionToPixel(double position) {
double height = (double) getHeight();
return pixelOriginY + (position) / (maxY) * (height - (pixelOriginY + H_BORDER));
}
protected double xPositionToPixel(double position) {
double width = getWidth();
return (width) - pixelOriginX - (position - minX) / (maxX - minX) * (width - (pixelOriginX + V_BORDER));
}
private void drawHorizontalLabels(Graphics2D g2) {
double axisV = xPositionToPixel(originX);
FontMetrics metrics = g2.getFontMetrics();
for (double y = originY + majorY; y < maxY + majorY; y += majorY) {
int position = (int) yPositionToPixel(y);
if (rightToLeft) {
g2.drawString(formatter.format(y), (int) axisV + 5, position);
}}
The constructor look like this :
public Graph(double originX, double originY, double pixelOriginX, double pixelOriginY,
double minX, double maxX,
double minY, double maxY,
double majorX, double majorY, String labelXaxis, String labelYaxis) {}
And this is how i initialise it :
new GraphDisplay(0.0, 0.0, 40, 100, -0.1, 120, -0.1, 5000, 20, 1000);
GraphDisplay extends Graph.
JFreeChart has this already built in.