I've got a GUI that generates a graphics image using the Mandelbrot set.
I've implemented some zoom buttons, but I'd like to be able to change the centre of my GUI with a mouseclick (make mouse coordinates the new centre-point).
It's proving to be quite difficult. Any suggestions?
My attempt can be found at the moveGraph method.
Thanks in advance!
package assn4_12mgs;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class MandelBrot extends JFrame{
MandelPanel mp;
double xMax = 2.26;
double xMin = -2.24;
double yMax = 2.26;
double yMin = -2.24;
double yMove, xMove;
static double ESCAPE_MODULUS = 2.0;
static int MAX_ITERATIONS = 32;
public MandelBrot(){
super();
setLayout(new BorderLayout());
setTitle("Graham's Mandelbrot GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,700);
setResizable(false);
mp = new MandelPanel();
mp.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
MoveGraph(evt);
}
});
JPanel panel = new JPanel(new FlowLayout());
JButton zoomIn = new JButton("+");
zoomIn.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
ZoomIn(evt);
}
});
JButton zoomOut = new JButton("-");
zoomOut.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
ZoomOut(evt);
}
});
JButton reset = new JButton("Reset");
reset.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent evt) {
reset(evt);
}
});
panel.add(reset, BorderLayout.WEST); ///How to change positioning?
panel.add(zoomOut, BorderLayout.EAST);
panel.add(zoomIn, BorderLayout.EAST);
add(panel, BorderLayout.SOUTH);
add(mp, BorderLayout.NORTH);
}
private void MoveGraph(MouseEvent evt){
int x = evt.getPoint().x;
int y = evt.getPoint().y;
xMove = x/100;
yMove = y/100;
mp.repaint();
}
private void ZoomIn(MouseEvent evt){
xMax /= 2;
xMin /= 2;
yMax /= 2;
yMin /= 2;
mp.repaint();
}
private void ZoomOut(MouseEvent evt){
xMax *= 2;
xMin *= 2;
yMax *= 2;
yMin *= 2;
mp.repaint();
}
private void reset(MouseEvent evt){
xMax = 2.26;
xMin = -2.24;
yMax = 2.26;
yMin = -2.24;
xMove = 0;
yMove = 0;
mp.repaint();
}
public class MandelPanel extends JPanel {
public MandelPanel() {
setPreferredSize(new Dimension(600,600));
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// draw here
int row, col;
ComplexNumber c, z;
double xPos, yPos;
double modulus = 0;
boolean escaped = false;
int iterations = 0;
int desiredColour;
// Calculate the scale factor to go from pixels to actual units
int height = mp.getHeight(); // drawingZone is the JPanel drawing area
int width = mp.getWidth();
double xScale = (xMax - xMin) / width; // These are min and max values in actual
double yScale = (yMax - yMin) / height; // coordinates.
Graphics2D g2D = (Graphics2D)g;
BufferedImage pretty = new BufferedImage(width, height,
BufferedImage.TYPE_3BYTE_BGR);
// Iterate through the entire panel, pixel by pixel
for (row = 0; row < height; row++) {
// Calculate the actual y position
yPos = yMax - row * yScale;// - yMove
for (col = 0; col < width; col++) {
// Calculate the actual x position
xPos = xMin + col * xScale;// + xMove;
// Create the complex number for this position
c = new ComplexNumber(xPos, yPos);
z = new ComplexNumber(0, 0);
iterations = 0;
// Iterate the fractal equation z = z*z + c
// until z either escapes or the maximum number of iterations
// is reached
do {
z = (z.multiply(z)).add(c);
modulus = z.abs();
escaped = modulus > ESCAPE_MODULUS;
iterations++;
} while (iterations < MAX_ITERATIONS && !escaped);
// Set the colour according to what stopped the above loop
if (escaped) {
desiredColour = setEscapeColour(iterations);
} else {
desiredColour = setColour(modulus);
}
pretty.setRGB(col, row, desiredColour);
} // end for
} // end for
g2D.drawImage(pretty, null, 0, 0);
//yMove = 0;
//xMove = 0;
}
}
// Sets gray level for escape situation
private static int setEscapeColour(int numIterations) {
float grayLevel = 0.5F - (float) numIterations / MAX_ITERATIONS;
grayLevel = Math.max(grayLevel, 0.1F);
return new Color(grayLevel, grayLevel, grayLevel).getRGB();
} // end setEscapeColour
// Sets colour level for interior situation
// The algorithm used here is *totally* empirical!
private static int setColour(double modulus) {
float factor = (float) (modulus / ESCAPE_MODULUS);
float incr = (float) Math.log10(factor * 5.5);
float r = Math.min(Math.abs(10.0F * incr) * factor, 1.0F);
float g = Math.min(Math.abs(6.0F * incr) * factor, 1.0F);
float b = Math.min(Math.abs(0.5F * factor + incr), 1.0F);
return new Color(r, g, b).getRGB();
} // end setColour
public static void main(String args[]){
MandelBrot manBrot = new MandelBrot();
manBrot.setVisible(true);
}
}
We take a point on which a user has clicked as a center point for drawing, then calculate the window (half the distance up and down, left and right) around that point. See
/**
* Calculate real coordinates of the point we clicked.
*/
double xDist = Math.abs(xMax) + Math.abs(xMin);
double yDist = Math.abs(yMax) + Math.abs(yMin);
double xTr = xDist / 600.0 * ((double) e.getX());
double yTr = yDist / 700.0 * ((double) e.getY());
/**
* Calculate the window coordinates. It is relative to the point where the user clicked.
*/
xMax = xTr + xDist/2.0;
xMin = xTr - xDist/2.0;
yMax = yTr + yDist/2.0;
yMin = yTr - yDist/2.0;
** The Code**
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JOptionPane;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class MandelBrot
extends JFrame
{
public static class ComplexNumber
{
double re;
double im;
public void setRe(double re)
{
this.re = re;
}
public double re()
{
return re;
}
public void setIm(double im)
{
this.im = im;
}
public double im()
{
return im;
}
public ComplexNumber(double re, double im)
{
this.re = re;
this.im = im;
}
public ComplexNumber add(ComplexNumber c)
{
setRe(re() + c.re());
setIm(im() + c.im());
return this;
}
public ComplexNumber multiply(ComplexNumber z)
{
setRe(re()*z.re() - im()*z.im());
setIm(im()*z.re() - re()*z.im());
return this;
}
public double abs()
{
return Math.sqrt(re()*re() + im()*im());
}
}
MandelPanel mp;
double xMax = 2.26;
double xMin = -2.24;
double yMax = 2.26;
double yMin = -2.24;
double yMove, xMove;
static double ESCAPE_MODULUS = 2.0;
static int MAX_ITERATIONS = 32;
public MandelBrot()
{
super();
setLayout(new BorderLayout());
setTitle("Graham's Mandelbrot GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600, 700);
setResizable(false);
mp = new MandelPanel();
mp.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
JOptionPane.showMessageDialog(
null,
"You clicked on a picture area (x,y): (" + e.getX() + "," + e.getY() + ")" ,
"Info",
JOptionPane.INFORMATION_MESSAGE);
double xDist = Math.abs(xMax) + Math.abs(xMin);
double yDist = Math.abs(yMax) + Math.abs(yMin);
double xTr = xDist / 600.0 * ((double) e.getX());
double yTr = yDist / 700.0 * ((double) e.getY());
xMax = xTr + xDist/2.0;
xMin = xTr - xDist/2.0;
yMax = yTr + yDist/2.0;
yMin = yTr - yDist/2.0;
System.out.format("%f %f %f %f %n", xDist, yDist, xTr, yTr);
System.out.format("%f %f %f %f %n", xMin, xMax, yMin, yMax);
mp.repaint();
}
public void mouseReleased(MouseEvent evt)
{
MoveGraph(evt);
}
});
JPanel panel = new JPanel(new FlowLayout());
JButton zoomIn = new JButton("+");
zoomIn.addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent evt)
{
ZoomIn(evt);
}
});
JButton zoomOut = new JButton("-");
zoomOut.addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent evt)
{
ZoomOut(evt);
}
});
JButton reset = new JButton("Reset");
reset.addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent evt)
{
reset(evt);
}
});
panel.add(reset, BorderLayout.WEST); ///How to change positioning?
panel.add(zoomOut, BorderLayout.EAST);
panel.add(zoomIn, BorderLayout.EAST);
add(panel, BorderLayout.SOUTH);
add(mp, BorderLayout.NORTH);
}
private void MoveGraph(MouseEvent evt)
{
int x = evt.getPoint().x;
int y = evt.getPoint().y;
xMove = x / 100;
yMove = y / 100;
mp.repaint();
}
private void ZoomIn(MouseEvent evt)
{
xMax /= 2;
xMin /= 2;
yMax /= 2;
yMin /= 2;
mp.repaint();
}
private void ZoomOut(MouseEvent evt)
{
xMax *= 2;
xMin *= 2;
yMax *= 2;
yMin *= 2;
mp.repaint();
}
private void reset(MouseEvent evt)
{
xMax = 2.26;
xMin = -2.24;
yMax = 2.26;
yMin = -2.24;
xMove = 0;
yMove = 0;
mp.repaint();
}
public class MandelPanel
extends JPanel
{
public MandelPanel()
{
setPreferredSize(new Dimension(600, 600));
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// draw here
int row, col;
ComplexNumber c, z;
double xPos, yPos;
double modulus = 0;
boolean escaped = false;
int iterations = 0;
int desiredColour;
// Calculate the scale factor to go from pixels to actual units
int height = mp.getHeight(); // drawingZone is the JPanel drawing area
int width = mp.getWidth();
double xScale = (xMax - xMin) / width; // These are min and max values in actual
double yScale = (yMax - yMin) / height; // coordinates.
Graphics2D g2D = (Graphics2D) g;
BufferedImage pretty = new BufferedImage(width, height,
BufferedImage.TYPE_3BYTE_BGR);
// Iterate through the entire panel, pixel by pixel
for (row = 0; row < height; row++)
{
// Calculate the actual y position
yPos = yMax - row * yScale;// - yMove
for (col = 0; col < width; col++)
{
// Calculate the actual x position
xPos = xMin + col * xScale;// + xMove;
// Create the complex number for this position
c = new ComplexNumber(xPos, yPos);
z = new ComplexNumber(0, 0);
iterations = 0;
// Iterate the fractal equation z = z*z + c
// until z either escapes or the maximum number of iterations
// is reached
do
{
z = (z.multiply(z)).add(c);
modulus = z.abs();
escaped = modulus > ESCAPE_MODULUS;
iterations++;
}
while (iterations < MAX_ITERATIONS && !escaped);
// Set the colour according to what stopped the above loop
if (escaped)
{
desiredColour = setEscapeColour(iterations);
}
else
{
desiredColour = setColour(modulus);
}
pretty.setRGB(col, row, desiredColour);
} // end for
} // end for
g2D.drawImage(pretty, null, 0, 0);
//yMove = 0;
//xMove = 0;
}
}
// Sets gray level for escape situation
private static int setEscapeColour(int numIterations)
{
float grayLevel = 0.5F - (float) numIterations / MAX_ITERATIONS;
grayLevel = Math.max(grayLevel, 0.1F);
return new Color(grayLevel, grayLevel, grayLevel).getRGB();
} // end setEscapeColour
// Sets colour level for interior situation
// The algorithm used here is *totally* empirical!
private static int setColour(double modulus)
{
float factor = (float) (modulus / ESCAPE_MODULUS);
float incr = (float) Math.log10(factor * 5.5);
float r = Math.min(Math.abs(10.0F * incr) * factor, 1.0F);
float g = Math.min(Math.abs(6.0F * incr) * factor, 1.0F);
float b = Math.min(Math.abs(0.5F * factor + incr), 1.0F);
return new Color(r, g, b).getRGB();
} // end setColour
public static void main(String args[])
{
MandelBrot manBrot = new MandelBrot();
manBrot.setVisible(true);
}
}
Related
enter image description here
I am programming a paint editor for my final year project. One of its function is that when an user select one or more lines, these lines can be rotated according to a specific point(one of the vertex of these selected lines). Besides, when a line is chosen, it will be marked as red and both vextices will be marked. The red vertex is rotation pivot chosen by user. To implement this, i first caculate the rotation angle and then use trigonometric function to caculate the rotated lines.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import javax.swing.*;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
public class MWE extends JFrame{
MyPanel panel = new MyPanel();
public MWE(){
setTitle("MyFirstFrame");
setSize(1160,830);
setLocation(100,100);
setVisible(true);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel.setBackground(Color.white);
panel.requestFocus();
panel.setVisible(true);
this.getContentPane().add(panel);
}
public static void main(String[] args){
MWE myFrame = new MWE();
}
}
class MyPanel extends JPanel{
private ArrayList selectedLines = new ArrayList<MyLine2D>();
private ArrayList selectedPoints = new ArrayList<MyPoint>();
MyPoint rotationP = new MyPoint(247,309,Color.red);
int lastX = 0, lastY = 0;
public MyPanel(){
this.setBackground(Color.WHITE);
this.requestFocus();
this.setVisible(true);
addMouseListener();
Line2D myLine = new Line2D.Double(247, 309, 344, 197);
selectedLines.add(new MyLine2D(myLine, Color.red));
MyPoint p1 = new MyPoint(247,309,Color.red);
MyPoint p2 = new MyPoint(344,197,Color.black);
selectedPoints.add(p1);
selectedPoints.add(p2);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int i = 0; i< selectedLines.size(); i++){
g.setColor(((MyLine2D)selectedLines.get(i)).getColor());
g.drawLine(((MyLine2D)selectedLines.get(i)).getX1(), ((MyLine2D)selectedLines.get(i)).getY1(),
((MyLine2D)selectedLines.get(i)).getX2(), ((MyLine2D)selectedLines.get(i)).getY2());
}
for(int i = 0; i < selectedPoints.size(); i++){
g.setColor(((MyPoint)selectedPoints.get(i)).getColor());
g.drawOval(((MyPoint)selectedPoints.get(i)).getX() - 3, ((MyPoint)selectedPoints.get(i)).getY() - 3, 6, 6);
}
}
private void addMouseListener(){
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e){
lastX = e.getX();
lastY = e.getY();
}
});
this.addMouseMotionListener(new MouseMotionAdapter(){
#Override
public void mouseDragged(MouseEvent e){
double vecCross = (lastX - rotationP.getX()) * (e.getX() - rotationP.getX()) + (lastY - rotationP.getY()) * (e.getY() - rotationP.getY());
int c = (Math.abs((lastX - rotationP.getX()) * (lastX - rotationP.getX())) + Math.abs((lastY - rotationP.getY()) * (lastY - rotationP.getY())))
* (Math.abs((e.getX() - rotationP.getX()) * (e.getX() - rotationP.getX())) + Math.abs((e.getY() - rotationP.getY()) * (e.getY() - rotationP.getY())));
double sqrt = Math.sqrt(c);
double cosValue = vecCross/sqrt;
double radian = Math.acos(cosValue);
if(((e.getY() - lastY)*(lastX - rotationP.getX()) < 0) && !Double.isNaN(radian)){
//
for(int i = 0; i < selectedLines.size(); i++){
((MyLine2D)selectedLines.get(i)).rotationLine(rotationP, -radian);
}
for(int i = 0; i < selectedPoints.size(); i++){
((MyPoint)selectedPoints.get(i)).rotationPoint(rotationP, -radian);
}
}
if(((e.getY() - lastY)*(lastX - rotationP.getX()) > 0) && !Double.isNaN(radian)){
for(int i = 0; i < selectedLines.size(); i++){
((MyLine2D)selectedLines.get(i)).rotationLine(rotationP, radian);
}
for(int i = 0; i < selectedPoints.size(); i++){
((MyPoint)selectedPoints.get(i)).rotationPoint(rotationP, radian);
}
}
lastX = e.getX();
lastY = e.getY();
repaint();
}
});
}
}
class MyLine2D {
private Line2D myLine = new Line2D.Double();
private Color color = Color.BLACK;
public MyLine2D(Line2D myLine, Color c){
this.myLine = myLine;
this.color = c;
}
public int getX1(){
return (int)myLine.getX1();
}
public int getY1(){
return (int)myLine.getY1();
}
public int getX2(){
return (int)myLine.getX2();
}
public int getY2(){
return (int)myLine.getY2();
}
public Color getColor(){
return this.color;
}
public void rotationLine(MyPoint pivot, double radians){
double x1=0, y1=0, x2=0, y2=0;
x1 = pivot.getX() + (myLine.getX1() - pivot.getX()) * Math.cos(radians) - (myLine.getY1() - pivot.getY()) * Math.sin(radians);
y1 = pivot.getY() + (myLine.getY1() - pivot.getY()) * Math.cos(radians) + (myLine.getX1() - pivot.getX()) * Math.sin(radians);
x2 = pivot.getX() + (myLine.getX2() - pivot.getX()) * Math.cos(radians) - (myLine.getY2() - pivot.getY()) * Math.sin(radians);
y2 = pivot.getY() + (myLine.getY2() - pivot.getY()) * Math.cos(radians) + (myLine.getX2() - pivot.getX()) * Math.sin(radians);
Line2D rotatedLine = new Line2D.Double(x1,y1,x2,y2);
myLine = rotatedLine;
}
}
class MyPoint {
private int x;
private int y;
private Color color = Color.black;
public MyPoint(int x, int y, Color c){
this.x = x;
this.y = y;
this.color = c;
}
public int getX(){
return this.x;
}
//
//
public int getY(){
return this.y;
}
public Color getColor(){
return this.color;
}
public void rotationPoint(MyPoint pivot, double radians){
double x1 = pivot.getX() + (x - pivot.getX()) * Math.cos(radians) - (y - pivot.getY()) * Math.sin(radians);
double y1 = pivot.getY() + (y - pivot.getY()) * Math.cos(radians) + (x - pivot.getX()) * Math.sin(radians);
x = (int) x1;
y = (int) y1;
}
}
vecCross is dot product of a vector from rotation pivot to original mouse pointer location and a vector from rotation pivot to present mouse pointer location. c is product of the magnitude of these two vectors. the Arraylist, selectedLines, is the lines selected and remain to be rotated. the ArrayList, selectedPoints, is the vertices of selected lines.
in the if arguement, i think '((e.getY() - lastY)*(lastX - rotationP.getX()) < 0 )' can be represented as my mouse moves anticlockwise. because origin of Jpanel is at top left, anticlockwise movement means to reduce its degree.
My Problem:
However, when i select some lines and enter Rotation mode and move my mouse clockwise, these lines dont rotate smoothly, sometimes quick and sometime slow, and those selected points will dettach from vertices, as shown in image. it is really strange because i use the some function to rotate the selected points and lines. can anyone give me some comments?
In my program I want to draw a simple score line graph. I have a text file and on each line is an integer score, which I read in and want to pass as argument to my graph class. I'm having some trouble implementing the graph class and all the examples I've seen have their methods in the same class as their main, which I won't have.
I want to be able to pass my array to the object and generate a graph, but when calling my paint method it is asking me for a Graphics g... This is what I have so far:
public class Graph extends JPanel {
public void paintGraph (Graphics g){
ArrayList<Integer> scores = new ArrayList<Integer>(10);
Random r = new Random();
for (int i : scores){
i = r.nextInt(20);
System.out.println(r);
}
int y1;
int y2;
for (int i = 0; i < scores.size(); i++){
y1 = scores.get(i);
y2 = scores.get(i+1);
g.drawLine(i, y1, i+1, y2);
}
}
}
For now I have inserted a simple random number generator to fill up my array.
I have an existing frame and basically want to instantiate the Graph class and mount the panel onto my frame. I'm really sorry that this question seems so jumbled by the way, but I've had little sleep...
The code in my main statement is:
testFrame = new JFrame();
testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Graph graph = new Graph();
testFrame.add(graph);
I'm not sure exactly what an SSCE is but this is my attempt at one:
public class Test {
JFrame testFrame;
public Test() {
testFrame = new JFrame();
testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Graph graph = new Graph();
testFrame.add(graph);
testFrame.setBounds(100, 100, 764, 470);
testFrame.setVisible(true);
}
Graph.java
public class Graph extends JPanel {
public Graph() {
setSize(500, 500);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D gr = (Graphics2D) g; // This is if you want to use Graphics2D
// Now do the drawing here
ArrayList<Integer> scores = new ArrayList<Integer>(10);
Random r = new Random();
for (int i : scores) {
i = r.nextInt(20);
System.out.println(r);
}
int y1;
int y2;
for (int i = 0; i < scores.size() - 1; i++) {
y1 = (scores.get(i)) * 10;
y2 = (scores.get(i + 1)) * 10;
gr.drawLine(i * 10, y1, (i + 1) * 10, y2);
}
}
}
Problems with your code and suggestions:
Again you need to change the preferredSize of the component (here the Graph JPanel), not the size
Don't set the JFrame's bounds.
Call pack() on your JFrame after adding components to it and before calling setVisible(true)
Your foreach loop won't work since the size of your ArrayList is 0 (test it to see that this is correct). Instead use a for loop going from 0 to 10.
You should not have program logic inside of your paintComponent(...) method but only painting code. So I would make the ArrayList a class variable and fill it inside of the class's constructor.
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawGraph extends JPanel {
private static final int MAX_SCORE = 20;
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final int BORDER_GAP = 30;
private static final Color GRAPH_COLOR = Color.green;
private static final Color GRAPH_POINT_COLOR = new Color(150, 50, 50, 180);
private static final Stroke GRAPH_STROKE = new BasicStroke(3f);
private static final int GRAPH_POINT_WIDTH = 12;
private static final int Y_HATCH_CNT = 10;
private List<Integer> scores;
public DrawGraph(List<Integer> scores) {
this.scores = scores;
}
#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 * BORDER_GAP) / (scores.size() - 1);
double yScale = ((double) getHeight() - 2 * BORDER_GAP) / (MAX_SCORE - 1);
List<Point> graphPoints = new ArrayList<Point>();
for (int i = 0; i < scores.size(); i++) {
int x1 = (int) (i * xScale + BORDER_GAP);
int y1 = (int) ((MAX_SCORE - scores.get(i)) * yScale + BORDER_GAP);
graphPoints.add(new Point(x1, y1));
}
// create x and y axes
g2.drawLine(BORDER_GAP, getHeight() - BORDER_GAP, BORDER_GAP, BORDER_GAP);
g2.drawLine(BORDER_GAP, getHeight() - BORDER_GAP, getWidth() - BORDER_GAP, getHeight() - BORDER_GAP);
// create hatch marks for y axis.
for (int i = 0; i < Y_HATCH_CNT; i++) {
int x0 = BORDER_GAP;
int x1 = GRAPH_POINT_WIDTH + BORDER_GAP;
int y0 = getHeight() - (((i + 1) * (getHeight() - BORDER_GAP * 2)) / Y_HATCH_CNT + BORDER_GAP);
int y1 = y0;
g2.drawLine(x0, y0, x1, y1);
}
// and for x axis
for (int i = 0; i < scores.size() - 1; i++) {
int x0 = (i + 1) * (getWidth() - BORDER_GAP * 2) / (scores.size() - 1) + BORDER_GAP;
int x1 = x0;
int y0 = getHeight() - BORDER_GAP;
int y1 = y0 - GRAPH_POINT_WIDTH;
g2.drawLine(x0, y0, x1, y1);
}
Stroke oldStroke = g2.getStroke();
g2.setColor(GRAPH_COLOR);
g2.setStroke(GRAPH_STROKE);
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);
}
g2.setStroke(oldStroke);
g2.setColor(GRAPH_POINT_COLOR);
for (int i = 0; i < graphPoints.size(); i++) {
int x = graphPoints.get(i).x - GRAPH_POINT_WIDTH / 2;
int y = graphPoints.get(i).y - GRAPH_POINT_WIDTH / 2;;
int ovalW = GRAPH_POINT_WIDTH;
int ovalH = GRAPH_POINT_WIDTH;
g2.fillOval(x, y, ovalW, ovalH);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
List<Integer> scores = new ArrayList<Integer>();
Random random = new Random();
int maxDataPoints = 16;
int maxScore = 20;
for (int i = 0; i < maxDataPoints ; i++) {
scores.add(random.nextInt(maxScore));
}
DrawGraph mainPanel = new DrawGraph(scores);
JFrame frame = new JFrame("DrawGraph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which will create a graph that looks like so:
Just complementing Hovercraft Full Of Eels's solution:
I reworked his code, tweaked it a bit, adding a grid, axis labels and now the Y-axis goes from the minimum value present up to the maximum value. I planned on adding a couple of getters/setters but I didn't need them, you can add them if you want.
Here is the Gist link, I'll also paste the code below: GraphPanel on Gist
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GraphPanel extends JPanel {
private int width = 800;
private int heigth = 400;
private int padding = 25;
private int labelPadding = 25;
private Color lineColor = new Color(44, 102, 230, 180);
private Color pointColor = new Color(100, 100, 100, 180);
private Color gridColor = new Color(200, 200, 200, 200);
private static final Stroke GRAPH_STROKE = new BasicStroke(2f);
private int pointWidth = 4;
private int numberYDivisions = 10;
private List<Double> scores;
public GraphPanel(List<Double> scores) {
this.scores = scores;
}
#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) / (scores.size() - 1);
double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore());
List<Point> graphPoints = new ArrayList<>();
for (int i = 0; i < scores.size(); i++) {
int x1 = (int) (i * xScale + padding + labelPadding);
int y1 = (int) ((getMaxScore() - scores.get(i)) * yScale + padding);
graphPoints.add(new Point(x1, y1));
}
// draw white background
g2.setColor(Color.WHITE);
g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding);
g2.setColor(Color.BLACK);
// create hatch marks and grid lines for y axis.
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 (scores.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);
}
// and for x axis
for (int i = 0; i < scores.size(); i++) {
if (scores.size() > 1) {
int x0 = i * (getWidth() - padding * 2 - labelPadding) / (scores.size() - 1) + padding + labelPadding;
int x1 = x0;
int y0 = getHeight() - padding - labelPadding;
int y1 = y0 - pointWidth;
if ((i % ((int) ((scores.size() / 20.0)) + 1)) == 0) {
g2.setColor(gridColor);
g2.drawLine(x0, getHeight() - padding - labelPadding - 1 - pointWidth, x1, padding);
g2.setColor(Color.BLACK);
String xLabel = i + "";
FontMetrics metrics = g2.getFontMetrics();
int labelWidth = metrics.stringWidth(xLabel);
g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3);
}
g2.drawLine(x0, y0, x1, y1);
}
}
// create x and y axes
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding);
g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding);
Stroke oldStroke = g2.getStroke();
g2.setColor(lineColor);
g2.setStroke(GRAPH_STROKE);
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);
}
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);
}
}
// #Override
// public Dimension getPreferredSize() {
// return new Dimension(width, heigth);
// }
private double getMinScore() {
double minScore = Double.MAX_VALUE;
for (Double score : scores) {
minScore = Math.min(minScore, score);
}
return minScore;
}
private double getMaxScore() {
double maxScore = Double.MIN_VALUE;
for (Double score : scores) {
maxScore = Math.max(maxScore, score);
}
return maxScore;
}
public void setScores(List<Double> scores) {
this.scores = scores;
invalidate();
this.repaint();
}
public List<Double> getScores() {
return scores;
}
private static void createAndShowGui() {
List<Double> scores = new ArrayList<>();
Random random = new Random();
int maxDataPoints = 40;
int maxScore = 10;
for (int i = 0; i < maxDataPoints; i++) {
scores.add((double) random.nextDouble() * maxScore);
// scores.add((double) i);
}
GraphPanel mainPanel = new GraphPanel(scores);
mainPanel.setPreferredSize(new Dimension(800, 600));
JFrame frame = new JFrame("DrawGraph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
It looks like this:
Or simply use the JFreechart library - http://www.jfree.org/jfreechart/ .
There exist many open source projects that handle all the drawing of line charts for you with a couple of lines of code. Here's how you can draw a line chart from data in a couple text (CSV) file with the XChart library. Disclaimer: I'm the lead developer of the project.
In this example, two text files exist in ./CSV/CSVChartRows/. Notice that each row in the files represents a data point to be plotted and that each file represents a different series. series1 contains x, y, and error bar data, whereas series2 contains just x and y, data.
series1.csv
1,12,1.4
2,34,1.12
3,56,1.21
4,47,1.5
series2.csv
1,56
2,34
3,12
4,26
Source Code
public class CSVChartRows {
public static void main(String[] args) throws Exception {
// import chart from a folder containing CSV files
XYChart chart = CSVImporter.getChartFromCSVDir("./CSV/CSVChartRows/", DataOrientation.Rows, 600, 400);
// Show it
new SwingWrapper(chart).displayChart();
}
}
Resulting Plot
Override the paintComponent method of your panel so you can custom draw. Like this:
#Override
public void paintComponent(Graphics g) {
Graphics2D gr = (Graphics2D) g; //this is if you want to use Graphics2D
//now do the drawing here
...
}
Hovercraft Full Of Eels' answer is very good, but i had to change it a bit in order to get it working on my program:
int y1 = (int) ((this.height - 2 * BORDER_GAP) - (values.get(i) * yScale - BORDER_GAP));
instead of
int y1 = (int) (scores.get(i) * yScale + BORDER_GAP);
because if i used his way the graphic would be upside down
(you'd see it if you used hardcoded values (e.g 1,3,5,7,9) instead of random values)
I am drawing a grid on a JPanel by overriding paint(g) and with it marking some points whichever clicked on the grid, but the main problem is, if someone minimize the grid or drag it around the screen, the part of the screen goes blank. I can't figure out how to change my code to have it refreshed every time the screen is minimized or dragged around, please help me with the code.
Here is my code:-
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class draw extends JPanel {
private int x,y,X,Y,xmin,xmax,ymin,ymax;
private int clickParam = 0;
private double d, theta;
private ArrayList<Integer> ab = new ArrayList<Integer>();
private ArrayList<Integer> or = new ArrayList<Integer>();
private ArrayList<Double> distance = new ArrayList<Double>();
private ArrayList<Double> angle = new ArrayList<Double>();
Graphics2D g2d = null;
public void drawing(){
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2d = g2;
int stroke[]={1,2,3,4,5};
g2.setStroke(new BasicStroke(stroke[1]));
xmin = 150;
ymin = 150;
xmax = 650;
ymax = 650;
int xsize = xmax - xmin;
int ysize = ymax - ymin;
g2.drawRect(xmin, ymin, xsize, ysize);
for(int i=50;i<=xsize;i+=50){
g2.drawLine(xmin+i, ymin, xmin+i, ymax);
g2.drawLine(xmin, ymin+i, xmax, ymin+i);
}
g2.setStroke(new BasicStroke(stroke[0]));
for(int i=10;i<=xsize;i+=10){
g2.drawLine(xmin+i, ymin, xmin+i, ymax);
g2.drawLine(xmin, ymin+i, xmax, ymin+i);
}
}
public void drawPoints(Graphics2D g2){
if(x >= xmin && x <= xmax && y >= ymin && y <= ymax)
g2.fillOval(x-3, y-3, 7, 7);
}
public void onClick(){
addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e){
setxy(e);
setXY();
clickParam = 2;
drawPoints(g2d);
if(x >= xmin && x <= xmax && y >= ymin && y <= ymax){
setDistance();
setAngle();
display();
}
}
});
}
public void setxy(MouseEvent e){
x = e.getX();
y = e.getY();
if(x >= xmin && x <= xmax && y >= ymin && y <= ymax){
ab.add(x);
or.add(y);
}
}
public void setXY(){
X = x - xmin;
Y = ymax - y;
}
public void setDistance(){
d = Math.sqrt(Math.pow(X/10, 2) + Math.pow(Y/10, 2));
distance.add(d);
}
public void setAngle(){
theta = Math.atan2(Y,X)*180/Math.PI;
angle.add(theta);
}
public void display(){
System.out.println("(X,Y) = ("+(X/10)+","+(Y/10)+")"+" & (d,theta) = ("+d+","+theta+")");
}
}
and the main class:-
import java.awt.Dimension;
import javax.swing.*;
public class mainClass {
public static void main(String args[]){
JFrame jframe = new JFrame("TEST");
draw d = new draw();
jframe.setPreferredSize(new Dimension(1000,1000));
jframe.pack();
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.add(d);
jframe.setVisible(true);
jframe.setResizable(false);
d.drawing();
d.onClick();
}
}
onClick is never called, therefore the MouseListener is never added.
Create a list of Points and loop through it in your paintComponent method.
drawPoints should only be called inside the paintComponent method, since it takes the current Graphics2D object.
Restructured code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class Draw extends JPanel { // Class names should start with an uppercase letter
private int xmin, xmax, ymin, ymax;
private ArrayList<Point> points = new ArrayList<Point>(); // Create a list where all clicked points will be stored
public Draw() {
xmin = 150;
ymin = 150;
xmax = 650;
ymax = 650;
addMouseListener(new MouseAdapter() { // Add MouseListener in the constructor
#Override
public void mousePressed(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
if (point.x >= xmin && point.x <= xmax && point.y >= ymin
&& point.y <= ymax) {
points.add(point); // Add the point to the list
repaint();
}
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int stroke[] = { 1, 2, 3, 4, 5 };
g2.setStroke(new BasicStroke(stroke[1]));
int xsize = xmax - xmin;
int ysize = ymax - ymin;
g2.drawRect(xmin, ymin, xsize, ysize);
for (int i = 50; i <= xsize; i += 50) {
g2.drawLine(xmin + i, ymin, xmin + i, ymax);
g2.drawLine(xmin, ymin + i, xmax, ymin + i);
}
g2.setStroke(new BasicStroke(stroke[0]));
for (int i = 10; i <= xsize; i += 10) {
g2.drawLine(xmin + i, ymin, xmin + i, ymax);
g2.drawLine(xmin, ymin + i, xmax, ymin + i);
}
drawPoints(g2);
}
private void drawPoints(Graphics2D g2) {
for (Point point : points) { // Loop through the list of points
g2.fillOval(point.x - 3, point.y - 3, 7, 7);
}
}
public static void main(String args[]) {
JFrame jframe = new JFrame("TEST");
Draw d = new Draw();
jframe.setSize(800,800);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setContentPane(d);
jframe.setVisible(true);
}
}
I have been trying to figure this one out for some time now, I am making a program that uses a triangle as an arrow and been trying to figure out how to make an arrow with two points, meaning that that the first point would be at the midpoint of the base of the triangle, while the second point would be at the tip facing the direction away from the first point.
This crude paint drawing should help figure out what I am talking about
http://i.stack.imgur.com/f3ktz.png (Would put direct images but don't have enough rep)
Now, I went through and tried figuring out how to calculate those other two endpoints of the triangle so I could make the polygon, but I am not doing it correctly because I am getting a triangle that isn't isosceles and the endpoints don't create a line perpendicular to the original line.
What I am currently getting (With some drawing over it to show the points)
http://i.stack.imgur.com/dljsn.png
My current code
public class Triangle extends Shape{
private boolean assigned = false;
private int[] x;
private int[] y;
public Triangle(Point startPoint, Point endPoint){
this.startPoint = startPoint;
this.endPoint = endPoint;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.white);
if(!assigned) {
x = new int[3];
y = new int[3];
double distance = startPoint.distance(endPoint);
double halfDistance = distance/2;
double angle = getAngle(startPoint,endPoint)- Math.PI/2.0;
x[0] = (int)endPoint.getX();
y[0] = (int)endPoint.getY();
x[1] = (int)((Math.sin(angle)*halfDistance) + startPoint.getX());
y[1] = (int)((Math.cos(angle)*halfDistance) + startPoint.getY());
x[2] = (int)(startPoint.getX() - (Math.sin(angle)*halfDistance));
y[2] = (int)(startPoint.getY() - (Math.cos(angle)*halfDistance));
assigned = true;
if(endPoint.distance(x[1],y[1]) == (Math.sqrt(5)*halfDistance))
System.out.println("DEBUG: Confirm Correct 1");
if(endPoint.distance(x[1],y[1]) == endPoint.distance(x[2],y[2]))
System.out.println("DEBUG: Confirm Correct 2");
}
g.fillPolygon(x,y,3);
g.setColor(Color.blue);
}
private double getAngle(Point pointOne, Point pointTwo){
double angle = Math.atan2(pointTwo.getY()- pointOne.getY(),pointTwo.getX()-pointOne.getX());
while(angle < 0){
angle += (2.0*Math.PI);
}
return angle;
}
}
I have working at this for hours and can't seem to figure it out, someone please help.
So, I ended up replacing double angle = getAngle(startPoint,endPoint)- Math.PI/2.0; with something more like double angle = -Math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x);
I wrote this little test program, which allows you to move to points around a circle and which generates the resulting triangle...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane tp = new TestPane();
JPanel control = new JPanel(new BorderLayout());
control.add(tp);
final JSlider startAngel = new JSlider(0, 359);
final JSlider endAngel = new JSlider(0, 359);
JPanel sliders = new JPanel(new GridLayout(1, 2));
sliders.add(startAngel);
sliders.add(endAngel);
startAngel.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
tp.setStartAngle(startAngel.getValue());
}
});
endAngel.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
tp.setEndAngle(endAngel.getValue());
}
});
startAngel.setValue(0);
endAngel.setValue(180);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(control);
frame.add(sliders, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point startPoint, endPoint;
private float startAngle = 0;
private float endAngle = 180;
public TestPane() {
}
#Override
public void invalidate() {
super.invalidate();
recalculate();
}
protected void recalculate() {
int dim = Math.min(getWidth(), getHeight());
dim -= 50;
float radius = dim / 2f;
startPoint = getPointOnCircle(startAngle, radius);
endPoint = getPointOnCircle(endAngle, radius);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected Point getPointOnCircle(float degress, float radius) {
int x = Math.round(getWidth() / 2);
int y = Math.round(getHeight() / 2);
double rads = Math.toRadians(degress - 90); // 0 becomes the top
// Calculate the outter point of the line
int xPosy = Math.round((float) (x + Math.cos(rads) * radius));
int yPosy = Math.round((float) (y + Math.sin(rads) * radius));
return new Point(xPosy, yPosy);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int[] x = new int[3];
int[] y = new int[3];
double distance = startPoint.distance(endPoint);
double halfDistance = distance / 2;
double angle = -Math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x);
System.out.println(angle);
x[0] = (int) endPoint.getX();
y[0] = (int) endPoint.getY();
x[1] = (int) ((Math.sin(angle) * halfDistance) + startPoint.getX());
y[1] = (int) ((Math.cos(angle) * halfDistance) + startPoint.getY());
x[2] = (int) (startPoint.getX() - (Math.sin(angle) * halfDistance));
y[2] = (int) (startPoint.getY() - (Math.cos(angle) * halfDistance));
g2d.setColor(Color.RED);
g2d.fillPolygon(x, y, 3);
g2d.setColor(Color.BLUE);
g2d.fillOval(startPoint.x - 5, startPoint.y - 5, 10, 10);
g2d.setColor(Color.GREEN);
g2d.fillOval(endPoint.x - 5, endPoint.y - 5, 10, 10);
g2d.dispose();
}
public void setStartAngle(float value) {
startAngle = value;
recalculate();
}
public void setEndAngle(float value) {
endAngle = value;
recalculate();
}
}
}
If that still gives you some weird results, apart from sharing some test data, I might consider using something like Math.atan2(Math.abs(endPoint.y - startPoint.y), Math.abs(endPoint.x - startPoint.x)) or simular
You don't need to calculate angles at all.
double startX = 40;
double startY = 120;
double endX = 110;
double endY = 15;
double deltaX = ( startY - endY ) / 2;
double deltaY = ( endX - startX ) / 2;
double[] polygonX = new double[3];
double[] polygonY = new double[3];
polygonX[0] = endX;
polygonY[0] = endY;
polygonX[1] = startX - deltaX;
polygonY[1] = startY - deltaY;
polygonX[2] = startX + deltaX;
polygonY[2] = startY + deltaY;
The drawing is VERY bad :D, but the point is that:
cos(ang) = 'distance' / ( startY - endY )
and
cod(ang) = ('distance'/2) / deltaX
so
deltaX = ( startY - endY ) / 2
The same aplies to deltaY = ( endX - startX ) / 2
So the other 2 point of the triangle, will be the startPoint minus and plus those deltas.
I am trying to get the x and y value of a point after increasing the distance r. Perhaps there is a better way of calculate the angle phi too, so that I don't need to check in which quadrant the point is. The 0-point is at the half of the width and height of the window. Here is my attempt:
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public final class Laser extends java.applet.Applet implements Runnable{
private static final long serialVersionUID = -7566644836595581327L;
Thread runner;
int width = 800;
int height = 600;
Point point = new Point(405,100);
Point point1 = new Point(405,100);
public void calc(){
int x = getWidth()/2;
int y = getHeight()/2;
int px = point.x;
int py = point.y;
int px1 = point1.x;
int py1 = point1.y;
double r = 0;
double phi = 0;
// Point is in:
// Quadrant 1
if(px > x && py < y){
r = Math.hypot(px1-x, y-py1);
phi = Math.acos((px1-x)/r)*(180/Math.PI);
}/*
// Quadrant 2
else if(px < x && py < y){
r = Math.hypot(x-px, y-py);
phi = Math.acos((px-x)/r)*(180/Math.PI);
}
// Quadrant 3
else if(px < x && py > y){
r = Math.hypot(x-px, py-y);
phi = Math.acos((px-x)/r)*(180/Math.PI)+180;
}
// Quadrant 4
else if(px > x && py > y){
r = Math.hypot(px-x, py-y);
phi = Math.acos((px-x)/r)*(180/Math.PI)+180;
}*/
r += 1;
point1.x = (int) (r*Math.cos(phi));
point1.y = (int) (r*Math.sin(phi));
System.out.println(r+";"+point1.x+";"+point1.y);
}
public void paint(Graphics g) {
g.setColor(Color.ORANGE);
calc();
g.drawLine(point.x, point.y, point1.x, point1.y);
int h = getHeight();
int w = getWidth();
g.setColor(Color.GREEN);
g.drawLine(0, h/2, w, h/2);
g.drawLine(w/2, 0, w/2, h);
}
/*
public void initPoints(){
for(int i = 0; i < pointsStart.length; i++){
int x = (int)(Math.random()*getWidth());
int y = (int)(Math.random()*getHeight());
pointsStart[i] = pointsEnd[i] = new Point(x,y);
}
}
*/
public void start() {
if (runner == null) {
runner = new Thread(this);
setBackground(Color.black);
setSize(width, height);
//initPoints();
runner.start();
}
}
#SuppressWarnings("deprecation")
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public void run() {
while (true) {
repaint();
try { Thread.sleep(700); }
catch (InterruptedException e) { }
}
}
public void update(Graphics g) {
paint(g);
}
}
You are changing (x,y) to be r from some other point, when it had previously been some distance r' from that point, correct? So why not avoid the trigonometry, and just scale each of the components from that point by r/r'?
Edit: ok, iterate over the pixels along whichever component (x or y) is longer (let's assume it's y); for each xi in (0..x), yi = xi*(y/x), and you plot (xi,yi).
Keep it simple! And use double variables for such computations, I changed it for you.
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Point2D;
public final class Laser extends java.applet.Applet implements Runnable {
private static final long serialVersionUID = -7566644836595581327L;
Thread runner;
int width = 800;
int height = 600;
Point2D.Double point = new Point2D.Double(400, 100);
Point2D.Double point1 = new Point2D.Double(405, 102);
public void calc() {
double px = point.x;
double py = point.y;
double px1 = point1.x;
double py1 = point1.y;
double dx = px1 - px;
double dy = py1 - py;
double len = Math.hypot(dx, dy);
double newlen = len+2;
double coeff = Math.abs((newlen-len)/len);
point1.x += dx * coeff;
point1.y += dy * coeff;
System.out.println(len+";"+point1.x+";"+point1.y);
}
public void paint(Graphics g) {
g.setColor(Color.ORANGE);
calc();
g.drawLine((int)point.x, (int)point.y, (int)point1.x, (int)point1.y);
int h = getHeight();
int w = getWidth();
g.setColor(Color.GREEN);
g.drawLine(0, h / 2, w, h / 2);
g.drawLine(w / 2, 0, w / 2, h);
}
/*
* public void initPoints(){
*
* for(double i = 0; i < pointsStart.length; i++){ double x =
* (double)(Math.random()*getWidth()); double y =
* (double)(Math.random()*getHeight()); pointsStart[i] = pointsEnd[i] = new
* Point(x,y); }
*
* }
*/
public void start() {
if (runner == null) {
runner = new Thread(this);
setBackground(Color.black);
setSize(width, height);
// initPoints();
runner.start();
}
}
#SuppressWarnings("deprecation")
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public void run() {
while (true) {
repaint();
try {
Thread.sleep(700);
}
catch (InterruptedException e) {
}
}
}
public void update(Graphics g) {
paint(g);
}
}