Combining rotations and translations - Java 2D - java

public void drawEarth(Graphics2D g2){
theta -=0.1;
g2.rotate(theta);
g2.translate(50, 50);
g2.setPaint(Color.blue);
g2.fill(shape);
}
public void rotate(Graphics2D g2)
{
theta -=0.1;
g2.translate(50, 50);
g2.rotate(theta);
}
I've written these two methods. The first one causes the shape to revolve around a point, and I'm now trying to make the shape spin about its axis. I've been told that doing translation before rotation would allow the shape to spin about it's axis (as shown in the second method), but I'm not sure how to combine these two translations so that it revolves and rotates?
Any help is much appreciated.

There is too many smart words to me but maybe you want do this:
g2.rotate(double theta, double x, double y)
rotate in documentation:
Concatenates the current Graphics2D
Transform with a translated rotation
transform.

For an object it works like this: An object always rotates around the Origin.
And it also works like this Scale --> Rotate --> Translate.
If you want to rotate an object around its own axis, it has to be on the origin (which it is when you don't translate). Just call a rotate first and then translate it into the world. Once you have done that, you have to rotate it around your earth. So call a rotate again.
So you get this: (Scale) --> Rotate on own axis --> Translate on own offset --> Translate to the earth --> Rotate around the earth
I hope this helps. I don't know about the java API for this, but only about the general viewing pipeline.

Related

Bar graph rotation in Androidplot orientation sensor

I am having difficulty attempting to rotate the Levels plot in the Orientation Sensor example, by 90 degrees such that the bar graph is pointing towards (or away from) the history plot.
I have tried the android:orientation="" in the xml file but with no positive result.
It does not seem to be down to simply a matter of swapping X and Y as the bar has to start from a different edge.
In my own code, I have replaced:-
SimpleXYSeries.ArrayFormat.Y_VALS_ONLY with
SimpleXYSeries.ArrayFormat.XY_VALS_INTERLEAVED as I am actually plotting a Histogram rather than a Single bar in the java file.
However I am unable to effectively rotate this plot (the history plot needs to remain as it is.)
EDIT:
Androidplot 1.3.1 has been released with added support for rotating the graph widget:
xml:
ap:graphRotation="ninety_degrees"
java
plot.getGraph().setRotation(Widget.Rotation.NINETY_DEGREES);
Unless you're using them, you'll also want to disable the domain/range cursor (normally hidden behind the origin lines):
plot.getGraph().setDomainCursorPaint(null);
plot.getGraph().setRangeCursorPaint(null);
Original answer (for anyone not yet on 1.3.1):
It's not directly supported today but could be added pretty easily.
For now, you can achieve the basic effect by rotating the canvas 90 degrees before each render cycle and restoring afterwards. This will work flawlessly if your plot space happens to be perfectly square. Otherwise, the canvas' immuatable height and width would need to be transposed to account for the altered aspect ratio, which may be possible but probably is not worth the headache involved.
Here's a quick and dirty way to rotate a plot:
plot.addListener(new PlotListener() {
#Override
public void onBeforeDraw(Plot source, Canvas canvas) {
final float h = canvas.getHeight()/2;
final float w = canvas.getWidth()/2;
canvas.save();
canvas.rotate(90, w, h);
#Override
public void onAfterDraw(Plot source, Canvas canvas) {
canvas.restore();
}
});*/
All of this approach's shortcomings can be resolved by instead extending XYGraphWidget and overriding doOnDraw(Canvas, RectF), since there we can mutate the RectF as needed. It's quite a bit more work though to wire the new instance back into the XYPlot and re-apply xml attrs to the widget.

Graphics2D rotate methods. What's the difference?

The Java API doesn't really explain this very well and I'm still unsure.
What is the difference between these two Graphics2d overloaded method calls?
public abstract void rotate(double theta)
and
public abstract void rotate(double theta,
double x,
double y)
The Java Doc is here:
http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#translate%28int,%20int%29
What I got from the documentation, was that the second rotate method translates the graphics object, rotates it, and translates it back. My confusion is about where drawing graphics fits in if it is already translated back to the previous origin.
If the graphics is rotated, can I go off the previous coordinate system (with the origin at (0,0)) and have everything end up where I'd expect?
My goal is to rotate the graphics around the center of a image (thus the translation), and then rotate and redraw the image. After that, I'd like to reset the graphics back to normal (or simply discard that version of graphics?).
Thanks in advance for any help.
If I remember right, Graphics2D#rotate(double) rotates around the top/left corner of the Graphics context (based on it's current transformation), where as Graphics2D#rotate(double, double, double) allows you to define the anchor point around which the Graphics context will be rotated. Sometimes, you just have to give it a try

How to rotate an image actor in libgdx by the middle point?

If I understand correctly, LibGDX is rotating an image with the use of the addActions method:
this.addAction( parallel(rotateBy(360, 0.5f), moveTo(320, 100, 0.5f)));
The thing is, it is being rotated by the point=(0,0) of the image.
Here's my question:
Is there a way to rotate an image by the center point of the object? Something like pinning it in the middle and then turning it like a wheel in a car?
Both rotateBy and rotateTo methods turn it by the (0,0) point of the image itself.
You have to properly set the "origin" of you actor. You can read from the Actor API that the origin is relative to the position and is used for scale and rotation.
So, calculate your middle point, and set origin to middle point.
Actor a;
....
a.setOrigin(a.getWidth()/2, a.getHeight()/2);
The easiest and shortest way I found for setting the origin is to call:
Actor a;
...
a.setOrigin(Align.center);
The easiest way is to translate the object so the 0,0 point is the centre, rotate it, then translate it back into position. I'm not familiar with libGDX, but there should be a method for aggregating the three transforms, meaning you apply only the one aggregated transform to your object. Keep in mind the order you aggregate the transforms, makes a difference.
A much more complicated way that gives exactly the same result involves calculating the amount of offset created by the rotate and translating the image back to its origin. Don't do it this way. Combining three simple transforms is the way to go and one of the best reasons for using transforms.
** Edit
Looking at the API the Actor object has a translate() method. Use this to shift your image so the 0,0 point is in the centre. In psuedocode;
x = this.getX();
y = this.getY();
cx = this.getWidth() * .5;
cy = this.getHeight() * .5;
this.translate(-(x+cx), -(y+cy)); // move so 0,0 is the centre of the Actor object
this.rotate(thisMuch); // rotate the Actor
this.translate((x+cx), (y+cy)); // move it back to its original location
This will result in your object rotating on its centre point, on the spot. It looks convoluted, but its pretty efficient in practise, more so if you are able to work direct with the matrices (transforms) that will be driving these methods.
Here is the simple way how can you rotate an actor in libgdx.
First, you need to set the origin:
img.setorigin(width/2,hieght/2);
Now you can rotate clockwise and anticlockwise, according to your need:
img.rotate(2f);
or
img.rotate(-2f);

Android OpenGL ES: How do you select a 2D object?

I have been searching for a introductory to 2D selection in OpenGL ES in Stack Overflow. I mostly see questions about 3D.
I'm designing a 2D tile-based level editor on Android 4.0.3, using OpenGL ES. In the level editor, there is a 2D, yellow, square object placed in the center of the screen. All I wanted is to detect to see if the object has been touched by a user.
In the level editor, there aren't any tiles overlapping. Instead, they are placed side-by-side, just like two nearby pixels in a bitmap image in MS Paint. My purpose is to individually detect a touch event for each square object in the level editor.
The object is created with a simple vertex array, and using GL_TRIANGLES to draw 2 flat right triangles. There are no manipulations and no loading from a file or anything. The only thing I know is that if a user touches any one of the yellow triangles, then both yellow triangles are to be selected.
Could anyone provide a hint as to how I need to do this? Thanks in advance.
EDIT:
This is the draw() function:
public void draw(GL10 gl) {
gl.glPushMatrix();
gl.glTranslatef(-(deltaX - translateX), (deltaY - translateY), 1f);
gl.glColor4f(1f, 1f, 0f, 1f);
//TODO: Move ClientState and MatrixStack outside of draw().
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertices);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 6);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glPopMatrix();
}
EDIT 2:
I'm still missing some info. Are you using a camera? or pushing other
matrixes before the model rendering?. For example, if you are using an
orthographic camera, you can easily unproject your screen coordinates
[x_screen, y_screen] like this (y is analogous):
I'm not using a camera, but I'm probably using an orthographic projection. Again, I do not know, as I'm just using a common OpenGL function. I do pushing and popping matrices, because I plan on integrating many tiles (square 2D objects) with different translation matrices. No two tiles will have the same translation matrix M.
Is a perspective projection the same as orthographic projection when it comes to 2D? I do not see any differences between the two.
Here's the initial setup when the surface is created (a class extending GLSurfaceView, and implementing GLSurfaceView.Renderer):
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
reset();
}
public void onDrawFrame(GL10 gl) {
clearScreen(gl);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0f, super.getWidth(), 0f, super.getHeight(), 1, -1);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
canvas.draw(gl);
}
private void clearScreen(GL10 gl) {
gl.glClearColor(0.5f, 1f, 1f, 1f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
}
A basic approach would be the following:
Define a bounding box for each "touchable" object. This could be
just a rectangle (x, y, width, height).
When you update a tile in the world you update its
bounding box (completely in world coordinates).
When user touches the screen, you have to unproject screen
coordinates to world coordinates
Check if unprojected point overlaps with any bounding box.
Some hints on prev items.[Edited]
1 and 2. You should have to keep track of where you are rendering
your tiles. Store their position and size. A rectangle is a
convenient structure. In your example it could be computed like
this. And you have to recompute it when model changes. Lets call it Rectangle r:
r.x = yourTile.position.x -(deltaX - translateX)
r.y = yourTile.position.y -(deltaY - translateY)
r.width= yourTile.width //as there is no model scaling
r.height = yourTile.height//
3 - if you are using
an orthographic camera, you can easily unproject your screen
coordinates [x_screen, y_screen] like this (y is analogous):
x_model = ((x_screen/GL_viewport_width) -0.5 )*camera.WIDTH + Camera.position.x
4 - For each of your Rectangles check if [x_model; y_model] is inside it.
[2nd Edit] By the way you are updating your matrixes, you can consider you are using a camera with postition surfaceView.width()/2, surfaceView.height()/2. You are matching 1 pixel on screen to 1 unit in world, so you dont need to unproject anything. You can replace that values on my formula and get x_screen = x_model - (You 'll need to flip the Y component of the touch event because of the Y grows downwards in Java, and upwards in GL).
Final words. If user touches point [x,y] check if [x, screenHeight-y]* hits some of your rectangles and you are done.
Do some debugging, log the touching points and see if they are as expected. Generate your rectangles and see if they match what you see on screen, then is a matter of checking if a point is inside a rectangle.
I must tell you that you should not set the camera to screen dimensions, because your app will look dramatically different on different devices. This is a topic on its own so i won't go any further, but consider defining your model in terms of world units - independent from screen size. This is getting so off-topic, but i hope you have gotten a good glimpse of what you need to know!
*The flipping i told you.
PS: stick with the orthographic projection (perspective would be more complex to use).
Please, allow me to post a second answer to your question. This is completely more high-level/philosophical. May be a silly, useless answer but, I hope it will help someone new to computer graphics to change it's mind to "graphics mode".
You can't really select a triangle on the screen. That square is not 2 triangles. That square is just a bunch of yellow pixels. OpenGL takes some vertices, connects them, process them and colors some pixels on the screen. At one stage on the graphics pipeline even geometrical information is lost, and you only have isolated pixels. That's analogous to a letter printed by a printer on a paper. You usually don't process information from a paper (ok, maybe a barcode reader does :D)
If you need to further process your drawings, you have to model them and process them yourself with auxiliary data structures. That's why I suggested you created a rectangle to model your tiles. You create your imaginary "world" of objects, and then render them to screen. The user touch-event does not belong to the same world, so you have to "translate" screen coordinates into your world coordinates. Then you change something in your world (may be the user drags her finger and you have to move an object), and back again tell OpenGL to render your world to screen.
You should operate on your model, not the view. Meshes are more of a view thing, so you shouldn't mix them with the model information, it's a good practice to separate both things. (please, an expert correct me, I'm quite a graphics hobbyist)
Have you checked out LibGDX?
Makes life so much easier when working with OpenGL ES.

drawing pacman in Java

Hello for a school exercise i need to create a game and i decided to create Pacman. Everything goes well but one thing i can't accomplish is to draw a pacman dude and his ghosts.. i made and oval but what now? i want the pacman mouth also to open and close as it moves. can someone help drawing this?
below what i have till now:
package h04PacMan;
import java.awt.*;
public class DrawPacMan {
public void drawPacMan(Graphics g, int x, int y, Color color) {
g.setColor(color); // set color
g.fillOval(x, y, 50, 50); // paint
g.setColor(Color.black);
g.drawOval(x, y, 50, 50); // outline
// mouth?
}
public void drawGhost(Graphics g, int x, int y, Color color) {
g.setColor(color); // color
// here goes shape
}
}
Instead of using drawOval and fillOval, you should have a look at drawArc and fillArc.
See java.awt.Graphics.
Concerning the animation of the mouth: Given that pacman is constantly moving, you could combine pacman's position with a sine function to get a nice and smooth mouth movement, something like this:
angle = 20 * (Math.sin((x + y)*2*Math.PI/50) + 1); # alt. betw. 0 and 40
g.fillArc(x, y, 50, 50, angle/2, 360-angle);
This way, Pacman's mouth will automatically do one open-close-cycle as he moves a distance of his own size through the maze. (You may have to tweak the numbers a bit to fit your setup.)
Of course, you will still need a thread to run the game as a whole, but the animation of Pacman's mouth can be done this way, too, without extra threads.
So there are a couple of things going on here that you will need to address.
1. Drawing Characters
I'll only address drawing Pacman here.
Thinking about the Pacman game, Pacman's character has two states -- mouth closed, and mouth opened (in each cardinal direction!). This will be important for when we animate Pacman in a moment, so first, lets establish our pacman shape by using the fillArc method from the Graphics library.
Example of Mouth-Open Pacman:
g.setColor(Color.yellow);
g.fillArc(0,0,150,150,30,300);
This will create pacman in the top-left corner of your window, with pacman's mouth facing to the right of the screen. The last two paramters of the fillArc method control this opening -- the 5th parameter is the starting angle, and the sixth parameter is the angle of the full arc. You may infer from this that the start angle 0 is the horizontal line going from the center of the arc to the right of the screen. Also remember from mathematics that a full circle is 360 degrees.
Using this information, try drawing mouth-opened Pacman facing up, down and left. After you do that, fill the entire arc to draw Pacman with his mouth closed. Also consider other methods in the Graphics library you can use to draw your ghosts!
2. Animating Pacman
For this task you will probably want to implement some sort of Thread structure to animate Pacman, which gets quite a bit more complicated than what you've demonstrated here. Since we don't know your program specifications, and you also haven't demonstrated any code relating to the animation yet, I'm hesitant to lay this out any further. However, I will direct you to some links on the matter:
For a general overview, check out Java Tutorials - Concurrency.
If you're using Swing for this project, you may want to use SwingWorker for your threads.
I'd recommend taking advantage Area/Path2D API.
Have a look at Graphics 2D
You can have a look at the sample code in this answer for an example

Categories