i'm not too sure on how to make it so when a rectangle is drawn onto the screen, there's a chance that it will be golden. Here's the current code i have for my game to randomly produce random rectangles:
public void drawRectangle() {
rects.clear();
int x = (int) (Math.random() * getWidth());
int y = (int) (Math.random() * getHeight());
int width = (int) (Math.random() * (getWidth() / 4));
int height = (int) (Math.random() * (getHeight() / 4));
if (x + width > getWidth()) {
x = getWidth() - width;
}
if (y + height > getHeight()) {
y = getHeight() - height;
}
Color color = new Color(
(int) (Math.random() * 255),
(int) (Math.random() * 255),
(int) (Math.random() * 255));
rects.add(new Rect(x, y, width, height, color));
repaint();
}
And heres the code i tried using to make it golden, although this was taken from online, i was jsut trying to get it working: EDIT: This code below is effectively now useless, but i'll keep it in the psot in case its of use
public static double golden(int n) {
if (n == 0) return 1;
return 1.0 + 1.0 / golden(n-1);
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
System.out.println(golden(n));
}
Any help is greatly appreciated! Thanks a bunch yet again
The basic idea is, you want to, randomly, create a golden rectangle (and possibly, randomly create the width or height)
You could use Math.random and if it's within a specified range (ie 0.75-1.0), generate a golden rectangle, but I'm lazy, so I'd use Random#nextBoolean to make the decision itself, for example...
private Random random = new Random(System.currentTimeMillis());
public void drawRectangle() {
rects.clear();
double x = (Math.random() * getWidth());
double y = (Math.random() * getHeight());
double width = 0;
double height = 0;
if (random.nextBoolean()) {
if (random.nextBoolean()) {
width = (Math.random() * (getWidth() / 4));
height = width * 1.618;
} else {
height = (Math.random() * (getHeight() / 4));
width = height * 1.618;
}
} else {
width = (Math.random() * (getWidth() / 4));
height = (Math.random() * (getHeight() / 4));
}
if (x + width > getWidth()) {
x = getWidth() - width;
}
if (y + height > getHeight()) {
y = getHeight() - height;
}
Color color = new Color(
(int) (Math.random() * 255),
(int) (Math.random() * 255),
(int) (Math.random() * 255));
rects.add(new Rect(x, y, width, height, color));
repaint();
}
Because the calculation of the golden width/height will generate a double value, I've opted to use doubles, you'll find that Rectangle2D.Double will be useful here and Graphics2D can paint Shape objects (see Graphics2D#draw and Graphics2D#fill)
Related
I have 8x8 Board, where SIZE = 8 and moveHistory is ArrayList of javafx.geometry.Point2D. Here is code :
private class ChessBoard extends Pane {
ImageView knightImageView = new ImageView("image/knight.jpg");
ChessBoard() {
this.setOnMouseClicked(e -> {
startX = (int)(e.getX() / (getWidth() / SIZE));
startY = (int)(e.getY() / (getHeight() / SIZE));
resetMoveHistory();
paint();
});
}
protected void paint() {
this.getChildren().clear();
this.getChildren().add(knightImageView);
knightImageView.setX(startX * getWidth() / SIZE);
knightImageView.setY(startY * getHeight() / SIZE);
knightImageView.setFitWidth(getWidth() / SIZE);
knightImageView.setFitHeight(getHeight() / SIZE);
for (int i = 1; i <= SIZE; i++) {
this.getChildren().add(new Line(0, i * getHeight() / SIZE,
getWidth(), i * getHeight() / SIZE));
this.getChildren().add(new Line(i * getWidth() / SIZE, 0,
i * getWidth() / SIZE, getHeight()));
}
if (moveHistory != null) {
for (int i = 1; i < moveHistory.size(); i++) {
Point2D p1 = moveHistory.get(i - 1);
Point2D p2 = moveHistory.get(i);
PathTransition ptMove = new PathTransition();
Line line = (new Line(
p1.getX() * (getWidth() / SIZE) + getWidth() / SIZE / 2,
p1.getY() * (getHeight() / SIZE) + (getHeight() / SIZE / 2),
p2.getX() * (getWidth() / SIZE) + getWidth() / SIZE / 2,
p2.getY() * (getHeight() / SIZE) + getHeight() / SIZE / 2));
ptMove.setPath(line);
ptMove.setNode(knightImageView);
ptMove.setCycleCount(1);
ptMove.setDuration(Duration.seconds(2));
ptMove.play();
}
}
}
}
What I am trying to do is display the moves with last loop, but it only shows 1 incorrect move and keeps playing it over and over. Where am I going wrong? Any help would be greatly appriecated!
The play() method starts the animation playing and exits immediately. So you effectively start all animations almost simultaneously, and let them all play concurrently. Each animation sets the translateX and translateY properties of your knightImageView, and these values will be set by each of the animations on each rendering frame during the duration of the animations. Whichever animation happens to set the values last will "win" on that frame, and that is the value that will be rendered. So the overall effect will be highly unpredictable.
What you want (I think) is to play one animation after the other. You can do this with a SequentialTransition. You code should probably look something like this:
if (moveHistory != null) {
SequentialTransition sequentialTransition = new SequentialTranstiion();
for (int i = 1; i < moveHistory.size(); i++) {
Point2D p1 = moveHistory.get(i - 1);
Point2D p2 = moveHistory.get(i);
PathTransition ptMove = new PathTransition();
Line line = (new Line(
p1.getX() * (getWidth() / SIZE) + getWidth() / SIZE / 2,
p1.getY() * (getHeight() / SIZE) + (getHeight() / SIZE / 2),
p2.getX() * (getWidth() / SIZE) + getWidth() / SIZE / 2,
p2.getY() * (getHeight() / SIZE) + getHeight() / SIZE / 2));
ptMove.setPath(line);
ptMove.setNode(knightImageView);
ptMove.setCycleCount(1);
ptMove.setDuration(Duration.seconds(2));
sequentialTransition.getChildren().add(ptMove);
}
sequentialTransition.play();
}
One other thing to note here is that the transition moves the image view by manipulating the translateX and translateY coordinates. The setX and setY methods of ImageView that you call probably don't do what you think: see the Javadocs.
I've been trying for hours to find the solution but with no results, so I have nowhere else to turn. I have a program that gathers data from user input and uses it to draw a graph. Every time the user changes the data in the text fields and presses submit I want a new graph drawn and get rid of the old one.
Currently nothing happens with the graph when I press submit with new inputs even though the inputs do change in both classes. For debugging purposes I had a
System.out.println(graphPoints.size());
in my DrawComponent class. I noticed that for everytime I press submit the amount of times graphPoints.size() gets printed out increases with one, so I assume thats no good. I really dont know where to go from here though.
Here is my actionlistener where I call the GraphPanel class:
query.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
textarea1.setText("");
textarea1.append(run(tickerInput,tickerInput2,startInput,slutInput,valuta));
Mainpanel.repaint();
if(testx != null)
testx.removeAll();
testx = new GraphPanel(first,second);
addItem(Mainpanel, testx, 0,20, 20,20, GridBagConstraints.SOUTH);
minframe.setVisible(true);
minframe.repaint();
minframe.pack();
testx.repaint();
And here is my GraphPanel class:
public GraphPanel(ArrayList<Double> first, ArrayList<Double> second) {
first1 = first;
Collections.reverse(first1);
second1 = second;
Collections.reverse(second1);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (first1.size() - 1);
double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore());
ArrayList<Point> graphPoints = new ArrayList<>();
for (int i = 0; i < first1.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - first1.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}
ArrayList<Point> graphPoints2 = new ArrayList<>();
graphPoints2.clear();
for (int i = 0; i < second1.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - second1.get(i)) * yScale + padding);
graphPoints2.add(new Point(x1, y1));
}
g2.setColor(Color.WHITE);
g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding);
g2.setColor(Color.BLACK);
for (int i = 0; i < numberYDivisions + 1; i++) {
int x0 = padding + labelPadding;
int x1 = pointWidth + padding + labelPadding;
int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding);
int y1 = y0;
if (first1.size() > 0) {
g2.setColor(gridColor);
g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1);
g2.setColor(Color.BLACK);
String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / numberYDivisions)) * 100)) / 100.0 + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3);
}
g2.drawLine(x0, y0, x1, y1);
}
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding);
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding);
Graphics g3 = g2;
Stroke oldStroke = g2.getStroke();
g2.setColor(lineColor);
g2.setStroke(GRAPH_STROKE);
System.out.println(graphPoints.size());
for (int i = 0; i < graphPoints.size() - 1; i++) {
int x1 = graphPoints.get(i).x;
int y1 = graphPoints.get(i).y;
int x2 = graphPoints.get(i + 1).x;
int y2 = graphPoints.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g3.setColor(Color.PINK);
for (int i = 0; i < graphPoints2.size() - 1; i++) {
int x1 = graphPoints2.get(i).x;
int y1 = graphPoints2.get(i).y;
int x2 = graphPoints2.get(i + 1).x;
int y2 = graphPoints2.get(i + 1).y;
g3.drawLine(x1, y1, x2, y2);
}
g2.setStroke(oldStroke);
g2.setColor(pointColor);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - pointWidth / 2;
int y = graphPoints.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g2.fillOval(x, y, ovalW, ovalH);
}
for (int i = 0; i < graphPoints2.size(); i++) {
int x = graphPoints2.get(i).x - pointWidth / 2;
int y = graphPoints2.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
g3.fillOval(x, y, ovalW, ovalH);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, heigth);
}
private double getMinScore() {
double minScore =0;
if (Collections.min(first1)<=Collections.max(second1)){
minScore= Collections.min(first1)-10;
}
else{
minScore = Collections.min(second1)-10;
}
return minScore;
}
private double getMaxScore() {
double maxScore =0;
if (Collections.max(first1)>=Collections.max(second1)){
maxScore= Collections.max(first1)+10;
}
else{
maxScore = Collections.max(second1)+10;
}
return maxScore;
}
Sorry for the wall of code, I couldn't decide what was relevant and what isn't.
The main clue here is the repeated messages. Either paintComponent is getting called a bunch of times, or you have a bunch of components getting painted. From this block in the action listener, it looks like the later:
if(testx != null)
testx.removeAll();
testx = new GraphPanel(first,second);
addItem(Mainpanel, testx, 0,20, 20,20, GridBagConstraints.SOUTH);
It removes all of the children from testx, then makes a new one and adds it to Mainpanel. What it doesn't do is remove the old testx from Mainpanel, so they're building up.
I'm currently struggling with the rotation of some rectangles.
I have a rectangle which consists of 9 small rectangles.
http://i57.tinypic.com/msn8ue.jpg
Now I rotated the big rectangle accordingly with affine transformation, which worked pretty fine.
http://i61.tinypic.com/25phlqp.jpg
My problem is that i now need to move the rectangles, so that the top left position of each rectangle is at point x,y.
I don't know how to do that and I hope that you can help me out.
Thanks!
public class MainClass {
public static void main(String[] args) {
JFrame jf = new JFrame("Demo");
Container cp = jf.getContentPane();
MyCanvas tl = new MyCanvas();
cp.add(tl);
jf.setSize(800, 800);
jf.setVisible(true);
}
}
class MyCanvas extends JComponent {
private static final long serialVersionUID = 5703217428905757134L;
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x = 400;
int y = 400;
int width = 100;
int height = 200;
final int OVERLAPPING_OUTLINE = 10;
Rectangle[] rect = new Rectangle[9];
rect[0] = new Rectangle(x + OVERLAPPING_OUTLINE, y + OVERLAPPING_OUTLINE, width - 2 * OVERLAPPING_OUTLINE, height - 2
* OVERLAPPING_OUTLINE);
rect[1] = new Rectangle(x - OVERLAPPING_OUTLINE, y - OVERLAPPING_OUTLINE, OVERLAPPING_OUTLINE * 2,
OVERLAPPING_OUTLINE * 2);
rect[2] = new Rectangle(x - OVERLAPPING_OUTLINE + width, y - OVERLAPPING_OUTLINE, OVERLAPPING_OUTLINE * 2,
OVERLAPPING_OUTLINE * 2);
rect[3] = new Rectangle(x - OVERLAPPING_OUTLINE, y + height - OVERLAPPING_OUTLINE, OVERLAPPING_OUTLINE * 2,
OVERLAPPING_OUTLINE * 2);
rect[4] = new Rectangle(x - OVERLAPPING_OUTLINE + width, y + height - OVERLAPPING_OUTLINE, OVERLAPPING_OUTLINE * 2,
OVERLAPPING_OUTLINE * 2);
rect[5] = new Rectangle(x - OVERLAPPING_OUTLINE, y + OVERLAPPING_OUTLINE, OVERLAPPING_OUTLINE * 2, height
- OVERLAPPING_OUTLINE * 2);
rect[6] = new Rectangle(x - OVERLAPPING_OUTLINE + width, y + OVERLAPPING_OUTLINE, OVERLAPPING_OUTLINE * 2, height
- OVERLAPPING_OUTLINE * 2);
rect[7] = new Rectangle(x + OVERLAPPING_OUTLINE, y - OVERLAPPING_OUTLINE, width - OVERLAPPING_OUTLINE * 2,
2 * OVERLAPPING_OUTLINE);
rect[8] = new Rectangle(x + OVERLAPPING_OUTLINE, y + height - OVERLAPPING_OUTLINE, width - OVERLAPPING_OUTLINE * 2,
2 * OVERLAPPING_OUTLINE);
for (Rectangle r : rect)
g2.draw(r);
g2.setColor(Color.RED);
AffineTransform af = new AffineTransform();
for (int i = 90; i < 360; i += 90) {
af.rotate(Math.toRadians(i), x - OVERLAPPING_OUTLINE, y - OVERLAPPING_OUTLINE);
for (Rectangle r : rect) {
Shape shape = af.createTransformedShape(r);
g2.draw(shape);
}
}
}
}
It looks like you need to use AffineTransform.translate(double tx, double ty).
I am working on a Java screen saver project and so far I have a good portion done. I need the code to generate a random shape of random color in a random position. I believe I have all of the random aspects taken care of, but now I just need to use a timer to create these shapes at 500 ms intervals. I also need to create a counter to count 30 shapes and then clear the screen and start again. (I have the background and the keylistener added for other parts of the project, but they are working perfect, in case anyone was wondering why they were there).
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class ScreenSaver1 extends JPanel implements ActionListener {
private JFrame frame = new JFrame("FullSize");
private Rectangle rectangle;
Timer t;
int x1, y1;
boolean full;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int shape;
shape = (int)(Math.random() * 4);
}
ScreenSaver1() {
t = new Timer(500, this);
t.setDelay(500);
t.start();
// Remove the title bar, min, max, close stuff
frame.setUndecorated(true);
// Add a Key Listener to the frame
frame.addKeyListener(new KeyHandler());
// Add this panel object to the frame
frame.add(this);
// Get the dimensions of the screen
rectangle = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration().getBounds();
// Set the size of the frame to the size of the screen
frame.setSize(rectangle.width, rectangle.height);
frame.setVisible(true);
// Remember that we are currently at full size
full = true;
}
// This method will run when any key is pressed in the window
class KeyHandler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
// Terminate the program.
if (e.getKeyChar() == 'x') {
System.out.println("Exiting");
System.exit(0);
}
else if (e.getKeyChar() == 'r') {
System.out.println("Change background color");
setBackground(new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256)));
repaint();
}
else if (e.getKeyChar() == 'z') {
System.out.println("Resizing");
frame.setSize((int)rectangle.getWidth() / 2, (int)rectangle.getHeight());
}
}
}
private void makeLine(Graphics g) {
int x = (int)(Math.random() * rectangle.getWidth());
int y = (int)(Math.random() * rectangle.getHeight());
int x1 = (int)(Math.random() * 100);
int y1 = (int)(Math.random() * 100);
g.setColor(new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256) ));
g.drawLine(x, y, x1, y1);
}
private void makeRect(Graphics g) {
int x = (int)(Math.random() * rectangle.getWidth());
int y = (int)(Math.random() * rectangle.getHeight());
int width = (int)(Math.random() * 100);
int height = (int)(Math.random() * 100);
g.setColor(new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256) ));
g.drawRect(x, y, width, height);
}
private void makeOval(Graphics g) {
int x = (int)(Math.random() * rectangle.getWidth());
int y = (int)(Math.random() * rectangle.getHeight());
int width = (int)(Math.random() * 100);
int height = (int)(Math.random() * 100);
g.setColor(new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256) ));
g.drawOval(x, y, width, height);
}
private void makeRoundRect(Graphics g) {
int x = (int)(Math.random() * rectangle.getWidth());
int y = (int)(Math.random() * rectangle.getHeight());
int width = (int)(Math.random() * 100);
int height = (int)(Math.random() * 100);
int arcWidth = (int)(Math.random() * width);
int arcHeight = (int)(Math.random() * height);
g.setColor(new Color((int)(Math.random() * 256), (int)(Math.random() * 256), (int)(Math.random() * 256) ));
g.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
}
public static void main(String[] args) {
ScreenSaver1 obj = new ScreenSaver1();
}
}
You're not going to like me, but I would suggest that you back up slightly...
To start with, Java provides a really good basic Shape interface, which defines how a "shape" should be rendered (amongst other things), so rather the completely reinventing the wheel, I would suggest you start with this.
Next, you need some kind of object that wraps both the Shape (which has position and size information) and the Color, for example...
public class RandomShape {
private final Color color;
private final Shape shape;
public RandomShape(Color color, Shape shape) {
this.color = color;
this.shape = shape;
}
public Color getColor() {
return color;
}
public Shape getShape() {
return shape;
}
public void paint(Graphics2D g2d) {
g2d.setColor(color);
g2d.draw(shape);
g2d.fill(shape);
}
}
This even has the ability to paint itself.
Next, I would create a List to contain these shapes...
private List<RandomShape> shapes;
This not only acts as your counter, but makes it incredibly simple to update the screen. When the shapes List contains 30 or more items, you simply clear it and repaint the screen...
Next, you need a javax.swing.Timer, which is used to trigger the updates...
This timer should...
Check to see if the shapes list needs to be cleared...
Randomly generate the Color...
int r = (int) (Math.random() * 255);
int g = (int) (Math.random() * 255);
int b = (int) (Math.random() * 255);
Color color = new Color(r, g, b);
Randomly generate the size and position of the shape...
int width = 10 + (int) (Math.random() * 40);
int height = 10 + (int) (Math.random() * 40);
int x = (int) (Math.random() * (getWidth() - width));
int y = (int) (Math.random() * (getHeight() - height));
Randomly generate the underlying basic shape...
Shape shape = null;
switch (whichShape) {
case 0:
shape = new Line2D.Double(x, y, x + width, y + height);
break;
case 1:
shape = new Rectangle2D.Double(x, y, width, height);
break;
case 2:
shape = new Ellipse2D.Double(x, y, width, height);
break;
}
Create the RandomShape, add it to the list and repaint the component...
RandomShape randomShape = new RandomShape(color, shape);
shapes.add(randomShape);
repaint();
Simple ;)
Now, when you need to paint the component, you simply iterate over the list of shapes...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (RandomShape shape : shapes) {
shape.paint(g2d);
}
g2d.dispose();
}
Take a look at How to use Swing Timers and Working with Geometry
Check out Playing With Shapes for an approach that allows you to use Shapes as a real component. Then you just add the component to a panel and you don't have to worry about custom painting.
You can paint all shapes without using a loop like this
private void paintAllShapes(Graphics g, int n) {
if(n < shapes.size()) {
shapes.get(n).paint((Graphics2D)g);
paintAllShapes(g, n+1);
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintAllShapes(g, 0);
}
Can anyone guide me how to code the arrow line in different direction.
wa and wl is positive the rectangle will be on top of the x-axis. Below example shown if wl is negative and wa is positive. The code below shown how i code the rectangle shape. x1 is the varaible to state where to start at x axis. e1 is the length of the shape, wa1 and wl1 is the height. wsign to determine the height wa1 or wl1 should display at negative side or positive side.
if (Math.abs(wl1) > Math.abs(wa1)) {
y_scale = (load_y0 - 40) / (double) Math.abs(wl1);
} else {
y_scale = (load_y0 - 40) / (double) Math.abs(wa1);
}
g.drawLine((int) ((double) x0 + x1 * x_scale), (int) (load_y),
(int) ((double) x0 + x1 * x_scale),
(int) (load_y + (wa1 * y_scale) * -1));
g.drawLine((int) ((double) x0 + (x1 + e1) * x_scale),
(int) (load_y), (int) ((double) x0 + (x1 + e1)
* x_scale), (int) (load_y + (wl1 * y_scale)
* -1));
g.drawLine((int) ((double) x0 + x1 * x_scale),
(int) (load_y + (wa1 * y_scale * -1)),
(int) ((double) x0 + (x1 + e1) * x_scale),
(int) (load_y + (wl1 * y_scale) * -1));
Here is a simple routine (adopted from here) for drawing arbitrary arrows:
import static java.awt.geom.AffineTransform.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
public class Main {
public static void main(String args[]) {
JFrame t = new JFrame();
t.add(new JComponent() {
private final int ARR_SIZE = 4;
void drawArrow(Graphics g1, int x1, int y1, int x2, int y2) {
Graphics2D g = (Graphics2D) g1.create();
double dx = x2 - x1, dy = y2 - y1;
double angle = Math.atan2(dy, dx);
int len = (int) Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
at.concatenate(AffineTransform.getRotateInstance(angle));
g.transform(at);
// Draw horizontal arrow starting in (0, 0)
g.drawLine(0, 0, len, 0);
g.fillPolygon(new int[] {len, len-ARR_SIZE, len-ARR_SIZE, len},
new int[] {0, -ARR_SIZE, ARR_SIZE, 0}, 4);
}
public void paintComponent(Graphics g) {
for (int x = 15; x < 200; x += 16)
drawArrow(g, x, x, x, 150);
drawArrow(g, 30, 300, 300, 190);
}
});
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.setSize(400, 400);
t.setVisible(true);
}
}
Result:
Simple arrow sample
/**
* #param fromPoint end of the arrow
* #param rotationDeg rotation angle of line
* #param length arrow length
* #param wingsAngleDeg wingspan of arrow
* #return Path2D arrow shape
*/
public static Path2D createArrowForLine(
Point2D fromPoint,
double rotationDeg,
double length,
double wingsAngleDeg) {
double ax = fromPoint.getX();
double ay = fromPoint.getY();
double radB = Math.toRadians(-rotationDeg + wingsAngleDeg);
double radC = Math.toRadians(-rotationDeg - wingsAngleDeg);
Path2D resultPath = new Path2D.Double();
resultPath.moveTo(length * Math.cos(radB) + ax, length * Math.sin(radB) + ay);
resultPath.lineTo(ax, ay);
resultPath.lineTo(length * Math.cos(radC) + ax, length * Math.sin(radC) + ay);
return resultPath;
}