I am currently making a program which animates the simple harmonic motion of a mass-spring when it is displaced. I have everything working apart from the fact that instead of drawing something like a spring, my program currently uses the graphics.drawline method to draw a straight line to represent the spring. I ideally want something like this however I am not very experienced with graphics and don't really know how to approach it, I tried to make an algorithm myself but it kept falling apart. Does anyone know of any existing algorithms which I could utilise here? If the stretching of the spring looked realistic then that would be great too (if possible).
Here is my current code:
g.fillRect(width/10 - 2, height/2 - 10, 4, 20);
g.fillRect(9*width/10 - 2, height/2 - 10, 4, 20);
g.drawLine(width/10, height/2, (int) (width/2 - (sCoefficientH * s)), height/2);
g.fillOval((int) (width/2 - (sCoefficientH * s)) -5, height/2 - 5, 10, 10);
As you can see there is a line connecting the wall (small rectangle) to the oval (which represents the mass on the spring). If I could add in a new method in this class which takes 2 co-ordinates and a relaxed size (where it wouldn't look compressed) and returns the graphics object (note that I'm not using Graphics2D) with the spring drawn in the correct place then I think it would look a lot nicer. This is what it looks like currently.
Try this:
void drawSpring(double x1, double y1, double x2, double y2, double w, int N, Graphics g)
{
// vector increment
double inv = 0.25 / (double)N;
double dx = (x2 - x1) * inv,
dy = (y2 - y1) * inv;
// perpendicular direction
double inv2 = w / sqrt(dx * dx + dy * dy);
double px = dy * inv2,
py = -dx * inv2;
// loop
double x = x1, y = y1;
for (int i = 0; i < N; i++)
{
g.drawLine(x , y ,
x + dx + px, y + dy + py);
g.drawLine(x + dx + px, y + dy + py,
x + 3.0 * dx - px, y + 3.0 * dy - py);
g.drawLine(x + 3.0 * dx - px, y + 3.0 * dy - py,
x + 4.0 * dx , y + 4.0 * dy );
x += 4.0 * dx;
y += 4.0 * dy;
}
}
Maybe change Graphics to whatever the equivalent is in Java.
EDIT: what I got in VB.NET:
Related
I am trying to draw an arc on Jpanel in swing from user input having the center of arc, starting point and end point of arc.
here is my current
int x1 = 300; //start point
int y1 = 300;
int x2 = 350; //center point of arc
int y2 = 350;
int x3 = 300; //end point of arc
int y3 = 400;
int h1 = y1 - y2; //calculate with and height from start-center and center-end
int d1 = x2 - x1;
int h2 = y2 - y3;
int d2 = x3 - x2;
int startangle = (int)(Math.atan(h1 / d1) * 180 / Math.PI);
if (x2 > x1 && y2 > y1) {
startangle = 180 - startangle;
} else if (x2 < x1) {
//change sign
} else if (y1 < y2) {
//change sign
}
System.out.println("x1,y1\n" + x1 + "\n" + y1 + "\n" + d2 / h2 + "\n" + Math.atan(d2 / h2) * 180 / Math.PI);
int endangle = (int)(Math.atan2(x3, y3) * 180 / Math.PI);
System.out.println("args: " + "\n" + x2 + "\n" + y2 + "\n" + startangle + "\n" + endangle + "\n");
g2.drawArc(x1, y1, d1, h1, startangle, startangle);
g2.drawArc(x2, y2, d2, h2, 0, endangle);
However i am not getting the arc on screen, literally nothing related to it (other shapes work but not this one). No errors or exceptions were thrown.
Edit: Thanks to #MadProgrammer's comment, i am getting a shape but not what i expect.
What i get:
What i expect from the same set of coordinates:
Edit 2: managed to make it work by using a bezier curve instead of an arc
It worked by using a bezier curve and drawing quadcurve in two phases (start-middle,middle-end) using the calculated control points instead of the drawArc method.
I think the bounding rectangle of drawarc is the height and width of the ellipse that your arc is part of.
I need to get new points of rotation to know the true position and dimension of the object, for a example:
Example 01.
The context of my application is rendering 2D graphics, the main for it below:
protected void paintComponent(Graphics g) {
...
g2d.rotate(Test.angle * Math.PI / 180, Test.hero, Test.heroY);
g2d.drawImage(Main.hero, Test.hero - 15, Test.heroY - 15, this);
...
The image is drawn correctly, but I cannot get the new points.
double angle = ang * Math.PI / 180;
double sin = Math.sin(angle);
double cos = Math.cos(angle);
double a = (centerX + ray) - x0;
double b = centerY - y0;
int xx = (int) (a * cos - b * -sin + x0);
int yy = (int) (a * -sin + b * cos + y0);
ang++;
it will rotate a point around centerX and centerY in a +ray from these origins, the code has tested and works from all angles.
public void move(){
double angle;
for(int i = 0; i < planets.size(); i++){
if(Math.abs(Math.sqrt(Math.pow(ship.locX - (planets.get(i).locX + planets.get(i).radi), 2) + Math.pow(ship.locY - (planets.get(i).locY + planets.get(i).radi), 2))) < planets.get(i).gravrange){
//Distance formula between spaceship and planets to determine whether the ship is within the influence of the planet.
angle = ((Math.atan2((planets.get(i).locX + planets.get(i).radi) - ship.locX, (planets.get(i).locY + planets.get(i).radi) - ship.locY)) / Math.PI) + 1;
//The problematic math equation.
Produces a double from 0 to 2, 0 being when ship.locY < planets.get(i).locY && ship.locX == (planets.get(i).locX - planets.get(i).radi). (when relative X = 0 and relative Y < 0.)
if(ship.locX > (planets.get(i).locX + planets.get(i).radi)){xm += Math.cos(angle) * planets.get(i).gravrate;}
else{xm -= Math.cos(angle) * planets.get(i).gravrate;}
if(ship.locY > (planets.get(i).locY + planets.get(i).radi)){ym += Math.sin(angle) * planets.get(i).gravrate;}
else{ym -= Math.sin(angle) * planets.get(i).gravrate;}
}
}
This uses the data to modify the X and Y velocities of the spacecraft.
This equation works for the majority of an orbit, but under certain circumstances has an issue in which the spacecraft undergoes a retrograde force, slowing it. Shortly afterward it begins to be repelled by the planetary body, which after a short period begins attracting it again. When the spacecraft reaches the original position at which this occurred, it begins to move in the opposite direction of its original orbit.
This continues to occur until the spacecraft begins a wavelike motion.
Is there a way to solve this, or am I simply using the wrong equation? I've been attempting to fix this for about two weeks now. I have no education in physics nor calculus at this point in time, so my understanding is limited.
Edit: The comments had questions about my math, so I'll attempt to answer them here. From what I know about atan2, it produces a number from -pi to pi. I divide by pi to produce a number from -1 to 1, then add 1 to produce 0 to 2. I then use this number as a radian measurement. My knowledge of radians (unit circle) is that a circle's radian measure is 0 to 2pi.
Edit 2: The following code has very different math but produces the desired results, save for issues of repelling rather than attracting when approaching the North and South 'poles' of the planet.
public void move(){
double angle;
double x1, x2, y1, y2;
for(int i = 0; i < planets.size(); i++){
x1 = ship.locX;
y1 = ship.locY;
x2 = planets.get(i).locX + planets.get(i).radi;
y2 = planets.get(i).locY + planets.get(i).radi;
if(Math.abs(Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))) < planets.get(i).gravrange){
//Distance formula between spaceship and planets
angle = (y2 - y1)/(x2 - x1); //Gets slope of line between points.
if(angle > 0){
if(y1 > y2){
xm += Math.cos(angle) * planets.get(i).gravrate;
ym += Math.sin(angle) * planets.get(i).gravrate;
}else{
xm -= Math.cos(angle) * planets.get(i).gravrate;
ym -= Math.sin(angle) * planets.get(i).gravrate;
}
}
else{
if(y1 > y2){
xm -= Math.cos(angle) * planets.get(i).gravrate;
ym -= Math.sin(angle) * planets.get(i).gravrate;
}else{
xm += Math.cos(angle) * planets.get(i).gravrate;
ym += Math.sin(angle) * planets.get(i).gravrate;}
}
}
}
I wrote it up very quickly to see if using the slope of the line rather than that strange atan2 equation would help. Apparently it did. I also made the code a bit more readable in this section.
The following code fixed my issue. I was overcomplicating my math equations as I usually do. Took me three weeks of Googling, asking people with degrees in physics and mathematics, and reading Javadocs before I figured that one out. Turns out how atan2 works is simply different from how I thought it worked and I was improperly using it.
The solution was simplifying the atan2 equation beforehand and removing the unnecessary additions.
x1 = ship.locX;
y1 = ship.locY;
x2 = planets.get(i).locX + planets.get(i).radi;
y2 = planets.get(i).locY + planets.get(i).radi;
if(Math.abs(Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))) < planets.get(i).gravrange){
//Distance formula between spaceship and planets
angle = Math.atan2((y2 - y1),(x2 - x1)); //Converts the difference to polar coordinates and returns theta.
xm -= Math.cos(angle) * planets.get(i).gravrate; //Converts theta to X/Y
ym -= Math.sin(angle) * planets.get(i).gravrate; //velocity values.
}
I am writing a game. I need to know how to rotate point a around point b by a given number of degrees. I am writing this in java and it is going to be part of my class, Point.
double x1 = point.x - center.x;
double y1 = point.y - center.y;
double x2 = x1 * Math.cos(angle) - y1 * Math.sin(angle));
double y2 = x1 * Math.sin(angle) + y1 * Math.cos(angle));
point.x = x2 + center.x;
point.y = y2 + center.y;
This approach uses rotation matrices. "point" is your point a, "center" is your point b.
I am having an issue with my program; currently it rotates around a set point, and can rotate models around it. Of course, this is a problem as I want it to be a first-person perspective, and currently, it rotates around a point in front of the viewer, instead of the perspective of the viewer. Here is the trigonometric calculations:
protected void drawWireframe(Graphics g) {
double theta = Math.PI * -azimuth / 180.0D;
double phi = Math.PI * elevation / 180.0D;
float cosT = (float) Math.cos(theta);
float sinT = (float) Math.sin(theta);
float cosP = (float) Math.cos(phi);
float sinP = (float) Math.sin(phi);
float cosTcosP = cosT * cosP;
float cosTsinP = cosT * sinP;
float sinTcosP = sinT * cosP;
float sinTsinP = sinT * sinP;
float near = 6.0F;
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
for (int i = 0; i < tiles.size(); i++) {
Point[] points = new Point[vertices.length];
for (int j = 0; j < points.length; j++) {
float x0 = -(tiles.get(i).getX() + xmod + vertices[j]
.getX());
float y0 = (tiles.get(i).getY() + ymod + vertices[j].getY());
float z0 = -(tiles.get(i).getZ() + zmod + vertices[j]
.getZ());
float x1 = cosT * x0 + sinT * z0;
float y1 = -sinTsinP * x0 + cosP * y0 + cosTsinP * z0;
float z1 = cosTcosP * z0 - sinTcosP * x0 - sinP * y0;
if (z1 + near > 0) {
x1 = x1 * near / (z1 + near);
y1 = y1 * near / (z1 + near);
points[j] = new Point((int) (Math.max(getWidth(),
getHeight()) / 2 - (Math.max(getWidth(),
getHeight()) / near) * x1), (int) (Math.max(
getWidth(), getHeight()) / 2 - (Math.max(
getWidth(), getHeight()) / near) * y1));
}
}
}
}
How would I go about moving the rotational point without actually modifying the xmod, ymod and zmod (these are used for movements like jumping, walking, running, crouching... etc)
I know how to figure out how to get the new x, y and z positions, I just don't know how to apply them; if I add them to the mods, it creates a weird loop-d-loop. If I add them to the x1, y1, z1's it doesn't cover the z not rotating from the perspective.
To change the rotation point, you effectively need three transforms:
Translate the coordinate system so that the rotation point becomes the origin.
Perform a rotation around the origin
Translate the coordinate system back again.
This can be factored a number of ways, but that's the basic priniciple: translate->rotate->translate.
The way you "move the rotation point" of an object is by translating the object so that the rotation point is at the origin; do the rotation; then translate the object back. All of this is done in memory, between frames - the user never actually sees the object moving to the origin and back.
By the way, all this stuff is significantly easier if you understand vectors and matrix transformations - as you've seen yourself, without them the code can get out of hand.
Using vectors/matrices, all your code above could be reduced to only a few lines.