Related
I am trying to add numbers around the clock from 1 to 12. The clock is not drawing the numbers. I have the clock drawn and the hour, minute, and second hands drawn.
import java.util.Calendar;
import java.util.GregorianCalendar;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
public class ClockPane extends Pane {
private int hour;
private int minute;
private int second;
/** Construct a default clock with the current time */
public ClockPane() {
setCurrentTime();
}
/** Construct a clock with specified hour, minute, and second */
public ClockPane(int hour, int minute, int second) {
this.hour = hour;
this.minute = minute;
this.second = second;
}
/** Return hour */
public int getHour() {
return hour;
}
/** Set a new hour */
public void setHour(int hour) {
this.hour = hour;
paintClock();
}
/** Return minute */
public int getMinute() {
return minute;
}
/** Set a new minute */
public void setMinute(int minute) {
this.minute = minute;
paintClock();
}
/** Return second */
public int getSecond() {
return second;
}
/** Set a new second */
public void setSecond(int second) {
this.second = second;
paintClock();
}
/* Set the current time for the clock */
public void setCurrentTime() {
// Construct a calendar for the current date and time
Calendar calendar = new GregorianCalendar();
// Set current hour, minute and second
this.hour = calendar.get(Calendar.HOUR_OF_DAY);
this.minute = calendar.get(Calendar.MINUTE);
this.second = calendar.get(Calendar.SECOND);
paintClock(); // Repaint the clock
}
private void paintClock() {
// Initialize clock parameters
double clockRadius = Math.min(getWidth(), getHeight()) * 0.8 * 0.5;
double centerX = getWidth() / 2;
double centerY = getHeight() / 2;
// Draw circle
Circle circle = new Circle(centerX, centerY, clockRadius);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
// Draw hour markers
double numberRadius = clockRadius * 0.85;
for (int i = 1; i <= 12; i++) {
double numberX = centerX + numberRadius * Math.sin(i * 2 * Math.PI / 12);
double numberY = centerY - numberRadius * Math.cos(i * 2 * Math.PI / 12);
Text number = new Text(numberX - 5, numberY + 5, "" + i);
number.setFill(Color.BLACK);
getChildren().addAll(number);
}
// Draw second hand
double sLength = clockRadius * 0.8;
double secondX = centerX + sLength * Math.sin(second * (2 * Math.PI / 60));
double secondY = centerY - sLength * Math.cos(second * (2 * Math.PI / 60));
Line sLine = new Line(centerX, centerY, secondX, secondY);
sLine.setStroke(Color.RED);
// Draw minute hand
double mLength = clockRadius * 0.65;
double xMinute = centerX + mLength * Math.sin(minute * (2 * Math.PI / 60));
double minuteY = centerY - mLength * Math.cos(minute * (2 * Math.PI / 60));
Line mLine = new Line(centerX, centerY, xMinute, minuteY);
mLine.setStroke(Color.BLUE);
// Draw hour hand
double hLength = clockRadius * 0.5;
double hourX =
centerX + hLength * Math.sin((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
double hourY =
centerY - hLength * Math.cos((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
Line hLine = new Line(centerX, centerY, hourX, hourY);
hLine.setStroke(Color.GREEN);
getChildren().clear(); // Clear the pane
getChildren().addAll(circle, sLine, mLine, hLine);
}
#Override
public void setWidth(double width) {
super.setWidth(width);
paintClock();
}
#Override
public void setHeight(double height) {
super.setHeight(height);
paintClock();
}
}
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
public class DisplayClock extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a clock and a label
ClockPane clock = new ClockPane();
String timeString = clock.getHour() + ":" + clock.getMinute() + ":" + clock.getSecond();
Label lblCurrentTime = new Label(timeString);
// Place clock and label in border pane
BorderPane pane = new BorderPane();
pane.setCenter(clock);
pane.setBottom(lblCurrentTime);
BorderPane.setAlignment(lblCurrentTime, Pos.TOP_CENTER);
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("DisplayClock"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
When I run the program the numbers are not showing on the clock. I check the imports. It's correct. The code is also correct. I don't know why it's not showing. What should I do to fix it?
I made a game in java to practice mouse accuracy on JGrasp with the little knowledge I have with programming. Now I'm trying to create a jar file for it. However, I don't have a main class and I just run it within JGrasp at the moment. I've been trying to figure out how to run it with a main class but all the things I tried didn't work. My understanding is really low. I have no idea what to do. I don't know how to make it so my code can be accessed by a main method.
import java.awt.event.*;
import java.awt.*;
import java.util.Random;
import java.awt.Graphics;
import java.awt.Image;
import java.util.Timer;
public class Aim extends java.applet.Applet implements Runnable, MouseListener, ComponentListener {
// position of center circle (coordinates)
private int scale = 500; // decide size of game
private int seed;
private int turn;
private Dimension size;
private Image image;
private Image background;
private Image gameOverImg;
private Image timerImgOnes;
private Image timerImgTens;
private Image timerImgMins;
private Image timerImgColon;
private Image scorePerMinImg;
private Image speedUpImg;
private Image lifeImg;
private Image yourTime;
private Graphics g;
private double targetScale = 6; // scale of targets (higher number = smaller targets)
private double originalTargetScale = targetScale;
private int circleScale = (int) (scale / targetScale);
private int circleScale2 = (int) (scale / (targetScale*1.35));
private int originalCircleScale = circleScale;
private int originalCircleScale2 = circleScale2;
private int eraseScale = (int) (scale / (targetScale-(targetScale*.1)));
private int eraseOffset = circleScale / 2;
private int mx = (scale/2) - (circleScale2/2);
private int my = mx;
private int mxO = mx;
private int myO = mx;
private double distScale = 1.3; // scale of how close the targets will be to each other
private int flick = 1;
private int flick2 = 1;
long tStart = System.currentTimeMillis();
long tEnd = System.currentTimeMillis();
long tDelta = tEnd - tStart;
double elapsedSeconds = tDelta / 1000.0;
private int gameOver;
private int newGame;
private int life = 3; // amount of lives
// used to determine users score per minute
private double score = 1;
private double scorePerMin;
private double requiredScorePerMin;
private int difficulty = 30; // Choose difficulty of speed. Lower # is harder
private int distance1 = (int) Math.hypot(circleScale*distScale, circleScale*distScale);
private int distance2 = (int) (circleScale * distScale);
// array for possible spots for the outer circle to spawn
private int[] mx2 = { mx + distance1, mx + distance2, mx + distance2, mx, mx, mx-distance1, mx-distance2, mx-distance2, };
private int[] my2 = { my, my-distance2, my+distance2, my-distance1, my+distance1, my, my-distance2, my+distance2, };
Random random = new Random();
Thread runner;
Timer T = new Timer();
// variables & array to paint timer & speed bar
private String[] timerImgArray = { "res/zero.png", "res/one.png", "res/two.png", "res/three.png", "res/four.png", "res/five.png", "res/six.png", "res/seven.png", "res/eight.png", "res/nine.png" };
private int ones;
private int tens;
private int mins;
private int timerDisplayScale;
private int timerCenter;
private int temp;
private int elapsedSecondsShort;
private int c;
private int timerDisplacement;
private int scoreBarSize;
private String[] lifeImgArray = { "res/life0.png", "res/life1.png", "res/life2.png", "res/life3.png" };
public void start() {
if (runner == null) {
runner = new Thread(this);
long tStart = System.currentTimeMillis();
runner.start();
}
}
public void run() {
while (true) {
if (life > 0) {
// Timer used for gametime display & score per minute calculation
tEnd = System.currentTimeMillis();
tDelta = tEnd - tStart;
elapsedSeconds = tDelta / 1000.0;
temp = (int)(elapsedSeconds*1);
elapsedSecondsShort = ((int)temp)/1;
c++;
if (requiredScorePerMin > scorePerMin) {
life = 0;
gameOver=1;
}
// calculate score per minute & required score per minute
scorePerMin = 60 * (score / elapsedSeconds);
requiredScorePerMin = 60 * (1 + (elapsedSeconds / difficulty));
// update all variables each frame
circleScale = (int) (scale / targetScale);
circleScale2 = (int) (scale / (targetScale*1.35));
eraseScale = (int) (scale / (targetScale-(targetScale*.1)));
eraseOffset = circleScale / 2;
mx = (scale/2) - (circleScale2/2);
my = mx;
distance1 = (int) Math.hypot(circleScale*distScale, circleScale*distScale);
distance2 = (int) (circleScale * distScale);
int zoomSize1 = (int)(scale/(originalCircleScale2/2.5));
int zoomSize2 = (int)(scale/(originalCircleScale/2.5));
// Calculates how much each circle will change in size throughout each zoom
if (Math.abs(circleScale - originalCircleScale) >= zoomSize1) flick*=-1;
if (Math.abs(circleScale2 - originalCircleScale2) >= zoomSize2) flick2*=-1;
// increases & decreases the size of targets
if (turn == 1){
if (flick2==-1) targetScale+= .05;
else targetScale-= .05;
}
if (turn == 0){
if (flick==-1) targetScale+= .05;
else targetScale-= .05;
}
// updates coordinates of outer circle
if (turn==1){
switch (seed) {
case 0:
mx2[seed] = mxO + distance1;
my2[seed] = myO;
break;
case 1:
mx2[seed] = mxO + distance2;
my2[seed] = myO - distance2;
break;
case 2:
mx2[seed] = mxO + distance2;
my2[seed] = myO + distance2;
break;
case 3:
mx2[seed] = mxO;
my2[seed] = myO - distance1;
break;
case 4:
mx2[seed] = mxO;
my2[seed] = myO + distance1;
break;
case 5:
mx2[seed] = mxO - distance1;
my2[seed] = myO;
break;
case 6:
mx2[seed] = mxO - distance1;
my2[seed] = myO - distance2;
break;
case 7:
mx2[seed] = mxO - distance2;
my2[seed] = myO - distance2;
break;
case 8:
mx2[seed] = mxO - distance2;
my2[seed] = my + distance2;
break;
}
}
// Finish updating variables
repaint();
if (life == 0) {
stop();
}
try { Thread.sleep(7); }
catch (InterruptedException e) {}
}
}
}
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
public void init() {
setSize(scale, scale);
size = getSize();
addMouseListener(this);
background = getImage(getDocumentBase(), "res/background.jpg");
gameOverImg = getImage(getDocumentBase(), "res/gameOver.jpg");
image = getImage(getDocumentBase(), "res/aim.png");
scorePerMinImg = getImage(getDocumentBase(), "res/SPM.png");
speedUpImg = getImage(getDocumentBase(), "res/speedUp.png");
}
public void update(Graphics g) {
Dimension newSize = getSize();
if (size.equals(newSize)) {
paint(g);
}
}
// paint center circle
public void paint(Graphics g) {
if (gameOver != 1){
if (turn == 0){
flick2 = -1;
scoreBarSize = (int) (scorePerMin - requiredScorePerMin);
g.setColor(Color.black);
g.drawImage(background, 0, 0, scale, scale, this);
timerDisplay();
g.drawImage(timerImgOnes, timerCenter + (timerDisplayScale / 2), 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(timerImgTens, timerCenter + (timerDisplayScale / 4), 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(timerImgMins, timerCenter - (timerDisplayScale/4), 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(timerImgColon, timerCenter, 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(scorePerMinImg, (scale/2) - scoreBarSize/2, scale - (scale/20), scoreBarSize, originalCircleScale2 / 4, this);
if (scoreBarSize < 35) g.drawImage(speedUpImg, (scale/2) - (originalCircleScale2/2), scale - (scale/11), scale/8, scale/20, this);
lifeImg = getImage(getDocumentBase(), lifeImgArray[life]);
g.drawImage(lifeImg, scale - (scale/14), (scale/2) - (originalCircleScale2/2), scale / 15, scale / 6, this);
g.drawImage(image, mx, my , circleScale2, circleScale2, this);
} else { // paint outer, moving circle
flick = -1;
scoreBarSize = (int) (scorePerMin - requiredScorePerMin);
g.drawImage(background, 0, 0, scale, scale, this);
g.drawImage(image, mx2[seed], my2[seed], circleScale, circleScale, this);
timerDisplay();
g.drawImage(timerImgOnes, timerCenter + (timerDisplayScale / 2), 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(timerImgTens, timerCenter + (timerDisplayScale / 4), 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(timerImgMins, timerCenter - (timerDisplayScale/4), 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(timerImgColon, timerCenter, 25 , originalCircleScale2 / 2, originalCircleScale2 / 2, this);
g.drawImage(scorePerMinImg, (scale/2) - scoreBarSize/2, scale - (scale/20), scoreBarSize, originalCircleScale2 / 4, this);
if (scoreBarSize < 35) g.drawImage(speedUpImg, (scale/2) - (originalCircleScale2/2), scale - (scale/11), scale/8, scale/20, this);
lifeImg = getImage(getDocumentBase(), lifeImgArray[life]);
g.drawImage(lifeImg, scale - (scale/14), (scale/2) - (originalCircleScale2/2), scale / 15, scale / 6, this);
}
} else{
g.drawImage(gameOverImg, 0, 0, scale, scale, this);
g.drawImage(timerImgOnes, scale - scale/3 + (timerDisplayScale / 2) - timerDisplayScale/3, scale - scale/7 , (originalCircleScale2/3)*2, (originalCircleScale2/3)*2, this);
g.drawImage(timerImgTens, scale - scale/3 + (timerDisplayScale / 4) - timerDisplayScale/3, scale - scale/7 , (originalCircleScale2/3)*2, (originalCircleScale2/3)*2, this);
g.drawImage(timerImgMins, scale - scale/3 - (timerDisplayScale / 4) - timerDisplayScale/3, scale - scale/7 , (originalCircleScale2/3)*2, (originalCircleScale2/3)*2, this);
g.drawImage(timerImgColon, scale - scale/3 - timerDisplayScale/3, scale - scale/7 , (originalCircleScale2/3)*2, (originalCircleScale2/3)*2, this);
g.drawImage(yourTime, timerCenter - ((timerDisplayScale*2)), scale - (scale/6) , scale/2, scale / 9, this);
}
}
// updating the timer images
public void timerDisplay(){
if ((c == 128) && (ones != 9)) {
ones++;
c = 0;
}
if ((ones == 9) && ( c == 128)){
tens++;
ones = 0;
c = 0;
}
if ((tens == 5) && (ones == 9) && (c == 128)) {
mins++;
tens = 0;
ones = 0;
c = 0;
}
timerDisplacement = timerDisplayScale/4;
timerDisplayScale = scale / 5;
timerCenter = (scale / 2) - timerDisplacement;
timerImgOnes = getImage(getDocumentBase(), timerImgArray[ones]);
timerImgTens = getImage(getDocumentBase(), timerImgArray[tens]);
timerImgMins = getImage(getDocumentBase(), timerImgArray[mins]);
timerImgColon = getImage(getDocumentBase(), "res/colon.png");
yourTime = getImage(getDocumentBase(), "res/yourTime.png");
}
/*
* Mouse methods
*/
public void mousePressed(MouseEvent e) {
if (turn == 0) seed = random.nextInt(8);
if (turn == 1) turn = 0; else turn = 1;
targetScale = originalTargetScale; // reset size of circle each time it is spawned
if (Math.abs(circleScale - originalCircleScale) >= 20) flick*=-1;
if (Math.abs(circleScale2 - originalCircleScale2) >= 20) flick2*=-1;
int x = e.getX();
int y = e.getY();
e.consume();
requestFocus();
int xDif = x - mx - (circleScale2 / 2);
int yDif = y - my - (circleScale2 / 2);
int xDif2 = x - mx2[seed] - (circleScale / 2);
int yDif2 = y - my2[seed] - (circleScale / 2);
if (gameOver != 1){
//determine if hit
if ((Math.hypot(xDif, yDif) <= (circleScale2 / 2) && turn == 1) || (Math.hypot(xDif2, yDif2) <= (circleScale / 2) && turn == 0)){
score++;
getAppletContext().showStatus("HIT");
play(getCodeBase(), "sounds/hit.au");
}
else { //miss
life--;
if (life == 0) {
gameOver=1;
}
getAppletContext().showStatus("MISSED");
play(getCodeBase(), "sounds/whoosh.au");
}
}
repaint();
}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {}
public void componentHidden(ComponentEvent e) {}
public void componentMoved(ComponentEvent e) {}
public void componentResized(ComponentEvent e) {
repaint();
}
public void componentShown(ComponentEvent e) {
}
public void destroy() {
removeMouseListener(this);
}
public String getAppletInfo() {
return "Title: Mouse Accuracy";
}
}
The java main method is:
public static void main(String [ ] args){
//do stuff
}
Put your starting method in and it will run fine.
I would still recommend you the swing JFrame instead of the applet bc it is way more updated and handy in my opinion.
I'm struggling with a problem: I want to access openstreetmap via my Java application. I wrote a JComponent which is able to show tiles downloaded from openstreetmap. The problem is that in the formula which calculates the y-position (see FIXME in the sourcecode) of the downloaded picture it is an error and I'm not able to find it. Some parts of the code are copied from http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames. The crazy thing is that the x-position is correct. The goTo() method is used to determine which place of the map should be in the center of the JComponent-View!
package ui;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JComponent;
public class OSMViewer extends JComponent {
private static final long serialVersionUID = 1L;
protected ImageHandler imagehandler = null;
protected int zoomlevel = 0;
protected double center_deg_lon = 0.0;
protected double center_deg_lat = 0.0;
final double DEGY = 85.0511;
final double DEGX = 180.0;
public OSMViewer(ImageHandler imagehandler) {
this.imagehandler = imagehandler;
// TODO
goTo(13, 30.0, 30.0);
}
public void goTo(final int zoom, final double lon, final double lat) {
zoomlevel = zoom;
center_deg_lon = lon;
center_deg_lat = lat;
repaint();
}
// deg
public int getTileNumberX(final int zoom, final double lon) {
int xtile = (int) Math.floor((lon + 180) / 360 * (1 << zoom));
return xtile;
}
// deg
public int getTileNumberY(final int zoom, final double lat) {
int ytile = (int) Math
.floor((1 - Math.log(Math.tan(Math.toRadians(lat)) + 1
/ Math.cos(Math.toRadians(lat)))
/ Math.PI)
/ 2 * (1 << zoom));
return ytile;
}
// deg
public double getLonDegPx(final int zoom) {
double deg_px = 2 * DEGX / (Math.pow(2, zoom) * 256);
return deg_px;
}
// deg
public double getLatDegPx(final int zoom) {
double deg_px = 2 * DEGY / (Math.pow(2, zoom) * 256);
return deg_px;
}
// deg
public int getPxX(final int zoom, final double lon) {
return (int) (((lon + DEGX) / (2 * DEGX)) * Math.pow(2, zoom) * 256);
}
// deg
public int getPxY(final int zoom, final double lat) {
return (int) (((DEGY - lat) / (2.0 * DEGY)) * Math.pow(2.0, zoom) * 256.0);
}
public void paintComponent(Graphics g) {
int x = getTileNumberX(zoomlevel, center_deg_lon);
int y = getTileNumberY(zoomlevel, center_deg_lat);
String str = ("" + zoomlevel + "/" + x + "/" + y);
System.out.println(str);
int xpos = (x * 256) - getPxX(zoomlevel, center_deg_lon)
+ (getWidth() / 2);
// FIXME
int ypos = (y * 256) - getPxY(zoomlevel, center_deg_lat)
+ (getHeight() / 2);
Image image = imagehandler.getImage(str);
if (image != null) {
g.drawImage(image, xpos, ypos, this);
}
g.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
}
}
Nice to hear that you were able to fix your problem :)
Please also note, that OSM runs on donated ressources and has restrictions on how people access the rendererd map tiles: http://wiki.openstreetmap.org/wiki/Tile_usage_policy Please pay attention that your app respects it, to avoid stressing the community servers.
i am having a bug which i can't figure out.I tried many times,the collision detection and calculating new velocities seems fine ,but some balls seem to stuck with each other i don't why.Can you please help me out.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;
import javax.swing.JFrame;
public class ElasticCollision extends Canvas implements Runnable {
private static final int WIDTH = 300;
private static final int HEIGHT = WIDTH / 16 * 9;
private static final int SCALE = 3;
private static final String TITLE = "Elastic collision";
private boolean running = false;
private JFrame frame;
private Thread thread;
private Random random = new Random();
private Color color;
private int a, b, c;
private Ball[] ball;
private int x = 0, y = 0;
private int radius = 0;
private int speedX = 0, speedY = 0;
private int noOfBalls = 25;
private double newVelX1 = 0, newVelY1 = 0;
private double newVelX2 = 0, newVelY2 = 0;
private double angle1 = 0, angle2 = 0, angle3 = 0;
private int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
public ElasticCollision() {
Dimension size = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
setPreferredSize(size);
frame = new JFrame();
ball = new Ball[noOfBalls];
}
public void start() {
for (int i = 0; i < noOfBalls; i++) {
x = random.nextInt(getWidth());
y = random.nextInt(getHeight());
radius = 25 + random.nextInt(25);
speedX = 1 + random.nextInt(2);
speedY = 1 + random.nextInt(2);
ball[i] = new Ball(x, y, radius, speedX, speedY);
}
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
}
public void run() {
long lastTime = System.nanoTime();
double unprocessed = 0;
double nsPerTick = 1000000000.0 / 60;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
while (running) {
long now = System.nanoTime();
unprocessed += (now - lastTime) / nsPerTick;
lastTime = now;
while (unprocessed >= 1) {
ticks++;
update();
unprocessed -= 1;
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < noOfBalls; i++) {
for (int j = i + 1; j < noOfBalls; j++) {
if (ball[i].inCollision != true
|| ball[j].inCollision != true)
checkCollision(ball[i], ball[j]);
}
}
frames++;
render();
if (System.currentTimeMillis() - lastTimer > 1000) {
lastTimer += 1000;
frame.setTitle(TITLE + " | " + ticks + " ticks, " + frames
+ " fps");
frames = 0;
ticks = 0;
}
}
stop();
}
public void update() {
for (int i = 0; i < noOfBalls; i++) {
ball[i].x += ball[i].speedX;
ball[i].y += ball[i].speedY;
if (ball[i].x >= getWidth() - ball[i].radius && ball[i].speedX > 0)
ball[i].speedX = -ball[i].speedX;
if (ball[i].x <= ball[i].radius && ball[i].speedX < 0)
ball[i].speedX = -ball[i].speedX;
if (ball[i].y >= getHeight() - ball[i].radius && ball[i].speedY > 0)
ball[i].speedY = -ball[i].speedY;
if (ball[i].y <= ball[i].radius && ball[i].speedY < 0)
ball[i].speedY = -ball[i].speedY;
}
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.yellow);
g.fillRect(0, 0, getWidth(), getHeight());
for (int i = 0; i < noOfBalls; i++)
ball[i].paint(g);
g.dispose();
bs.show();
}
public void checkCollision(Ball ball1, Ball ball2) {
double distance;
if (ball1.x + ball1.radius + ball2.radius > ball2.x
&& ball1.x < ball1.x + ball1.radius + ball2.radius
&& ball1.y + ball1.radius + ball2.radius > ball2.y
&& ball1.y < ball2.y + ball1.radius + ball2.radius) {
distance = Math.sqrt(((ball1.x - ball2.x) * (ball1.x - ball2.x))
+ ((ball1.y - ball2.y) * (ball1.y - ball2.y)));
if ((int) distance < ball1.radius + ball2.radius) {
ball1.collision = true;
ball2.collision = true;
ball1.inCollision = true;
ball2.inCollision = true;
ball1.collisionX = ((ball1.x * ball2.radius) + (ball2.x * ball1.radius))
/ (ball1.radius + ball2.radius) + ball1.radius;
ball1.collisionY = ((ball1.y * ball2.radius) + (ball2.y * ball1.radius))
/ (ball1.radius + ball2.radius) + ball1.radius;
ball2.collisionX = ((ball1.x * ball2.radius) + (ball2.x * ball1.radius))
/ (ball1.radius + ball2.radius) + ball2.radius;
ball2.collisionY =
((ball1.y * ball2.radius) + (ball2.y * ball1.radius))
/ (ball1.radius + ball2.radius) + ball2.radius;
/*
* x1 = (ball1.x - getWidth()) / 2; y1 = (ball2.y - getHeight())
* / 2; angle1 = Math.toDegrees(Math.atan2(y1, x1));
*
* x2 = (ball1.x - getWidth()) / 2; y2 = (ball2.y - getHeight())
* / 2; angle2 = Math.toDegrees(Math.atan2(y2, x2));
*/
double colision_angle = Math.toDegrees(Math.atan2(
(ball2.y - ball1.y), (ball2.x - ball1.x)));
double speed1 = Math.sqrt(ball1.speedX * ball1.speedX
+ ball1.speedY * ball1.speedY);
double speed2 = Math.sqrt(ball2.speedX * ball2.speedX
+ ball2.speedY * ball2.speedY);
double direction1 = Math.atan2(ball1.speedY, ball1.speedX);
double direction2 = Math.atan2(ball2.speedY, ball2.speedX);
double vx_1 = speed1 * Math.cos(direction1 - colision_angle);
double vy_1 = speed1 * Math.sin(direction1 - colision_angle);
double vx_2 = speed2 * Math.cos(direction2 - colision_angle);
double vy_2 = speed2 * Math.sin(direction2 - colision_angle);
double final_vx_1 = ((ball1.radius - ball2.radius) * vx_1 + (ball2.radius + ball2.radius)
* vx_2)
/ (ball1.radius + ball2.radius);
double final_vx_2 = ((ball1.radius + ball1.radius) * vx_1 + (ball2.radius - ball1.radius)
* vx_2)
/ (ball1.radius + ball2.radius);
double final_vy_1 = vy_1;
double final_vy_2 = vy_2;
newVelX1 = (int) (Math.cos(colision_angle) * final_vx_1 + Math
.cos(colision_angle + Math.PI / 2) * final_vy_1);
newVelY1 = (int) (Math.sin(colision_angle) * final_vx_1 + Math
.sin(colision_angle + Math.PI / 2) * final_vy_1);
newVelX2 = (int) (Math.cos(colision_angle) * final_vx_2 + Math
.cos(colision_angle + Math.PI / 2) * final_vy_2);
newVelY2 = (int) (Math.sin(colision_angle) * final_vx_2 + Math
.sin(colision_angle + Math.PI / 2) * final_vy_2);
ball1.speedX = (int) newVelX1;
ball1.speedY = (int) newVelY1;
ball2.speedX = (int) newVelX2;
ball2.speedY = (int) newVelY2;
ball1.x = ball1.x + (int) newVelX1;
ball1.y = ball1.y + (int) newVelY1;
ball2.x = ball2.x + (int) newVelX2;
ball2.y = ball2.y + (int) newVelY2;
}
}
}
public static void main(String[] args) {
ElasticCollision balls = new ElasticCollision();
balls.frame.setResizable(false);
balls.frame.add(balls);
balls.frame.pack();
balls.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
balls.frame.setVisible(true);
balls.start();
}
}
class Ball {
protected int x = 0, y = 0;
protected int radius;
protected int speedX = 0, speedY = 0;
protected boolean collision = false;
protected int collisionX = 0, collisionY = 0;
protected boolean inCollision = false;
public Ball(int x, int y, int radius, int speedX, int speedY) {
this.x = x + radius;
this.y = y + radius;
this.radius = radius;
this.speedX = speedX;
this.speedY = speedY;
}
public void paint(Graphics g) {
if (!collision) {
g.setColor(Color.red);
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
} else {
g.setColor(Color.green);
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
g.setColor(Color.blue);
g.fillOval(collisionX - radius, collisionY - radius, 20, 20);
g.setColor(Color.black);
g.drawOval(collisionX - radius, collisionY - radius, 20, 20);
collision = false;
inCollision = false;
}
g.setColor(Color.black);
g.drawOval(x - radius, y - radius, radius * 2, radius * 2);
}
}
My guess is that your logic doesn't let the balls move apart once the collision is detected. Only change the direction of movement once and not every instant the balls are close to one another.
I would like to know if its possible to draw a Arc on a graphics Panel using a gradient and how I would go about it.
My end goal would be to rotate the arc in a full circle so it would be similar to a rotating loading circle. However it is not a loading bar. It would be a background of a custom JButton.
Any suggestions to alternatives that would create a similar effect would be appreciated.
This is similar to what oi want to draw. Keep in mind that it will be "rotating"
public class TestArc {
public static void main(String[] args) {
new TestArc();
}
public TestArc() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int radius = Math.min(getWidth(), getHeight());
int x = (getWidth() - radius) / 2;
int y = (getHeight() - radius) / 2;
RadialGradientPaint rgp = new RadialGradientPaint(
new Point(getWidth() / 2, getHeight() / 2),
radius,
new float[]{0f, 1f},
new Color[]{Color.RED, Color.YELLOW}
);
g2d.setPaint(rgp);
g2d.fill(new Arc2D.Float(x, y, radius, radius, 0, 45, Arc2D.PIE));
g2d.dispose();
}
}
}
You might like to have a look at 2D Graphics for more info
Updated after additional input
So you want a conical fill effect then...
The implementation I have comes from Harmonic Code, but I can't find a direct reference to it (I think it's part of his (excellent) series), but you can see the source code here
Now. I had issues with the angles as it appears that 0 starts at the top point (not the left) and it doesn't like negative angles...you might have better luck, but what I did was create a basic buffer at a position I could easily get working and then rotate the graphics context using an AffineTransformation...
public class TestArc {
public static void main(String[] args) {
new TestArc();
}
public TestArc() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private float angle = 0;
private float extent = 270;
private BufferedImage buffer;
public TestPane() {
Timer timer = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angle -= 5;
if (angle > 360) {
angle = 0;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(false);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected BufferedImage getBuffer() {
if (buffer == null) {
int radius = Math.min(getWidth(), getHeight());
int x = (getWidth() - radius) / 2;
int y = (getHeight() - radius) / 2;
buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
float startAngle = 0;
Color start = new Color(0, 128, 0, 128);
Color end = new Color(0, 128, 0, 0);
ConicalGradientPaint rgp = new ConicalGradientPaint(
true,
new Point(getWidth() / 2, getHeight() / 2),
0.5f,
new float[]{startAngle, extent},
new Color[]{start, end});
g2d.setPaint(rgp);
g2d.fill(new Arc2D.Float(x, y, radius, radius, startAngle + 90, -extent, Arc2D.PIE));
// g2d.fill(new Ellipse2D.Float(0, 0, radius, radius));
g2d.dispose();
g2d.dispose();
}
return buffer;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int radius = Math.min(getWidth(), getHeight());
int x = (getWidth()) / 2;
int y = (getHeight()) / 2;
BufferedImage buffer = getBuffer();
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(angle), x, y));
x = (getWidth() - buffer.getWidth()) / 2;
y = (getHeight() - buffer.getHeight()) / 2;
g2d.drawImage(buffer, x, y, this);
g2d.dispose();
}
}
public final class ConicalGradientPaint implements java.awt.Paint {
private final java.awt.geom.Point2D CENTER;
private final double[] FRACTION_ANGLES;
private final double[] RED_STEP_LOOKUP;
private final double[] GREEN_STEP_LOOKUP;
private final double[] BLUE_STEP_LOOKUP;
private final double[] ALPHA_STEP_LOOKUP;
private final java.awt.Color[] COLORS;
private static final float INT_TO_FLOAT_CONST = 1f / 255f;
/**
* Standard constructor which takes the FRACTIONS in values from 0.0f to
* 1.0f
*
* #param CENTER
* #param GIVEN_FRACTIONS
* #param GIVEN_COLORS
* #throws IllegalArgumentException
*/
public ConicalGradientPaint(final java.awt.geom.Point2D CENTER, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException {
this(false, CENTER, 0.0f, GIVEN_FRACTIONS, GIVEN_COLORS);
}
/**
* Enhanced constructor which takes the FRACTIONS in degress from 0.0f to
* 360.0f and also an GIVEN_OFFSET in degrees around the rotation CENTER
*
* #param USE_DEGREES
* #param CENTER
* #param GIVEN_OFFSET
* #param GIVEN_FRACTIONS
* #param GIVEN_COLORS
* #throws IllegalArgumentException
*/
public ConicalGradientPaint(final boolean USE_DEGREES, final java.awt.geom.Point2D CENTER, final float GIVEN_OFFSET, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException {
// Check that fractions and colors are of the same size
if (GIVEN_FRACTIONS.length != GIVEN_COLORS.length) {
throw new IllegalArgumentException("Fractions and colors must be equal in size");
}
final java.util.ArrayList<Float> FRACTION_LIST = new java.util.ArrayList<Float>(GIVEN_FRACTIONS.length);
final float OFFSET;
if (USE_DEGREES) {
final double DEG_FRACTION = 1f / 360f;
if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), -0.5) == 0) {
OFFSET = -0.5f;
} else if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), 0.5) == 0) {
OFFSET = 0.5f;
} else {
OFFSET = (float) (GIVEN_OFFSET * DEG_FRACTION);
}
for (float fraction : GIVEN_FRACTIONS) {
FRACTION_LIST.add((float) (fraction * DEG_FRACTION));
}
} else {
// Now it seems to work with rotation of 0.5f, below is the old code to correct the problem
// if (GIVEN_OFFSET == -0.5)
// {
// // This is needed because of problems in the creation of the Raster
// // with a angle offset of exactly -0.5
// OFFSET = -0.49999f;
// }
// else if (GIVEN_OFFSET == 0.5)
// {
// // This is needed because of problems in the creation of the Raster
// // with a angle offset of exactly +0.5
// OFFSET = 0.499999f;
// }
// else
{
OFFSET = GIVEN_OFFSET;
}
for (float fraction : GIVEN_FRACTIONS) {
FRACTION_LIST.add(fraction);
}
}
// Check for valid offset
if (OFFSET > 0.5f || OFFSET < -0.5f) {
throw new IllegalArgumentException("Offset has to be in the range of -0.5 to 0.5");
}
// Adjust fractions and colors array in the case where startvalue != 0.0f and/or endvalue != 1.0f
final java.util.List<java.awt.Color> COLOR_LIST = new java.util.ArrayList<java.awt.Color>(GIVEN_COLORS.length);
COLOR_LIST.addAll(java.util.Arrays.asList(GIVEN_COLORS));
// Assure that fractions start with 0.0f
if (FRACTION_LIST.get(0) != 0.0f) {
FRACTION_LIST.add(0, 0.0f);
final java.awt.Color TMP_COLOR = COLOR_LIST.get(0);
COLOR_LIST.add(0, TMP_COLOR);
}
// Assure that fractions end with 1.0f
if (FRACTION_LIST.get(FRACTION_LIST.size() - 1) != 1.0f) {
FRACTION_LIST.add(1.0f);
COLOR_LIST.add(GIVEN_COLORS[0]);
}
// Recalculate the fractions and colors with the given offset
final java.util.Map<Float, java.awt.Color> FRACTION_COLORS = recalculate(FRACTION_LIST, COLOR_LIST, OFFSET);
// Clear the original FRACTION_LIST and COLOR_LIST
FRACTION_LIST.clear();
COLOR_LIST.clear();
// Sort the hashmap by fraction and add the values to the FRACION_LIST and COLOR_LIST
final java.util.SortedSet<Float> SORTED_FRACTIONS = new java.util.TreeSet<Float>(FRACTION_COLORS.keySet());
final java.util.Iterator<Float> ITERATOR = SORTED_FRACTIONS.iterator();
while (ITERATOR.hasNext()) {
final float CURRENT_FRACTION = ITERATOR.next();
FRACTION_LIST.add(CURRENT_FRACTION);
COLOR_LIST.add(FRACTION_COLORS.get(CURRENT_FRACTION));
}
// Set the values
this.CENTER = CENTER;
COLORS = COLOR_LIST.toArray(new java.awt.Color[]{});
// Prepare lookup table for the angles of each fraction
final int MAX_FRACTIONS = FRACTION_LIST.size();
this.FRACTION_ANGLES = new double[MAX_FRACTIONS];
for (int i = 0; i < MAX_FRACTIONS; i++) {
FRACTION_ANGLES[i] = FRACTION_LIST.get(i) * 360;
}
// Prepare lookup tables for the color stepsize of each color
RED_STEP_LOOKUP = new double[COLORS.length];
GREEN_STEP_LOOKUP = new double[COLORS.length];
BLUE_STEP_LOOKUP = new double[COLORS.length];
ALPHA_STEP_LOOKUP = new double[COLORS.length];
for (int i = 0; i < (COLORS.length - 1); i++) {
RED_STEP_LOOKUP[i] = ((COLORS[i + 1].getRed() - COLORS[i].getRed()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
GREEN_STEP_LOOKUP[i] = ((COLORS[i + 1].getGreen() - COLORS[i].getGreen()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
BLUE_STEP_LOOKUP[i] = ((COLORS[i + 1].getBlue() - COLORS[i].getBlue()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
ALPHA_STEP_LOOKUP[i] = ((COLORS[i + 1].getAlpha() - COLORS[i].getAlpha()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]);
}
}
/**
* Recalculates the fractions in the FRACTION_LIST and their associated
* colors in the COLOR_LIST with a given OFFSET. Because the conical
* gradients always starts with 0 at the top and clockwise direction you
* could rotate the defined conical gradient from -180 to 180 degrees which
* equals values from -0.5 to +0.5
*
* #param FRACTION_LIST
* #param COLOR_LIST
* #param OFFSET
* #return Hashmap that contains the recalculated fractions and colors after
* a given rotation
*/
private java.util.HashMap<Float, java.awt.Color> recalculate(final java.util.List<Float> FRACTION_LIST, final java.util.List<java.awt.Color> COLOR_LIST, final float OFFSET) {
// Recalculate the fractions and colors with the given offset
final int MAX_FRACTIONS = FRACTION_LIST.size();
final java.util.HashMap<Float, java.awt.Color> FRACTION_COLORS = new java.util.HashMap<Float, java.awt.Color>(MAX_FRACTIONS);
for (int i = 0; i < MAX_FRACTIONS; i++) {
// Add offset to fraction
final float TMP_FRACTION = FRACTION_LIST.get(i) + OFFSET;
// Color related to current fraction
final java.awt.Color TMP_COLOR = COLOR_LIST.get(i);
// Check each fraction for limits (0...1)
if (TMP_FRACTION <= 0) {
FRACTION_COLORS.put(1.0f + TMP_FRACTION + 0.0001f, TMP_COLOR);
final float NEXT_FRACTION;
final java.awt.Color NEXT_COLOR;
if (i < MAX_FRACTIONS - 1) {
NEXT_FRACTION = FRACTION_LIST.get(i + 1) + OFFSET;
NEXT_COLOR = COLOR_LIST.get(i + 1);
} else {
NEXT_FRACTION = 1 - FRACTION_LIST.get(0) + OFFSET;
NEXT_COLOR = COLOR_LIST.get(0);
}
if (NEXT_FRACTION > 0) {
final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, NEXT_COLOR, (int) ((NEXT_FRACTION - TMP_FRACTION) * 10000), (int) ((-TMP_FRACTION) * 10000));
FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR);
FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR);
}
} else if (TMP_FRACTION >= 1) {
FRACTION_COLORS.put(TMP_FRACTION - 1.0f - 0.0001f, TMP_COLOR);
final float PREVIOUS_FRACTION;
final java.awt.Color PREVIOUS_COLOR;
if (i > 0) {
PREVIOUS_FRACTION = FRACTION_LIST.get(i - 1) + OFFSET;
PREVIOUS_COLOR = COLOR_LIST.get(i - 1);
} else {
PREVIOUS_FRACTION = FRACTION_LIST.get(MAX_FRACTIONS - 1) + OFFSET;
PREVIOUS_COLOR = COLOR_LIST.get(MAX_FRACTIONS - 1);
}
if (PREVIOUS_FRACTION < 1) {
final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, PREVIOUS_COLOR, (int) ((TMP_FRACTION - PREVIOUS_FRACTION) * 10000), (int) (TMP_FRACTION - 1.0f) * 10000);
FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR);
FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR);
}
} else {
FRACTION_COLORS.put(TMP_FRACTION, TMP_COLOR);
}
}
// Clear the original FRACTION_LIST and COLOR_LIST
FRACTION_LIST.clear();
COLOR_LIST.clear();
return FRACTION_COLORS;
}
/**
* With the START_COLOR at the beginning and the DESTINATION_COLOR at the
* end of the given RANGE the method will calculate and return the color
* that equals the given VALUE. e.g. a START_COLOR of BLACK (R:0, G:0, B:0,
* A:255) and a DESTINATION_COLOR of WHITE(R:255, G:255, B:255, A:255) with
* a given RANGE of 100 and a given VALUE of 50 will return the color that
* is exactly in the middle of the gradient between black and white which is
* gray(R:128, G:128, B:128, A:255) So this method is really useful to
* calculate colors in gradients between two given colors.
*
* #param START_COLOR
* #param DESTINATION_COLOR
* #param RANGE
* #param VALUE
* #return Color calculated from a range of values by given value
*/
public java.awt.Color getColorFromFraction(final java.awt.Color START_COLOR, final java.awt.Color DESTINATION_COLOR, final int RANGE, final int VALUE) {
final float SOURCE_RED = START_COLOR.getRed() * INT_TO_FLOAT_CONST;
final float SOURCE_GREEN = START_COLOR.getGreen() * INT_TO_FLOAT_CONST;
final float SOURCE_BLUE = START_COLOR.getBlue() * INT_TO_FLOAT_CONST;
final float SOURCE_ALPHA = START_COLOR.getAlpha() * INT_TO_FLOAT_CONST;
final float DESTINATION_RED = DESTINATION_COLOR.getRed() * INT_TO_FLOAT_CONST;
final float DESTINATION_GREEN = DESTINATION_COLOR.getGreen() * INT_TO_FLOAT_CONST;
final float DESTINATION_BLUE = DESTINATION_COLOR.getBlue() * INT_TO_FLOAT_CONST;
final float DESTINATION_ALPHA = DESTINATION_COLOR.getAlpha() * INT_TO_FLOAT_CONST;
final float RED_DELTA = DESTINATION_RED - SOURCE_RED;
final float GREEN_DELTA = DESTINATION_GREEN - SOURCE_GREEN;
final float BLUE_DELTA = DESTINATION_BLUE - SOURCE_BLUE;
final float ALPHA_DELTA = DESTINATION_ALPHA - SOURCE_ALPHA;
final float RED_FRACTION = RED_DELTA / RANGE;
final float GREEN_FRACTION = GREEN_DELTA / RANGE;
final float BLUE_FRACTION = BLUE_DELTA / RANGE;
final float ALPHA_FRACTION = ALPHA_DELTA / RANGE;
//System.out.println(DISTANCE + " " + CURRENT_FRACTION);
return new java.awt.Color(SOURCE_RED + RED_FRACTION * VALUE, SOURCE_GREEN + GREEN_FRACTION * VALUE, SOURCE_BLUE + BLUE_FRACTION * VALUE, SOURCE_ALPHA + ALPHA_FRACTION * VALUE);
}
#Override
public java.awt.PaintContext createContext(final java.awt.image.ColorModel COLOR_MODEL, final java.awt.Rectangle DEVICE_BOUNDS, final java.awt.geom.Rectangle2D USER_BOUNDS, final java.awt.geom.AffineTransform TRANSFORM, final java.awt.RenderingHints HINTS) {
final java.awt.geom.Point2D TRANSFORMED_CENTER = TRANSFORM.transform(CENTER, null);
return new ConicalGradientPaintContext(TRANSFORMED_CENTER);
}
#Override
public int getTransparency() {
return java.awt.Transparency.TRANSLUCENT;
}
private final class ConicalGradientPaintContext implements java.awt.PaintContext {
final private java.awt.geom.Point2D CENTER;
public ConicalGradientPaintContext(final java.awt.geom.Point2D CENTER) {
this.CENTER = new java.awt.geom.Point2D.Double(CENTER.getX(), CENTER.getY());
}
#Override
public void dispose() {
}
#Override
public java.awt.image.ColorModel getColorModel() {
return java.awt.image.ColorModel.getRGBdefault();
}
#Override
public java.awt.image.Raster getRaster(final int X, final int Y, final int TILE_WIDTH, final int TILE_HEIGHT) {
final double ROTATION_CENTER_X = -X + CENTER.getX();
final double ROTATION_CENTER_Y = -Y + CENTER.getY();
final int MAX = FRACTION_ANGLES.length;
// Create raster for given colormodel
final java.awt.image.WritableRaster RASTER = getColorModel().createCompatibleWritableRaster(TILE_WIDTH, TILE_HEIGHT);
// Create data array with place for red, green, blue and alpha values
int[] data = new int[(TILE_WIDTH * TILE_HEIGHT * 4)];
double dx;
double dy;
double distance;
double angle;
double currentRed = 0;
double currentGreen = 0;
double currentBlue = 0;
double currentAlpha = 0;
for (int py = 0; py < TILE_HEIGHT; py++) {
for (int px = 0; px < TILE_WIDTH; px++) {
// Calculate the distance between the current position and the rotation angle
dx = px - ROTATION_CENTER_X;
dy = py - ROTATION_CENTER_Y;
distance = Math.sqrt(dx * dx + dy * dy);
// Avoid division by zero
if (distance == 0) {
distance = 1;
}
// 0 degree on top
angle = Math.abs(Math.toDegrees(Math.acos(dx / distance)));
if (dx >= 0 && dy <= 0) {
angle = 90.0 - angle;
} else if (dx >= 0 && dy >= 0) {
angle += 90.0;
} else if (dx <= 0 && dy >= 0) {
angle += 90.0;
} else if (dx <= 0 && dy <= 0) {
angle = 450.0 - angle;
}
// Check for each angle in fractionAngles array
for (int i = 0; i < (MAX - 1); i++) {
if ((angle >= FRACTION_ANGLES[i])) {
currentRed = COLORS[i].getRed() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * RED_STEP_LOOKUP[i];
currentGreen = COLORS[i].getGreen() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * GREEN_STEP_LOOKUP[i];
currentBlue = COLORS[i].getBlue() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * BLUE_STEP_LOOKUP[i];
currentAlpha = COLORS[i].getAlpha() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * ALPHA_STEP_LOOKUP[i];
continue;
}
}
// Fill data array with calculated color values
final int BASE = (py * TILE_WIDTH + px) * 4;
data[BASE + 0] = (int) (currentRed * 255);
data[BASE + 1] = (int) (currentGreen * 255);
data[BASE + 2] = (int) (currentBlue * 255);
data[BASE + 3] = (int) (currentAlpha * 255);
}
}
// Fill the raster with the data
RASTER.setPixels(0, 0, TILE_WIDTH, TILE_HEIGHT, data);
return RASTER;
}
}
}
}