I'm working on a game where you are a spaceship. This spaceship has to be able to rotate. The rectangle has two arrays x[], y[] containing all the corners positions of the rectangle. But when I apply the rotation formula, I get a rather wierd rotation. To try to explain it, it looks like it's rotating the bottom left of the screen.
To make these corner arrays i take in an x position, y position, width and height.
Making of the corner-arrays
public Vertex2f(float x, float y, float w, float h){
this.x[0] = x;
this.y[0] = y;
this.x[1] = x+w;
this.y[1] = y;
this.x[2] = x+w;
this.y[2] = y+h;
this.x[3] = x;
this.y[3] = y+h;
}
My rotation function
public void rotate(float angle){
this.rotation = angle;
double cos = Math.cos(rotation);
double sin = Math.sin(rotation);
for(int i = 0; i < x.length; i++){
x[i] = (float)(cos * x[i] - sin * y[i]);
y[i] = (float)(sin * x[i] + cos * y[i]);
}
}
If it helps I am using LWJGL/OpenGL in java for all the graphics and Slick2d to load and init the sprites I am using.
Try this one:
public void rotate(float angle){
this.rotation = angle;
double cos = Math.cos(rotation);
double sin = Math.sin(rotation);
double xOffset = (x[0]+x[2])/2;
double yOffset = (y[0]+y[2])/2;
for(int i = 0; i < 3; i++){
x[i] = (float)(cos * (x[i]-xOffset) - sin * (y[i]-yOffset)) + xOffset;
y[i] = (float)(sin * (x[i]-xOffset) + cos * (y[i]-yOffset)) + yOffset;
}
}
you have to rotate around center of your rectangle. Otherwise center is in x=0 and y=0
edited:
public void rotate(float angle){
this.rotation = angle;
double cos = Math.cos(rotation);
double sin = Math.sin(rotation);
double xOffset = (x[0]+x[2])/2;
double yOffset = (y[0]+y[2])/2;
for(int i = 0; i < 3; i++){
double newX = (float)(cos * (x[i]-xOffset) - sin * (y[i]-yOffset)) + xOffset;
double newY = (float)(sin * (x[i]-xOffset) + cos * (y[i]-yOffset)) + yOffset;
x[i] = newX;
y[i] = newY;
}
}
see other thread
The problem with the formulas
x[i] = (float)(cos * x[i] - sin * y[i]);
y[i] = (float)(sin * x[i] + cos * y[i]);
apart from the missing rotation center is that you change x[i] in the first formula but expect to use the original value in the second formula. Thus you need to use local variables lx, ly as in
float lx = x[i] - xcenter;
float ly = y[i] - ycenter;
x[i] = xcenter + (float)(cos * lx - sin * ly);
y[i] = ycenter + (float)(sin * lx + cos * ly);
If the object already is rotated with an angle of rotation, then this code adds the angle angle to the total rotation angle. If instead the given argument angle is to be the new total rotation angle, then the sin and cos values need to be computed with the angle difference. That is, start the procedure with, for instance,
public void rotate(float angle){
double cos = Math.cos(angle - rotation);
double sin = Math.sin(angle - rotation);
this.rotation = angle;
Related
I have to points in 3D space that I want to draw a cylinder between. I currently have this code:
applet.pushMatrix();
applet.stroke(0);
applet.fill(0);
applet.line(this.start.x, this.start.y, this.start.z, this.end.x, this.end.y, this.end.z); //debug, shows where the cylinder should be
applet.translate(this.start.x, this.start.y);
applet.beginShape(PConstants.TRIANGLE_STRIP);
float xdif = this.end.x - this.start.x;
float ydif = this.end.y - this.start.y;
float zdif = this.end.z - this.start.z;
float rx = (float)Math.atan(ydif / xdif);
float ry = (float)Math.atan(zdif / xdif);
float rz = (float)Math.atan(zdif == 0 ? 0 : ydif / zdif);
applet.rotateZ((float) (rx - Math.PI / 2));
applet.rotateY((float) (ry - Math.PI / 2));
applet.rotateX((float) (rz - Math.PI / 2));
float r = 20;
float len = HelperFunctions.distance(this.start, this.end) / 2;
boolean w = false;
for (int i = 0; i < 2; i += 1) {
for (float j = 0; j < Math.PI * 2 + 0.2; j += 0.4) {
w = !w;
float z = (i + (w ? 0 : 1)) * len;
float x = (float)(r * Math.cos(j));
float y = (float)(r * Math.sin(j));
applet.vertex(y, x, z);
}
}
applet.endShape();
applet.popMatrix();
The cylinder does draw correctly, however, it doesn't rotate correctly. I'm trying to use trig to determine the rotation angles, however, I'm not sure I've done it correctly. How would I get the correct angles to rotate around such that it is drawn from Vector start to Vector end?
Vector is a custom class with just a float x, y, z, and HelperFunctions.distance takes two Vectors and calculates the distance (pythagoras).
Thanks in advance.
I am having a bit of trouble trying to figure out how to draw paths from a point on a canvas with the start of each path being equally distanced from the initial point. To illustrate what I mean, the code that I have so far is able to generate this:
and the desired result is something like this:
My code:
int n = 3;
int r;
double x;
double y;
point1 = new Point(mWidth/2, mHeight/2);
double angle;
double angleFactor;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < 3; i++){
angleFactor = 2 * Math.PI / n;
angle = i * angleFactor;
x = (point1.x) + r * Math.cos(angle);
y = (point1.y) + r * Math.sin(angle);
//Draw paths
path.reset();
path.moveTo(point1.x, point1.y);
path.lineTo((float) x, (float) y);
canvas.drawPath(path, paint);
}
}
Is there a simple solution to this?
Since you want to have a tiny distance between the offset of a line and the center point, you can define start coordinates like this:
double xStart, xEnd;
double yStart, yEnd;
double offsetFraction = 0.1;
Inside the for loop in onDraw() :
double lengthX = r * Math.cos(angle);
double lengthY = r * Math.sin(angle);
xStart = (point1.x) + offsetFraction * lengthX;
yStart = (point1.y) + offsetFraction * lengthY;
xEnd = (point1.x) + lengthX;
yEnd = (point1.y) + lengthY;
//Draw paths
path.reset();
path.moveTo((float) xStart, (float) yStart);
path.lineTo((float) xEnd, (float) yEnd);
canvas.drawPath(path, paint);
I have a Java class that creates a virtual screen (let's call it a map) that can be translated, resized, and rotated.
When I rotate it, however, it only rotates it around (0, 0).
To transform the point to the screen you first rotate it, then resize it, then translate it.
private double dx; //offset in x and y
private double dy;
private double t; //rotation (radians)
private double sx; //scale of x and y
private double sy;
public double[] toScreen(double x, double y) //takes (x, y) on the map and gives (x1, y1) for the screen
{
double[] xy = {x, y};
if(t != 0)
{
double distance = Math.hypot(xy[0], xy[1]);
double theta = Math.atan2(xy[1], xy[0]) + t;
xy[0] = Math.cos(theta)*distance;
xy[1] = Math.sin(theta)*distance;
}
xy[0] *= sx;
xy[1] *= sy;
xy[0] += dx;
xy[1] += dy;
return xy;
}
to set the rotation or change it, you manipulate the variable t, but it rotates on (0, 0).
If I make a method that takes in (x, y) to rotate around like public void changeRotation(double t, double x, double y).
I want (x, y) to be map coordinates. What would the method look like and can you explain what it does?
If I understood correctly this is what you need :
/**
* #param point point (x,y) of the coordinates to be rotated
* #param center point (x,y) of the center (pivot) coordinates
* #param angle in radians
* #return point (x,y) of the new (translated) coordinates
*/
static Point2D.Double rotateAPoint(Point2D.Double point, Point2D.Double center, double angle){
double newX = center.x + Math.cos(angle) * (point.x - center.x) -
Math.sin(angle) * (point.y-center.y) ;
double newY = center.y + Math.sin(angle) * (point.x - center.x) +
Math.cos(angle) * (point.y - center.y) ;
return new Point2D.Double(newX, newY);
}
Try with
Point2D.Double point = new Point2D.Double(200,100);
Point2D.Double center = new Point2D.Double(100,100);
double angle = Math.PI/2 ; //90 degress
System.out.println(rotateAPoint(point, center, angle) );
System.out.println(rotateAPoint(point, center, -angle));
If you prefer to use double[] :
/**
* #param point (x,y) of the coordinates to be rotated
* #param center (x,y) of the center (pivot) coordinates
* #param angle in radians
* #return (x,y) of the new (translated) coordinates
*/
static double[] rotateAPoint(double[] point, double[] center, double angle){
double newX = center[0] + Math.cos(angle) * (point[0] - center[0]) -
Math.sin(angle) * (point[0]-center[0]) ;
double newY = center[1] + Math.sin(angle) * (point[1] - center[1]) +
Math.cos(angle) * (point[1] - center[1]) ;
return new double[]{newX, newY};
}
Explanation about the math here
I've try to rotate an Image in Java using setRGB and BufferedImage, but I get a strange result. Has anyone any idea why?
BufferedImage pic1 = ImageIO.read(new File("Images/Input-1.bmp"));
int width = pic1.getWidth(null);
int height = pic1.getHeight(null);
double angle = Math.toRadians(90);
double sin = Math.sin(angle);
double cos = Math.cos(angle);
double x0 = 0.5 * (width - 1); // point to rotate about
double y0 = 0.5 * (height - 1); // center of image
BufferedImage pic2 = pic1;
// rotation
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
double a = x - x0;
double b = y - y0;
int xx = (int) (+a * cos - b * sin + x0);
int yy = (int) (+a * sin + b * cos + y0);
if (xx >= 0 && xx < width && yy >= 0 && yy < height) {
pic2.setRGB(x, y, pic1.getRGB(xx, yy));
}
}
}
ImageIO.write(pic2, "bmp", new File("Images/Output2.bmp"));
In the LEFT side is the original picture and in the RIGHT side it's my result. Have anyone any idea how can I fix it?
Thanks for help.
The problem is that you're using the same image as input and output:
BufferedImage pic2 = pic1;
You must create another image for pic2 and then do the rotation, copying pixels from Image1 to Image2.
Note, however, that using getRGB and setRGB it terribly slow. Its 100 times faster if you manipulate the pixels directly.
I'm trying to simulate an analog stick on a mobile platform.
I calculate a stick vector which based on the position of the finger and the radius of the stick returns a value from -1 to 1.
public void calcStickVector(float x, float y)
{
float cx = getCenterX();
float cy = getCenterY();
float distX = x - cx;
float distY = y - cy;
distX /= getRadius();
distY /= getRadius();
distX = JMath.clamp(-1.0f, 1.0f, distX);
distY = JMath.clamp(-1.0f, 1.0f, distY);
stickVector.x = distX;
stickVector.y = distY;
}
public RectF getInnerStickRect()
{
float r = getInnerRadius();
float cx = getCenterX() + (getRadius() * getStickVector().x);
float cy = getCenterY() + (getRadius() * getStickVector().y);
innerStickRect.left = cx - r;
innerStickRect.top = cy - r;
innerStickRect.right = cx + r;
innerStickRect.bottom = cy + r;
return innerStickRect;
}
It almost works, but visually the inner stick, when moved around seems to form a square rather than going around in a circle. Is there something wrong with my logic?
Thanks
As it is, you really are making a box with 1's as the corners. You need to normalize the vector(divide x and y by distance) instead of dividing by radius and clamping.
double dist = Math.sqrt(distX*distX) + (distY*distY));
distX /= dist;
distY /= dist;