How to change the colour of my Mandelbrot Set display? - java

I found some code to display a Mandelbrot set in java, this one has a turqoise colour theme and I was wondering how to change this to another colour, for example a red colour theme. Here is the code:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class Mandelbrot extends JFrame {
private final int MAX_ITER = 570;
private final double ZOOM = 150;
private BufferedImage I;
private double zx, zy, cX, cY, tmp;
public Mandelbrot() {
super("Mandelbrot Set");
setBounds(100, 100, 800, 600);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
zx = zy = 0;
cX = (x - 400) / ZOOM;
cY = (y - 300) / ZOOM;
int iter = MAX_ITER;
while (zx * zx + zy * zy < 4 && iter > 0) {
tmp = zx * zx - zy * zy + cX;
zy = 2.0 * zx * zy + cY;
zx = tmp;
iter--;
}
I.setRGB(x, y, iter | (iter << 8));
}
}
}
#Override
public void paint(Graphics g) {
g.drawImage(I, 0, 0, this);
}
public static void main(String[] args) {
new Mandelbrot().setVisible(true);
}
}
The hex code for red is #FF0000 and the rbg decimal code is (255,0,0) if that helps.
Thanks for your time.

The essense of your code (in coloring) is this
I.setRGB(x, y, iter | (iter << 8));
whatever iter is is plugged into the lower bits and also shifted by 8 bits which corersponds to the Green value in the middle.
So I guess you could try
I.setRGB(x, y, iter << 12);
This will plug the iter value in the upper bits (Red Green).

Related

setRGB not working in Runnable Mandelbrot set

I need to draw the Mandelbrot set using parallel programming, the language used is Java. I employ Runnable tasks to do that. As setRGB is synchronized, I don't need locks to control concurrency and also the BufferedImage shared between all threads is accessed in parallel so it should not be a problem of concurrency. Here is the code below:
public class MandelParalelo extends JFrame
implements Runnable{
private final int MAX_ITER = 100000;
private final double ZOOM = 150;
private static BufferedImage Imagen;
private double zx, zy, cX, cY, tmp;
private int nTareas = 6;
private int linf, lsup;
public void run()
{
for (int y = linf; y < lsup; y++) {
for (int x = 0; x < getWidth(); x++) {
zx = zy = 0;
cX = (x - 400) / ZOOM;
cY = (y - 300) / ZOOM;
int iter = MAX_ITER;
while (zx * zx + zy * zy < 4 && iter > 0) {
tmp = zx * zx - zy * zy + cX;
zy = 2.0 * zx * zy + cY;
zx = tmp;
iter--;
}
Imagen.setRGB(x, y, iter | (iter << 8));//setRGB es synchronized
}
}
}
public MandelParalelo(int i, int s)
{
linf = i;
lsup = s;
}
public MandelParalelo() {
super("Conjunto de Mandelbrot");
setBounds(100, 100, 800, 600);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
Imagen = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_RGB);
ExecutorService ejecutor = Executors.newFixedThreadPool(8);
int inf = 0, tVentana = getHeight()/nTareas, sup = tVentana;
for(int i = 0; i < nTareas; i++)
{
ejecutor.execute(new MandelParalelo(inf, sup));
inf = sup;
sup += tVentana;
}
ejecutor.shutdown();
while(!ejecutor.isTerminated()){}
}
public void paint(Graphics g) {
g.drawImage(Imagen, 0, 0, this);
}
public static void main(String[] args) {
new MandelParalelo().setVisible(true);
}
}
What I have been returned is a black Image:

Draw Line Graph2D with data [duplicate]

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)

Java Code Color Function Error

Aloha,
i have trouble finding the error in my java code. In my opinion everything is fine and correct but the function is not executed correctly and I dont understand why. The function should detect the difference between the colors and calculate the arithmetic mean of them.
The resilt of it should be draw under the original picture. What did I miss, please help me?
package edge;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import javax.swing.JComponent;
import javax.swing.JFrame;
/**
*
* #author Alaska
*/
public class Edge extends JComponent {
final int W = 500;
final int H = 300;
Image m_TrgImg, m_SrcImg;
public Edge(JFrame father) {
try {
FileDialog diag = new FileDialog(father);
diag.setVisible(true);
m_SrcImg = getToolkit().getImage(diag.getDirectory() + diag.getFile()).getScaledInstance(W, H, Image.SCALE_SMOOTH);
MediaTracker mt = new MediaTracker(this);
mt.addImage(m_SrcImg, 0);
mt.waitForAll();
int[] srcPix = new int[W * H];
int[] trgPix = new int[W * H];
PixelGrabber grab = new PixelGrabber(m_SrcImg, 0, 0, W, H, srcPix, 0, W);
grab.getPixels();
MemoryImageSource imgProd = new MemoryImageSource(W, H, trgPix, 0, W);
m_TrgImg = createImage(imgProd);
detectEdges(srcPix, trgPix);
m_TrgImg.flush();
} catch (InterruptedException e) {
System.out.println(e);
}
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(m_SrcImg, 0, 0, this);
g.drawImage(m_TrgImg, 0, H, this);
}
#Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
#Override
public Dimension getMinimumSize() {
return new Dimension(W, H * 2);
}
private void detectEdges(int[] srcPix, int[] trgPix) {
for (int x = 0; x < W; ++x) {
for (int y = 0; y < H; ++y) {
trgPix[y * W + x] = compColor(srcPix, x, y);
}
}
}
private int getRed(int col) {
return (col >> 16) & 255;
}
private int getGreen(int col) {
return (col >> 8) & 255;
}
private int getBlue(int col) {
return col & 255;
}
private int compColor(int[] srcPix, int x, int y) {
int red = 0;
int green = 0;
int blue = 0;
int cnt = 0;
final int IDX = y * W + x;
final int RED = getRed(srcPix[IDX]);
final int GREEN = getGreen(srcPix[IDX]);
final int BLUE = getBlue(srcPix[IDX]);
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
if (dx != 0 || dy != 0) {
final int X = x + dx;
final int Y = y + dy;
final int LOCAL_IDX = Y * W + X;
if (0 <= X && X < W && 0 <= Y && Y < H) {
++cnt;
red += Math.abs(RED - getRed(srcPix[LOCAL_IDX]));
green += Math.abs(GREEN - getGreen(srcPix[LOCAL_IDX]));
blue += Math.abs(BLUE - getBlue(srcPix[LOCAL_IDX]));
}
}
}
}
return 0xff000000 | (255 - (red / cnt) << 16) | (255 - (green / cnt) << 8) | (255 - (blue / cnt));
}
public static void main(String[] args) throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.getContentPane().add(new Edge(f));
f.pack();
f.setVisible(true);
}
}
You need to grab.grabPixels(), not grab.getPixels().
http://docs.oracle.com/javase/7/docs/api/java/awt/image/PixelGrabber.html
Also what trashgod said about Initial Threads. You need to create your GUI with SwingUtilities.invokeLater().
Edit
The method is executed correctly but you are getting all black values on the input because your pixel array contains only the initialized values which is 0.

How to make star shape in Java?

I'm trying to make some shapes with Java. I created two rectangles with two different colors but I want to create a star shape and I can't find useful source to help me doing this.
Here is my code:
import java.awt.*;
import javax.swing.*;
public class shapes extends JPanel{
#Override
public void paintComponent(Graphics GPHCS){
super.paintComponent(GPHCS);
GPHCS.setColor(Color.BLUE);
GPHCS.fillRect(25,25,100,30);
GPHCS.setColor(Color.GRAY);
GPHCS.fillRect(25,65,100,30);
GPHCS.setColor(new Color(190,81,215));
GPHCS.drawString("This is my text", 25, 120);
}
}
You could try using a polygon and some basic math:
int midX = 500;
int midY = 340;
int radius[] = {118,40,90,40};
int nPoints = 16;
int[] X = new int[nPoints];
int[] Y = new int[nPoints];
for (double current=0.0; current<nPoints; current++)
{
int i = (int) current;
double x = Math.cos(current*((2*Math.PI)/max))*radius[i % 4];
double y = Math.sin(current*((2*Math.PI)/max))*radius[i % 4];
X[i] = (int) x+midX;
Y[i] = (int) y+midY;
}
g.setColor(Color.WHITE);
g.fillPolygon(X, Y, nPoints);
You can also use existing classes e.g. http://java-sl.com/shapes.html for regular polygons and stars.
The Polygon class can be considered as a legacy class that has been there since Java 1.0, but should hardly be used any more in new code. The odd way of specifying the x/y coordinates in separate arrays, and, more importantly, the fact that it only supports int[] arrays limits its application areas. Although it implements the Shape interface, there are more modern implementations of this interface that can be used to represent polygons. In most cases, describing the polygon as a Path2D is easier and more flexible. One can create a Path2D p = new Path2D.Double(); and then do a sequence of moveTo and lineTo calls to geneate the desired shape.
The following program shows how the Path2D class may be used to generate star shapes. The most important method is the createStar method. It is very generic. It receives
the center coordinates for the star
the inner and outer radius of the star
the number of rays that the star should have
the angle where the first ray should be (i.e. the rotation angle of the star)
If desired, a simpler method may be wrapped around this one - as with the createDefaultStar example in the code below.
The program shows different stars, painted as lines and filled with different colors and radial gradient paints, as examples:
The complete program as a MCVE:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawStarShape
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new DrawStarShapePanel());
f.setSize(600, 600);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class DrawStarShapePanel extends JPanel
{
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.BLACK);
g.draw(createDefaultStar(50, 200, 200));
g.setPaint(Color.RED);
g.fill(createStar(400, 400, 40, 60, 10, 0));
g.setPaint(new RadialGradientPaint(
new Point(400, 200), 60, new float[] { 0, 1 },
new Color[] { Color.RED, Color.YELLOW }));
g.fill(createStar(400, 200, 20, 60, 8, 0));
g.setPaint(new RadialGradientPaint(
new Point(200, 400), 50, new float[] { 0, 0.3f, 1 },
new Color[] { Color.RED, Color.YELLOW, Color.ORANGE }));
g.fill(createStar(200, 400, 40, 50, 20, 0));
}
private static Shape createDefaultStar(double radius, double centerX,
double centerY)
{
return createStar(centerX, centerY, radius, radius * 2.63, 5,
Math.toRadians(-18));
}
private static Shape createStar(double centerX, double centerY,
double innerRadius, double outerRadius, int numRays,
double startAngleRad)
{
Path2D path = new Path2D.Double();
double deltaAngleRad = Math.PI / numRays;
for (int i = 0; i < numRays * 2; i++)
{
double angleRad = startAngleRad + i * deltaAngleRad;
double ca = Math.cos(angleRad);
double sa = Math.sin(angleRad);
double relX = ca;
double relY = sa;
if ((i & 1) == 0)
{
relX *= outerRadius;
relY *= outerRadius;
}
else
{
relX *= innerRadius;
relY *= innerRadius;
}
if (i == 0)
{
path.moveTo(centerX + relX, centerY + relY);
}
else
{
path.lineTo(centerX + relX, centerY + relY);
}
}
path.closePath();
return path;
}
}
I have 2 method.
1)
public static Bitmap drawStar(int W, int H, int color, boolean andRing)
{
Path path = new Path();
Bitmap output = Bitmap.createBitmap(W, H, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
float midW ,min ,fat ,half ,radius;
if(andRing)
{
midW = W / 2;
min = Math.min(W, H);
half = min / 2;
midW = midW - half;
fat = min / 17;
radius = half - fat;
paint.setStrokeWidth(fat);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(midW + half, half, radius, paint);
path.reset();
paint.setStyle(Paint.Style.FILL);
path.moveTo( half * 0.5f, half * 0.84f);
path.lineTo( half * 1.5f, half * 0.84f);
path.lineTo( half * 0.68f, half * 1.45f);
path.lineTo( half * 1.0f, half * 0.5f);
path.lineTo( half * 1.32f, half * 1.45f);
path.lineTo( half * 0.5f, half * 0.84f);
}
else
{
min = Math.min(W, H);
half = min/2;
path.reset();
paint.setStyle(Paint.Style.FILL);
path.moveTo( half * 0.1f , half * 0.65f);
path.lineTo( half * 1.9f , half * 0.65f);
path.lineTo( half * 0.40f , half * 1.65f);
path.lineTo( half , 0 );
path.lineTo( half * 1.60f, half * 1.65f);
path.lineTo( half * 0.1f, half * 0.65f);
}
canvas.drawPath(path, paint);
return output;
}
2)
public static Bitmap drawStar(int W,int H,int spikes,int innerRadius,int outerRadius, int backColor,boolean border, int borderColor)
{
if(W < 10)
W = 10;
if(H < 10)
H = 10;
if(spikes < 5)
spikes = 5;
int smallL = W;
if(H < W)
smallL = H;
if(outerRadius > smallL/2)
outerRadius = smallL/2;
if(innerRadius < 5)
innerRadius = 5;
if(border)
{
outerRadius -=2;
innerRadius -=2;
}
Path path = new Path();
Bitmap output = Bitmap.createBitmap(W, H, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(backColor);
int cx = W/2;
int cy = H/2;
double rot = Math.PI / 2 * 3;
float x,y;
double step = Math.PI / spikes;
path.moveTo(cx, cy - outerRadius);
for (int i = 0; i < spikes; i++)
{
x = (float) (cx + Math.cos(rot) * outerRadius);
y = (float) (cy + Math.sin(rot) * outerRadius);
path.lineTo(x, y);
rot += step;
x = (float) (cx + Math.cos(rot) * innerRadius);
y = (float) (cy + Math.sin(rot) * innerRadius);
path.lineTo(x, y);
rot += step;
}
path.lineTo(cx, cy - outerRadius);
path.close();
canvas.drawPath(path, paint);
if(border)
{
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(borderColor);
canvas.drawPath(path, paint);
}
return output;
}

How do i align this text correctly?

I wrote this polar clock today and i am almost finished exept i want to align my text inside the line similar to this. Does anyone know how to do this? Ive tried to use FontRenderContext and font metrics but i cant seem to get it to work. Here is the whole source code so you can compile it and see for yourselves.
import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.Calendar;
import java.util.TimeZone;
public class Clock extends Applet implements Runnable {
int[][] colorsInt = {{20,20,20},{100,100,50},{50,100,100},{10,170,50},{79,29,245},{24,69,234},{253,24,103}};
Color[] colors;
int size;
int radius;
boolean anitalias = false;
static final float HPI = (float)(Math.PI / 180f);
public void start() {
enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
new Thread(this).start();
}
public void run() {
setSize(500, 500); // For AppletViewer, remove later.
// Set up the graphics stuff, double-buffering.
BufferedImage screen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D)screen.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
WritableRaster wr = screen.getRaster();
Graphics appletGraphics = getGraphics();
// Some variables to use for the fps.
long fpstn = 1000000000 / 600;
int tick = 0, fps = 0, acc = 0;
long lastTime = System.nanoTime();
// Vars
Calendar c;
size = 500;
radius = size / 2;
Arc2D.Float arch;
float scale, radians;
long miliSecond;
int second, minute, hour, month, year, dayOfWeek, dayOfMonth, dayOfYear, daysInMonth, daysInYear;
float[] tvars = new float[6];
float[] vars = new float[6];
String[] names = new String[6];
FontMetrics fm = g.getFontMetrics();
Font font = g.getFont();
FontRenderContext frc = g.getFontRenderContext();
GlyphVector gv = font.createGlyphVector(frc, "Hello world");
int length = gv.getNumGlyphs();
// Init
initColors();
for (int i = 0; i < vars.length; i++)
vars[i] = 0;
// Game loop.
while (true) {
long now = System.nanoTime();
acc += now - lastTime;
tick++;
if (acc >= 1000000000L) {
acc -= 1000000000L;
fps = tick;
tick = 0;
}
// Update
c = Calendar.getInstance();
miliSecond = c.get(Calendar.MILLISECOND);
second = c.get(Calendar.SECOND);
minute = c.get(Calendar.MINUTE);
hour = c.get(Calendar.HOUR_OF_DAY);
dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
dayOfYear = c.get(Calendar.DAY_OF_YEAR);
dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
month = c.get(Calendar.MONTH);
daysInMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH);
daysInYear = c.getActualMaximum(Calendar.DAY_OF_YEAR);
tvars[0] = (second * 1000 + miliSecond) / 60000f * 360f;
tvars[1] = (minute * 60f + second) / 3600f * 360f;
tvars[2] = (hour * 60f + minute) / 1440f * 360f;
tvars[3] = ((dayOfWeek - 2) * 24f + hour) / 168f * 360f;
tvars[4] = ((dayOfMonth - 1) * 24f + hour) / (daysInMonth * 24f) * 360f;
tvars[5] = dayOfYear / (float)daysInYear * 360f;
for (int i = 0; i < vars.length; i++) {
if (tvars[i] - vars[i] > 1) {
vars[i] += (tvars[i] - vars[i]) / 15;
} else if(tvars[i] - vars[i] < -1) {
vars[i] -= (vars[i] - tvars[i]) / 15;
} else {
vars[i] = tvars[i];
}
}
names[0] = second + " Second" + (second > 1 ? "s" : "");
lastTime = now;
// Render
g.setColor(colors[0]);
g.fillRect(0, 0, size, size);
for (int i = 0; i < vars.length; i++) {
scale = i / (float)vars.length * radius * 1.7f;
g.setColor(colors[0]);
g.fillOval((int)(scale / 2), (int)(scale / 2), (int)(size - scale), (int)(size - scale));
g.setColor(colors[i + 1]);
scale += 15;
arch = new Arc2D.Float(scale / 2, scale / 2, size - scale, size - scale, 450 - vars[i], vars[i], Arc2D.PIE);
g.fill(arch);
g.setColor(Color.WHITE);
radians = (vars[i]) * HPI;// vars[i] - 90
scale = ((float)(vars.length - i) / (float)vars.length * (float)radius / 2f * 1.7f) + 15f;
g.translate(radius, radius);
System.out.println(i + ": " + ((1 - scale / radius) * 2));
for (int j = 0; j < names[0].length(); j++) {
char ch = names[0].charAt(j);
radians = ((vars[i] - (names[0].length() - j) * 2) * (1 + (1 - scale / radius) * 2)) * HPI;
g.rotate(radians);
g.drawString(ch + "", 0, -scale);
g.rotate(-radians);
}
g.translate(-radius, -radius);
/*float x = (float)Math.cos(radians) * scale;
float y = (float)Math.sin(radians) * (vars.length - i) / vars.length * radius / 2 * 1.7f;
g.drawRect((int)x + size / 2, (int)y + size / 2, 10, 10);*/
}
scale = vars.length / (float)vars.length * radius * 1.7f;
g.setColor(colors[0]);
g.fillOval((int)(scale / 2), (int)(scale / 2), (int)(size - scale), (int)(size - scale));
g.setColor(Color.WHITE);
g.drawString("FPS " + String.valueOf(fps), 20, 30);
// Draw the entire results on the screen.
appletGraphics.drawImage(screen, 0, 0, null);
do {
Thread.yield();
} while (System.nanoTime() - lastTime < 0);
if (!isActive()) {
return;
}
}
}
public void initColors() {
colors = new Color[colorsInt.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = new Color(colorsInt[i][0], colorsInt[i][1], colorsInt[i][2]);
}
}
}
Here's a simple example of rotating text.
Addendum: You'll want to adjust the the text's radial starting point by stringWidth(name[n]). Your program appears to be rotating individual characters in a effort to follow the arc, while the example appears to be drawing the text in a straight line tangent to the arc. The latter approach may prove simpler. For example, this variation centers the labels across the arc's getStartPoint():
for (int i = 0; i < vars.length; i++) {
...
String s = names[0];
int w = fm.stringWidth(s);
int h = fm.getHeight() + fm.getMaxDescent();
Point2D p = arch.getStartPoint();
int x = (int) p.getX();
int y = (int) p.getY();
radians = (vars[i]) * HPI;
g.rotate(radians, x, y);
g.drawString(s, x - w / 2, y + h);
g.rotate(-radians, x, y);
}
For convenience the code above does rotate() to and fro; for comparison, here's the original example showing repeated concatenations of rotate():
import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
/** #see http://stackoverflow.com/questions/6238037 */
public class RotateText extends JPanel {
private static final Font f = new Font("Serif", Font.BOLD, 32);
private static final String s = "Hello World!";
private static final Color[] colors = {
Color.red, Color.green, Color.blue, Color.cyan
};
private Graphics2D g2d;
private AffineTransform at;
public RotateText() {
setPreferredSize(new Dimension(400, 400));
}
#Override
public void paintComponent(Graphics g) {
g2d = (Graphics2D) g;
g2d.setFont(f);
g2d.setColor(Color.black);
g2d.fillRect(0, 0, getWidth(), getHeight());
at = g2d.getTransform();
int w = this.getWidth();
int h = this.getHeight();
int w2 = g2d.getFontMetrics().stringWidth(s) / 2;
int h2 = 2 * g2d.getFontMetrics().getHeight() / 3;
render(0, w / 2 - w2, h - h2);
render(1, h2, h / 2 - w2);
render(2, w / 2 + w2, h2);
render(3, w - h2, h / 2 + w2);
g2d.setTransform(at);
g2d.setColor(Color.yellow);
g2d.fillRect(w / 3, h / 3, w / 3, h / 3);
}
private void render(int n, int x, int y) {
g2d.setColor(colors[n]);
g2d.setTransform(at);
g2d.rotate(n * Math.PI / 2, x, y);
g2d.drawString(s, x, y);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
//#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new RotateText(), BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
});
}
}
You have to be able to draw text along the curves. There are several ways to do it, but the simplest one is to use Stroke API. You can find an example at http://www.jhlabs.com/java/java2d/strokes/
The other way is using affine transforms. The example is at http://www.java2s.com/Code/Java/2D-Graphics-GUI/Drawtextalongacurve.htm

Categories