I've searched for some time already but haven't been able to find an answer to my question.
First I'll show two comparison pictures:
Method 1:
method 1 http://img713.imageshack.us/img713/3558/tcg6.jpg
Method 2:
method 2 http://img716.imageshack.us/img716/2755/tcg7.jpg
Method 1 has never given me any trouble, but I recently found out that it simply takes too long, and method 2 fixed that.
Code for method 1:
private void drawDefaultOrientation() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
bufferedImage.setRGB(xOffset + x, yOffset + y, color.getRGB());
}
}
}
Code for method 2:
private void drawDefaultOrientation() {
DataBufferInt buffer = (DataBufferInt)bufferedImage.getRaster().getDataBuffer();
int[] pixelArray = buffer.getData();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
pixelArray[(xOffset + x) + ((yOffset + y) * bufferedImage.getWidth())] = color.getRGB();
}
}
}
Please also note that the inBorder(dx, dy); and outBorder(dx, dy); set the color variable to a color with a Red, Green, Blue and Alpha value.
Callee code:
new CustomRectangle(bufferedImage, 220, 90, 15, 245, 5, defaultOrientation) {
#Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
#Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 128 - Math.min(dx, dy)));
}
}.draw();
I am really lost as to why the color difference is here.
I really hope anyone out there can help me. First I thought it had to do with the Alpha values, but as seen the alpha variaton still exists with method 2.
Regards.
I'd suggest, for "simple" thing (including boxes, shapes, gradients, and a lot more), you use directly the Java2D API. It will be both more efficient and simpler to write.
For example to fill a rectangle in your image with a color:
public void rectangle(Color color, float x1, float y1, float w, float h) {
Graphics2D g = bufferedImage.createGraphics();
g.setColor(color);
g.fill(new Rectangle2D.Float(x1, y1, w, h));
g.dispose(); // optional but releases the resource earlier
}
You can also use "g" to draw as much things as you need to do.
Related
I've created a bouncing balls animation, that's drawn on a surface (library from my university) that has 2 frames in it, and 2 arrays of balls that half goes to the first frame and the second to the second frame.
For some reason - the balls pass through to y and x axis of their frame.
I've already tried doing some of the solutions that were suggested (like here) and it didn't help..
my code:
public static void updateBalVelocity(Ball ball, int width, int height,
int minWidth, int minHeight) {
// get default value of the dx and dy
double dx = ball.getVelocity().getDx();
double dy = ball.getVelocity().getDy();
// check if the ball is touching the border (x/y axis) and if so -
// change it's directions
if ((ball.getX() + ball.getSize() + dx) >= width) {
dx = (dx > 0) ? -dx : dx;
} else if ((ball.getX() - ball.getSize()) <= minWidth) {
dx = Math.abs(dx);
}
if ((ball.getY() + ball.getSize() + dy) >= height) {
dy = (dy > 0) ? -dy : dy;
} else if ((ball.getY() - ball.getSize()) <= minHeight) {
dy = Math.abs(dy);
}
// apply the velocity to the ball
ball.setVelocity(dx, dy);
}
public static void moveBalls(Ball[] balls, DrawSurface d, int height,
int width, int minHeight, int minWidth) {
for (Ball ball : balls) {
updateBalVelocity(ball, width, height, minWidth, minHeight);
ball.moveOneStep();
d.setColor(ball.getColor());
d.fillCircle(ball.getX(), ball.getY(), ball.getSize());
ball.drawOn(d);
}
}
and in the run method:
while (true) {
...
// move balls
BouncingBallHelper.moveBalls(ballsD1, d, 500, 500, 50, 50);
BouncingBallHelper.moveBalls(ballsD2, d, 600, 600, 450, 450);
gui.show(d);
// wait for 50 milliseconds.
sleeper.sleepFor(50);
}
So I'm supposed to make a program where a ball bounces around a drawingpanel for 10 seconds. The ball has to bounce off the sides of the panel if it hits them. Right now when the ball hits the bottom panel instead of bouncing it appears in the middle of the screen and moves in the opposite direction until it hits the top and disappears.
I'm pretty sure the problem is in this part of my code...
(Earlier in the code I declared x to 1, y to 250, dx to 1, and dy to 1)
//Changes dirction
public static int newDirection1(int x, int dx, int size){
if (x < 0 || x > 500 || (x + size) < 0 || (x + size) > 500) {
dx *= -1;
return dx;
} else {
return dx;
}
}
//Changes direction
public static int newDirection2(int y, int dy, int size){
if (y < 0 || y > 500 || (y + size) < 0 || (y + size) > 500) {
dy *= -1;
return dy;
} else {
return dy;
}
}
//Moves ball one step
public static void move(Graphics g, Color color, int size, int x1, int y1, int x2, int y2){
g.setColor(Color.WHITE);
g.fillOval(x1, y1, size, size);
g.setColor(color);
g.fillOval(x2, y2, size, size);
}
//Pauses for 10ms
public static void sleep(int millis, DrawingPanel panel){
panel.sleep(millis);
}
public static void bounceLoop(DrawingPanel panel, Graphics g, Color color, int size, int x, int dx, int y, int dy, int millis){
int x1 = x + dx;
int x2 = x + dx;
int y1 = y + dy;
int y2 = y + dy;
for (int i = 0; i < 1000; i++) {
x1 = x + dx * i;
x2 = (x + dx * i) + dx;
y1 = y + dy * i;
y2 = (y + dy * i) + dy;
dx = newDirection1(x2, dx, size);
dy = newDirection2(y2, dy, size);
move(g, c, size, x1, y1, x2, y2);
sleep(millis, panel);
}
}
}
in the loop don't use:
x1 = x + dx * i
use
x1 = x1 + dx
(same for y)
because whenever dx is going to change, and multiply by -1, instead of continuing from where it was, and go to the other direction, it's going to continue from the other side of your panel, or a point that is really off.
Also a few things that could possibly fix the coding:
1- you don't need a dx parameter for your getNewDirection, you only need the coordinate.
2- the boundry conditions may give you errors, give it a small offset that can't be visible to the naked eye to avoid errors with creating objects outside the created panel or whatever you are using
I noticed that one of my methods is being very slow, with profiling I noticed it took up like 95% of the total execution time.
The class:
package gui;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
/**
*
* #author Frank
*/
public abstract class CustomRectangle {
protected final BufferedImage bufferedImage;
protected final int width;
protected final int height;
protected final int xOffset;
protected final int yOffset;
protected final int borderSize;
protected final boolean defaultOrientation;
protected Color color;
public CustomRectangle(final BufferedImage bufferedImage, final int width, final int height, final int xOffset, final int yOffset, final int borderSize, final boolean defaultOrientation) {
this.bufferedImage = bufferedImage;
this.width = width;
this.height = height;
if (defaultOrientation) {
this.xOffset = xOffset;
this.yOffset = yOffset;
}
else {
this.xOffset = bufferedImage.getWidth() - 1 - xOffset;
this.yOffset = bufferedImage.getHeight() - 1 - yOffset;
}
this.borderSize = borderSize;
this.defaultOrientation = defaultOrientation;
}
abstract public void inBorder(final int dx, final int dy);
abstract public void outBorder(final int dx, final int dy);
public void draw() {
if (defaultOrientation) {
drawDefaultOrientation();
}
else {
drawOppositeOrientation();
}
}
private void drawDefaultOrientation() {
int[] pixelArray = ((DataBufferInt)bufferedImage.getRaster().getDataBuffer()).getData();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
pixelArray[(xOffset + x) + ((yOffset + y) * bufferedImage.getWidth())] = color.getRGB();
}
}
}
private void drawOppositeOrientation() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder(dx, dy);
}
else {
outBorder(dx, dy);
}
bufferedImage.setRGB(xOffset - x, yOffset - y, color.getRGB());
}
}
}
public void setColor(final Color color) {
this.color = color;
}
}
The slow method is the drawDefaultOrientation() method.
The scary part however is that even if I leave out all image-modifying code, then it is still slow.
The callee code:
new CustomRectangle(bufferedImage, 440, 180, 30, 490, 10, defaultOrientation) {
#Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - (int)Math.round(0.5 * Math.min(dx, dy))));
}
#Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 128 - (int)Math.round(0.5 * Math.min(dx, dy))));
}
}.draw();
There must be something going on as in any way this code should not take this long, even if it loops over x and y coordinates.
Some thought I had was that it could have to do with the Anonymous inner class + Override...
But hopefully someone with more knowledge can answer the question.
Try this: If red, green, blue don't change, then stop using an anonymous class, and in your implemented subclass do: (note, this might not work, but the basic idea should, if you can avoid constantly calling new Color by caching all the colors you might need)
private final Color[] colors;
public ImplementedCustomRectangle(...) {
super(...); // ... is not real code, I just don't want to copy/paste
colors = new Color[256];
for (i = 0; i < 256; i++) {
colors[i] = new Color(red, green, blue, i);
}
}
#Override
public void inBorder(final int dx, final int dy) {
int value = 255 - (int)Math.round(0.5 * Math.min(dx, dy));
setColor(colors[value]);
}
#Override
public void outBorder(final int dx, final int dy) {
int value = 128 - (int)Math.round(0.5 * Math.min(dx, dy);
setColor(colors[value]);
}
I am trying to convert some (ugly looking) code into functions, such that everything is better managable. However I have come to a problem, current code:
int red = card.getColor().getRed();
int green = card.getColor().getGreen();
int blue = card.getColor().getBlue();
Color color = new Color(red, green, blue);
int width;
int height;
int xOffset;
int yOffset;
int border;
//Whole card
width = CARD_DIMENSION.width;
height = CARD_DIMENSION.height;
xOffset = 0;
yOffset = 0;
border = 5;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < border || dy < border) {
g2d.setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
else {
g2d.setColor(new Color(red, green, blue, 192 - Math.min(dx, dy)));
}
g2d.drawLine(x + xOffset, y + yOffset, x + xOffset, y + yOffset);
}
}
I would have to copy this everytime I want to draw some new rectangle. At first sight it isn't hard to put it in a function, however these lines:
if (dx < border || dy < border) {
g2d.setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
else {
g2d.setColor(new Color(red, green, blue, 192 - Math.min(dx, dy)));
}
They make it hard since I use dx and dy there.
Now I have come up with a proposed solution which I would want to use with anonymous inner classes and overriding the two functions:
private abstract class CustomRectangle {
protected final int width;
protected final int height;
protected final int xOffset;
protected final int yOffset;
protected final int borderSize;
public CustomRectangle(final int width, final int height, final int xOffset, final int yOffset, final int borderSize) {
this.width = width;
this.height = height;
this.xOffset = xOffset;
this.yOffset = yOffset;
this.borderSize = borderSize;
}
abstract void inBorder();
abstract void outBorder();
public void draw(Graphics2D g2d) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int dx = Math.min(x, width - 1 - x);
int dy = Math.min(y, height - 1 - y);
if (dx < borderSize || dy < borderSize) {
inBorder();
}
else {
outBorder();
}
g2d.drawLine(x + xOffset, y + yOffset, x + xOffset, y + yOffset);
}
}
}
}
But I am still afraid that it will be hard if not impossible to put in a formula using dx and dy (two local variables to the for loops).
I would appreciate it if anyone has any suggestions on either the general problem or on my own approach, because having several codeblocks that do essentially the same is just not acceptable.
Regards.
I need to draw a line from two points and what I did so far is using drawLine(x1,y1,x2,y2). But what I want to do is draw a line that intersects with these two points (x1,y1) and (x2,y2).
I don't want to just draw a line between them, here's an image of what I have and what I want to do:
you could use some mathematik. get the increase of your line. You should know the function
f(x) = mx + b. With your two points,which you allready got, you can calculate two other Points at the Border of your frame, and draw a line between them
You'll need to calculate the coordinates at which your line meets the boundaries of your graphics context.
If you have (x1,y1) and (x2,y2), calculate the x_a and y_a such that (x_a,0) and (0,y_a) lie on the line.
If x_a = 0, the line will start from the left edge. If y_a = 0, the line will start from the top edge.
Repeat for the bottom/right coords of the line.
Bresenham's line algorithm
private int sign (int x) {
return (x > 0) ? 1 : (x < 0) ? -1 : 0;
}
public void drawBresenhamLine (int xstart, int ystart, int xend, int yend, Graphics g){
int x, y, dx, dy, incx, incy, pdx, pdy, es, el, err;
dx = xend - xstart;
dy = yend - ystart;
incx = sign(dx);
incy = sign(dy);
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
if (dx > dy){
pdx = incx; pdy = 0;
es = dy; el = dx;
} else {
pdx = 0; pdy = incy;
es = dx; el = dy;
}
x = xstart;
y = ystart;
err = el/2;
g.drawLine (x, y, x, y);
for (int t = 0; t < el; t++)//if I multiply el a line will be longer
{
err -= es;
if (err < 0) {
err += el;
x += incx;
y += incy;
} else {
x += pdx;
y += pdy;
}
g.drawLine (x, y, x, y);
}
}