Related
I need help with Translating, Rotating, and Scaling a Yin-Yang Symbol in Java. Can anyone provide suggestions I'll post the code below. I'm trying to use affine transformation does anyone have a way to make sure every part follows suit when I decide to move rotate, translate, scale?
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
public class ScaleTranslationRotation extends JFrame
{
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
int xLeft,yUpper,width, height;
xLeft = this.getInsets().left;
yUpper = this.getInsets().top;
width = this.getWidth()-xLeft-this.getInsets().right;
height = this.getHeight()-this.getInsets().top-this.getInsets().bottom;
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
int radius = (int)(Math.min(getWidth(), getHeight()) * 0.2);
int x = xCenter - radius;
int y = yCenter - radius;
AffineTransform yUp = new AffineTransform();
g.setColor(Color.blue);
g.fillOval(x, y, 2 * radius, 2 * radius);
g.setColor(Color.cyan);
g.drawOval(x, y, 2 * radius, 2 * radius);
g.setColor(Color.cyan);
g.fillArc(x, y, 2 * radius, 2 * radius, 270, 180);
g.setColor(Color.blue);
g.fillOval(x + (radius / 2), y, radius, radius);
g.setColor(Color.cyan);
g.fillOval(x + (radius / 2), y + radius, radius, radius);
g.setColor(Color.cyan);
g.fillOval(x + radius - (radius / 4), y + radius / 4, radius / 2, radius / 2);
g.setColor(Color.blue);
g.fillOval(x + radius - (radius / 4), y + radius + radius / 4, radius / 2, radius / 2);
g2d.setStroke(new BasicStroke(1.0f));
g.setColor(Color.red);
drawSimpleCoordinateSystem(width,height, g2d);
grid(width, height, g2d);
}
public static void drawSimpleCoordinateSystem(int x, int y, Graphics2D g2d){
int xOffset = 30;
int yOffset = 50;
int step = 20;
String s;
//Remember the actual font.
Font fo = g2d.getFont();
//Use a small font.
g2d.setFont(new Font("sansserif",Font.PLAIN,9));
//x-axis.
g2d.drawLine(xOffset,yOffset,x,yOffset);
//Marks and labels for the x-axis.
for (int i=xOffset+step; i<=x; i=i+step)
{
g2d.drawLine(i,yOffset-2,i,yOffset+2);
g2d.drawString(String.valueOf(i),i-7,yOffset-7);
}
//y-axis.
g2d.drawLine(xOffset,yOffset,xOffset,y);
//Marks and labels for the y-axis.
s=" "; //for indention of numbers < 100
for (int i=yOffset+step; i<=y; i=i+step){
g2d.drawLine(xOffset-2,i,xOffset+2,i);
if (i>99){s="";}
g2d.drawString(s+String.valueOf(i),xOffset-25,i+5);
}
//Reset to the original font.
g2d.setFont(fo);
}
public void grid(int x, int y, Graphics2D g2d){
int xOffset = 30;
int yOffset = 50;
int step = 20;
g2d.drawLine(xOffset, yOffset, x, yOffset);
for(int i = xOffset+step; i<= x; i = i+step){
g2d.drawLine(i, yOffset, i, y);
}
g2d.drawLine(xOffset, yOffset, xOffset, y);
for(int i = yOffset+step; i<=y; i = i+step){
g2d.drawLine(xOffset, i, x, i);
}
}
public static void main(String[] args)
{
ScaleTranslationRotation f = new ScaleTranslationRotation();
f.setTitle("STR");
f.setSize(1920,1020);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Just put your code yin-yang symbol code in a method
private void drawSymbol(int x, int y, int radius, Graphics g) {
g.setColor(Color.blue);
g.fillOval(x, y, 2 * radius, 2 * radius);
g.setColor(Color.cyan);
g.drawOval(x, y, 2 * radius, 2 * radius);
g.setColor(Color.cyan);
g.fillArc(x, y, 2 * radius, 2 * radius, 270, 180);
g.setColor(Color.blue);
g.fillOval(x + (radius / 2), y, radius, radius);
g.setColor(Color.cyan);
g.fillOval(x + (radius / 2), y + radius, radius, radius);
g.setColor(Color.cyan);
g.fillOval(x + radius - (radius / 4), y + radius / 4, radius / 2, radius / 2);
g.setColor(Color.blue);
g.fillOval(x + radius - (radius / 4), y + radius + radius / 4, radius / 2, radius / 2);
}
And then use an Affine transformation before calling the method to perform the requested transformation.
In the following I draw the symbol three times with different transformation
Remember to restore the original affine transformation to the initial value:
drawSymbol(x,y,radius,g);
//save original transformation
AffineTransform oldt=((Graphics2D) g).getTransform();
//create new transformation and apply it
AffineTransform yUp = new AffineTransform();
yUp.translate(0,-100);
((Graphics2D) g).setTransform(yUp);
drawSymbol(x,y,radius,g);
//create anothernew transformation and apply it
yUp = new AffineTransform();
yUp.translate(-100,0);
((Graphics2D) g).setTransform(yUp);
drawSymbol(x,y,radius,g);
//restore old transforamtion
((Graphics2D) g).setTransform(oldt);
g2d.setStroke(new BasicStroke(1.0f));
g.setColor(Color.red);
drawSimpleCoordinateSystem(width,height, g2d);
grid(width, height, g2d);
I am trying to draw a circle in side a square and having multiple square circles in java. I am almost done but my output isn't coming out as I wanted to. The picture is what I am trying to do but it's not working out.
Here is my code:
a.awt.*;
public class SquaredCircles {
public static final int WIDTH=400;
public static final int HEIGHT=400;
public static void main (String[] args) {
DrawingPanel panel = new DrawingPanel(WIDTH,HEIGHT);
Graphics g = panel.getGraphics ();
panel.setBackground(new Color(0, 255, 255 ) );
int x = 0;
int y = 0;
int size = 100;
int rows = 5;
int numSquares = 1;
drawManySquares ( g, numSquares, x, y, size, rows );
x = 10;
y = 120;
size = 24;
rows = 4;
numSquares = 4;
drawManySquares( g, numSquares, x, y, size, rows );
x = 150;
y = 20;
size = 40;
rows = 6;
numSquares = 5;
drawManySquares( g, numSquares, x, y, size, rows );
x = 130;
y = 275;
size = 36;
rows = 3;
numSquares = 3;
drawManySquares( g, numSquares, x, y, size, rows );
}
public static void drawManySquares( Graphics g, int numSquares, int x, int y, int size, int rows ) {
for ( int i = 0; i < numSquares; i++ ) {
for ( int j = 0; j < numSquares; j++ ) {
drawOneSquare( g, x + i size, y + j size, size, rows );
}
}
}
public static void drawOneSquare( Graphics g, int x, int y, int size, int rows ) {
g.setColor ( Color.GREEN);
g.fillRect(x , y, size, size);
g.setColor ( Color.YELLOW);
g.fillOval ( x, y, size, size);
g.setColor ( Color.BLACK);
g.drawLine(size / 2, x, size / 2, size);
g.setColor ( Color.BLACK);
g.drawLine(x, size / 2, size, size / 2);
for (int i = 0; i <= rows; i = i + 1) {
g.setColor ( Color.BLACK);
g.drawOval(x + (i* (size/rows)), y+ (i*(size/rows)), size - (i*(size/rows +10 )) , size - (i*(size/rows +10)));
}
}
}
Start by having a look at Painting in AWT and Swing and Performing Custom Painting to see how painting should be done in Swing
Break down your problem into manageable chunks. The first thing you need to be able to do is paint a circle of a given size at a specific location, something like
public void paintCircleAt(Graphics2D g2d, int radius, int centerX, int centerY, Color stroke, Color fill) {
Ellipse2D.Double circle = new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2);
g2d.setColor(fill);
g2d.fill(circle);
g2d.setColor(stroke);
g2d.draw(circle);
}
So, this allows you to paint a circle of a given radius around the center points of x/y filled and outlined with the specified color, pretty simple.
Now, you need someway to paint a series of circles around the same center point, something like...
public void paintCirclesIn(Graphics2D g2d, int count, int radius, int centerX, int centerY, Color stroke, Color fill) {
System.out.println(radius + "; " + centerX + "; " + centerY);
int delta = radius / count;
int innerRadius = radius;
for (int index = 0; index < count; index++, innerRadius -= delta) {
paintCircleAt(g2d, innerRadius, centerX, centerY, stroke, fill);
}
}
Okay, this basically calculates the difference (delta) between each circle and the paints that many circles with that much difference in their radius from the previous one. Because of the way the painting is done, we start with the outer circle and paint in.
And finally, we need someway to paint a square and circles, something like...
public void paintCirclesInSquare(Graphics2D g2d, int count, int x, int y, int width, int height, Color squareStroke, Color squareFill, Color circleStroke, Color circleFill) {
int centerX = x + (width / 2);
int centerY = y + (height / 2);
int radius = Math.min(centerX, centerY);
Rectangle2D box = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(squareFill);
g2d.fill(box);
g2d.setColor(squareStroke);
g2d.draw(box);
paintCirclesIn(g2d, count, radius, centerX, centerY, circleStroke, circleFill);
g2d.drawLine(centerX, y, centerX, y + height);
g2d.drawLine(x, centerY, x + width, centerY);
}
This, again, simply reuses the existing code we already have and adds to it, painting the square, the circles in the square and finally the lines.
Now, from here, you could write a method which took the number of columns/rows you wanted, the x/y position to start from, the size of each of square, the number of circles you need and the colors and reuse this functionality, but I'll leave that up to you ;)
Runnable example for you to play with...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CirclesAndSquares {
public static void main(String[] args) {
new CirclesAndSquares();
}
public CirclesAndSquares() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int x = getWidth() / 2;
int y = getHeight() / 2;
// paintCircleAt(g2d, Math.min(x, y), y, y, Color.BLACK, Color.YELLOW);
// paintCirclesIn(g2d, 5, Math.min(x, y), x, y, Color.BLACK, Color.YELLOW);
paintCirclesInSquare(g2d, 5, 0, 0, getWidth() - 1, getHeight() - 1, Color.BLACK, Color.GREEN, Color.BLACK, Color.YELLOW);
g2d.dispose();
}
public void paintCirclesInSquare(Graphics2D g2d, int count, int x, int y, int width, int height, Color squareStroke, Color squareFill, Color circleStroke, Color circleFill) {
int centerX = x + (width / 2);
int centerY = y + (height / 2);
int radius = Math.min(centerX, centerY);
Rectangle2D box = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(squareFill);
g2d.fill(box);
g2d.setColor(squareStroke);
g2d.draw(box);
paintCirclesIn(g2d, count, radius, centerX, centerY, circleStroke, circleFill);
g2d.drawLine(centerX, y, centerX, y + height);
g2d.drawLine(x, centerY, x + width, centerY);
}
public void paintCirclesIn(Graphics2D g2d, int count, int radius, int centerX, int centerY, Color stroke, Color fill) {
System.out.println(radius + "; " + centerX + "; " + centerY);
int delta = radius / count;
int innerRadius = radius;
for (int index = 0; index < count; index++, innerRadius -= delta) {
paintCircleAt(g2d, innerRadius, centerX, centerY, stroke, fill);
}
}
public void paintCircleAt(Graphics2D g2d, int radius, int centerX, int centerY, Color stroke, Color fill) {
Ellipse2D.Double circle = new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2);
g2d.setColor(fill);
g2d.fill(circle);
g2d.setColor(stroke);
g2d.draw(circle);
}
}
}
I am trying to write an applet that draws a main square and then uses a recursive method that draws smaller squares on the corners of the main square. I'm really confused on how to go about this. I have drawn the square with the others squares on its corners but i need to do this process recursively and thats where i get lost. I need to set a min side length so the recursive method knows when to stop. Here is my code.
import javax.swing.JApplet;
import java.awt.*;
public class LabC extends JApplet
{
public void paint(Graphics g)
{
g.drawRect(50, 100, 100, 100);
g.drawRect(25, 75, 50, 50);
g.drawRect(125, 75, 50, 50);
g.drawRect(125, 175, 50, 50);
g.drawRect(25, 175, 50, 50);
}
}
I think this is more or less what are you looking for
public static class LabC extends JLabel {
public void paintRecursiveWraper(Graphics g, int minW, int minH, int x, int y, int w, int h) {
g.drawRect(x, y, w, h);
paintRecusive(g, minW, minH, x, y, w, h);
}
public void paintRecusive(Graphics g, int minW, int minH, int x, int y, int w, int h) {
if (h <= minH || w <= minW) {
return;
}
int newW, newH;
int newX, newY;
newW = (int) (w * scaleFactor);
newH = (int) (h * scaleFactor);
// Bot Left Square
newX = x;
newY = y;
g.drawRect(newX, newY, newW, newH);
paintRecusive(g, minW, minH, newX, newY, newW, newH);
// Bot Right Square
newX = (int) (x + w * (1 - scaleFactor));
newY = y;
g.drawRect(newX, newY, newW, newH);
paintRecusive(g, minW, minH, newX, newY, newW, newH);
// Top Left Square
newX = x;
newY = (int) (y + h * (1 - scaleFactor));
g.drawRect(newX, newY, newW, newH);
paintRecusive(g, minW, minH, newX, newY, newW, newH);
// Top Right Square
newX = (int) (x + w * (1 - scaleFactor));
newY = (int) (y + h * (1 - scaleFactor));
g.drawRect(newX, newY, newW, newH);
paintRecusive(g, minW, minH, newX, newY, newW, newH);
}
public void paint(Graphics g) {
paintRecursiveWraper(g, 10, 10, 0, 0, 1000, 1000);
}
}
scaleFactor has to be between 0 and 1
Edited*
So far I have a java app where I draw a circle(player) and then draw a green rectangle on top(gun barrel). I have it so when the player moves, the barrel follows with it. I want it to find where the mouse is pointing and then rotate the barrel accordingly. For an example of what I mean look at this video I found http://www.youtube.com/watch?v=8W7WSkQq5SU See how the player image reacts when he moves the mouse around?
Here's an image of what the game looks like so far:
So how do I rotate it like this? Btw I don't like using affinetransform or Graphics2D rotation. I was hoping for a better way. Thanks
Using the Graphics2D rotation method is indeed the easiest way. Here's a simple implementation:
int centerX = width / 2;
int centerY = height / 2;
double angle = Math.atan2(centerY - mouseY, centerX - mouseX) - Math.PI / 2;
((Graphics2D)g).rotate(angle, centerX, centerY);
g.fillRect(...); // draw your rectangle
If you want to remove the rotation when you're done so you can continue drawing normally, use:
Graphics2D g2d = (Graphics2D)g;
AffineTransform transform = g2d.getTransform();
g2d.rotate(angle, centerX, centerY);
g2d.fillRect(...); // draw your rectangle
g2d.setTransform(transform);
It's a good idea to just use Graphics2D anyway for anti-aliasing, etc.
Using AffineTransform, sorry, only way I know how :P
public class RotatePane extends javax.swing.JPanel {
private BufferedImage img;
private Point mousePoint;
/**
* Creates new form RotatePane
*/
public RotatePane() {
try {
img = ImageIO.read(getClass().getResource("/MT02.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mousePoint != null) {
int x = width / 2;
int y = height / 2;
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
int x = (width - img.getWidth()) / 2;
int y = (height - img.getHeight()) / 2;
g2d.rotate(Math.toRadians(rotation), width / 2, height / 2);
g2d.drawImage(img, x, y, this);
x = width / 2;
y = height / 2;
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.drawLine(x, y, x, y - height / 4);
g2d.dispose();
}
}
Will produce this effect
The red line (point out from the center) will want to follow the cursor.
I'm using Java/Slick 2D to play with graphics and using the mouse to rotate an image. Something strange happens though: the image doesn't necessarily face the mouse. At 45 degrees from the normal line it does, but the further you get, the further your are off. See the images below (the white circle being the mouse, the text being the angle):
Here is the rotation code I used:
int mX = Mouse.getX();
int mY = HEIGHT - Mouse.getY();
int pX = sprite.x;
int pY = sprite.y;
int tempY, tempX;
double mAng, pAng = sprite.angle;
double angRotate=0;
if(mX!=pX){
mAng = Math.toDegrees(Math.atan2(mY - pY, mX - pX));
if(mAng==0 && mX<=pX)
mAng=180;
}
else{
if(mY>pY)
mAng=90;
else
mAng=270;
}
sprite.angle = mAng;
sprite.image.setRotation((float) mAng);
Any ideas what's going on? I'm assuming it has something to do with the fact that the image coordinates come from the top left, but I don't know how to counter it. FYI: screen 640x460, image 128x128 and centered in window.
EDIT: Unfortunately, nothing there really worked. Here is a picture with some more information:
EDIT2: Found the answer! had to change: int px/py = sprite.x/y to
int pX = sprite.x+sprite.image.getWidth()/2;
int pY = sprite.y+sprite.image.getHeight()/2;
It looks like your getting the value of your mouse from the left and setting that distance to your rotation... Here's something that might help:
http://www.instructables.com/id/Using-Java-to-Rotate-an-Object-to-Face-the-Mouse/?ALLSTEPS
This is some example code I wrote of a similar question which might help.
Now it doesn't use slick, it uses Swing and Graphics2D but it might help you gain some ideas.
public class TestRotatePane extends JPanel {
private BufferedImage img;
private Point mousePoint;
public TestRotatePane() {
try {
img = ImageIO.read(getClass().getResource("/MT02.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mousePoint != null) {
int x = width / 2;
int y = height / 2;
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
int x = (width - img.getWidth()) / 2;
int y = (height - img.getHeight()) / 2;
g2d.rotate(Math.toRadians(rotation), width / 2, height / 2);
g2d.drawImage(img, x, y, this);
x = width / 2;
y = height / 2;
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.drawLine(x, y, x, y - height / 4);
g2d.dispose();
}
}
You will, obviously, need to supply your own image ;)