I have created a closed contour with a list of points which I want to be filled by a color.I have used boundary fill recursion algorithm but no luck the array index goes out of bounds since i cannot develop the if condition since the color inside the closed contour and color outside the contour is same.What method should i use to get the desired contour to be filled up by a specific color.Here is the code that i have tried
public class BoundaryFillAlgorithm {
public static BufferedImage toFill = MemoryPanel.Crect;
static Graphics g1 = toFill.getGraphics();
static int seedx = toFill.getWidth()/2;
static int seedy = toFill.getHeight()/2;
public static void BoundaryFill(int x,int y){
Color old = new Color(toFill.getRGB(x, y));
g1.setColor(Color.BLACK);
if(old!=Color.BLACK){
g1.fillOval(x, y, 1, 1);
BoundaryFill(x+1,y);
BoundaryFill(x,y+1);
BoundaryFill(x-1,y);
BoundaryFill(x,y-1);
}
}
Here's the image
Here's the method call
BoundaryFillAlgorithm.BoundaryFill(BoundaryFillAlgorithm.seedx,BoundaryFillAlgorithm.seedy);
g.setColor(Color.red); // Set color to red
g.fillRect(600, 400, 100, 100);// a filled-in RED rectangle
Why reinventing the wheel?
Graphics2D has a already a method fill(Shape).
There a many classes implementing the Shape interface, especially Polygon,
which you might reuse.
Finally corrected my code heres the corrected code:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class BoundaryFillAlgorithm {
public static BufferedImage toFill = MemoryPanel.Crect;
Graphics g1 = toFill.getGraphics();
public BoundaryFillAlgorithm(BufferedImage toFill){
int x = toFill.getWidth()/2-10;
int y = toFill.getHeight()/2;
int old = toFill.getRGB(x, y);
this.toFill = toFill;
fill(x,y,old);
}
private void fill(int x,int y,int old) {
if(x<=0) return;
if(y<=0) return;
if(x>=toFill.getWidth()) return;
if(y>=toFill.getHeight())return;
if(toFill.getRGB(x, y)!=old)return;
toFill.setRGB(x, y, 0xFFFF0000);
fill(x+1,y,old);
fill(x,y+1,old);
fill(x-1,y,old);
fill(x,y-1,old);
fill(x+1,y-1,old);
fill(x+1,y+1,old);
fill(x-1,y-1,old);
fill(x+1,y-1,old);
}
}
Related
As the title says, I want to be able to right-click lines I've drawn on Jpanel. Since those lines aren't Components I can't simply add MouseListener to them. Currently I'm drawing lines on my Jpanel with the following code:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (UserDrawnLine line : userDrawnLines) {
g.setColor(new Color(line.colorRValue,line.colorGValue, line.colorBValue));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(line.thickness));
g.drawLine(line.startPointX, line.startPointY, line.endPointX, line.endPointY);
}
}
This is my UserDrawnLine class:
public class UserDrawnLine {
public int startPointX;
public int startPointY;
public int endPointX;
public int endPointY;
public int colorRValue;
public int colorGValue;
public int colorBValue;
public float thickness;
public UserDrawnLine(int startPointX, int startPointY, int endPointX, int endPointY, int colorRValue,int colorGValue,int colorBValue, float thickness) {
this.startPointX = startPointX;
this.startPointY = startPointY;
this.endPointX = endPointX;
this.endPointY = endPointY;
this.colorRValue=colorRValue;
this.colorBValue=colorBValue;
this.colorGValue=colorGValue;
this.thickness=thickness;
}
}
I've been thinking about storing points through which the line goes and then reacting accordingly when user clicks on Jpanel on one of those points. However this doesn't seem like the best solution. Any better ones?
Create a Collection Lines and, using the Point provided from the MouseEvent in the MouseListener, iterate over the Collection and check if the point is on each Line. You may have to roll your own Line class and implement a contains method (note that the Line2D cannot be used as it's contains method always returns false).
To determine if a Point P is on the line:
distance(P, A) + distance(P, B) = distance(A,B)
Where A and B are the line endpoints, and P is the test point. One can use an error term to allow for points that are near but not exactly on the Line (for instance, when using wider strokes to render, you might wish to increase this error term). Assuming your class has endpoints a and b:
public boolean contains(Point p, double error){
double dist = Math.sqrt(Math.pow(p.x - a.x, 2) + Math.pow(p.y - a.y, 2)) +
Math.sqrt(Math.pow(p.x - b.x, 2) + Math.pow(p.y - b.y, 2));
return Math.abs(dist - this.distance) <= error;
}
My issues is the following: My actual project (of which the code below is a simplified version of) involves many concentric circles (each with a different colour) and animation utilising a Timer. The circles are drawn using the drawOval method.
My problem is that when these concentric circles are drawn, there appears to be loads of gaps in the outline of these circles, which I'm guessing is something to do with the fact that a circle is composed of pixels and lines as is any shape so the appearance of roundness is an illusion. I say this because when I swap the drawOval method for drawRect the painting looks as you would expect.
When messing around with other people's codes I saw that using RenderingHints somehow solved this problem however slowed down the animation beyond a point that I felt was acceptable.
Below is a screenshot of what is painted. Rather than seeing a solid opaque circle (as all of the circles drawn have the same colour in this example) we see this:
Here is my simplified code:
Test10
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Test10 extends JPanel {
Circle[] circles;
public static void main(String[] args) {
new Test10().go();
}
void go() {
JFrame frame = new JFrame("Circle Test");
frame.getContentPane().add(this);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
circles = new Circle[200];
for (int i = 0; i < 200; i++) {
circles[i] = new Circle(i, ((2 * ( 200 - i) + 1)));
}
repaint();
frame.setPreferredSize(new Dimension(500,500));
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
for (Circle circle : circles ) {
circle.draw(g);
}
}
}
Circle
import java.awt.Graphics;
public class Circle {
int topLeft;
int diameter;
public Circle(int topLeft, int diameter) {
this.topLeft = topLeft;
this.diameter = diameter;
}
void draw(Graphics g) {
g.drawOval(topLeft, topLeft, diameter, diameter);
}
}
Could anyone explain to me a) Why this is happening and b) How to overcome this problem.
UPDATE
Having tried various methods including starting with the outermost circle and using fillOval instead of drawOval, and using a higher stroke value, I still find I have a problem with certain artefacts appearing similar to the screenshot Pavel posted. Here is a screenshot from my full application running the animation, if you look carefully you can see inconsistencies in the colour of mostly any given circle, resulting in these strange results. Their distribution actually follows the same pattern as the screenshot posted above so clearly something fundamental isn't being addressed by these options. Here is my screen shot:
It is impossible to draw perfect circle.
Try using the following method
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(2));
int i = 0;
for (Circle circle : circles ) {
Shape circle2 = new Ellipse2D.Double(i++, i, circle.diameter, circle.diameter);
g2d.draw(circle2);
}
}
You said you tried with RenderingHints, and it slowed your animation, but you haven't give us any code with animation, so maybe try my code (it would be good to see animation implementation). It looked better, but still not what you wanted. Setting stroke to another value will solve this (set to at least 2). Another one is to use .fill() instead of .draw(). I know that it is not perfect, but you may try it.
ANOTHER IDEA
I thought, that maybe you could add some blur to your image, so those artifacts are not visible?
I haven't done it before, but I found this (found HERE):
private class BlurGlass extends JComponent {
private JFrame f;
public BlurGlass(JFrame f) {
this.f = f;
setOpaque(false);
setFocusable(false);
}
public void paintComponent(Graphics g) {
int w = f.getWidth();
int h = f.getHeight();
setLocation(0, 0);
setSize(w, h);
g.setColor(new Color(0, 0, 0, 0.3f));
g.fillRect(0, 0, w, h);
}
}
now somwhere in go() method:
frame.setGlassPane(new BlurGlass(frame));
frame.getGlassPane().setVisible(true);
It looks a lot better for me. Play a bit with this GlassPane color (try changing .3f to some other value).
You might want to make the Stroke bigger. I've had luck with this in situations similar to yours
You can try by adding this line in your Circle class inside draw function:
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//and draw the Oval on g2
Also another solution might be to fill the circles:
Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2.fill(circle);
That happens because a computer cannot draw a perfect circle.
A computer uses square pixels to approximate a real circle but its just not possible to achieve perfection and that results in some pixels not being shown
Drawing a filled circle will help you
a detailed explanation
Can you please try fillOval method instead of drawOval.
g.fillOval(topLeft, topLeft, diameter, diameter);
Reverse your idea. Start with the outermost circle, then draw the inner circle and so on, finishing with the smallest circle. You should use fillOval in the process.
The other rendering hint that is often useful for circles/ovals is
g.setRenderingHint( RenderingHints. KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
See my other answer with more details and example.
This question already has answers here:
Adding Image to a Polygon
(2 answers)
Closed 8 years ago.
I'm trying to basically remake Asteroids in java, but I'm going to use a bald eagle as a ship that shoots down Soviet flags. Right now, my bald eagle image is a square with a white outline around the eagle. I would like to remove this, is there any way to map this in a one-to-one fashion to a polygon of sorts?
Here's my code, though I don't know exactly how this will help anything:
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
GameTest t = new GameTest();
}
public static class GameTest extends JFrame {
private static final int WINDOW_WIDTH = 800;
private static final int WINDOW_HEIGHT = 500;
private GamePanel gamePanel;
public GameTest() throws IOException {
super("Deep Fried Freedom");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setLayout(new BorderLayout());
gamePanel = new GamePanel();
add(gamePanel);
center(this);
setVisible(true);
}
public static void center(JFrame frame) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Point center = ge.getCenterPoint();
int w = frame.getWidth();
int h = frame.getHeight();
int x = center.x - w / 2, y = center.y - h / 2;
frame.setBounds(x, y, w, h);
frame.validate();
}//end of center method
}
}
public class GamePanel extends JPanel {
public static BufferedImage baldEagleImage;
public GamePanel() throws IOException {
super();
baldEagleImage = ImageIO.read(new File("baldeagleimage.jpg"));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);// set color black
g.fillRect(0, 0, getWidth(), getHeight()); // paint background
g.drawImage(baldEagleImage, 350, 175, null);//paint the launcher
}//end paintComponent method
}//end GamePanel class
You have several ways that you can achieve this effect. Your best bet would be to use the alpha channel of your image. Just open your image in an image editing tool such as Gimp. In this set the background of your image to transparent around your image.
Another option (which is not the best) but fulfils your request is to use a paint stroke in Java2D. Have a look at using the java2d clipping feature. You can get a tutorial on this here
Usually you will have a Java object that represents the ship, and it has x and y coordinates called something like centerX and centerY. That gives you the center of the ship on your screen within the bounds of the viewable area. You modify these values when you want the ship to move up and down, and you g.drawImage the image you want to use at these coordinates as well (plus any offsets as needed to make the image appear centered to your liking).
A common method is to have a thread started upon initialization, and in that thread is a while(true) block that does an update() method on all objects that need to be updated, and then a Thread.sleep(17) that mimics a framerate of about 60 frames per second. In this method, your ship has its X and Y coords updated and then the image drawn at that location every 17 milliseconds, and that's how you get a ship (and any other object for that matter) to appear like they are moving around on the screen.
I had to make an applet that shows its own source code. This is what I have:
//Reference the required Java libraries
import java.applet.Applet;
import java.awt.*;
//The applet code
public class FirstApplet extends Applet {
public void paint(Graphics g) {
//Draw a rectangle width=250, height=100
g.drawRect(0,0,250,600);
//Set the color to blue
g.setColor(Color.blue);
//Write the message to the web page
g.drawString("\n //Reference the required Java libraries\n import java.applet.Applet;\n import java.awt.*; \n //The applet code\n public class FirstApplet extends Applet {\n public void paint(Graphics g) {\n //Draw a rectangle width=250, height=100\n g.drawRect(0,0,250,100); \n //Set the color to blue\n g.setColor(Color.blue); \n //Write the message to the web page\n g.drawString",10,50);
}
}
However, the \n is not making a new line. My text continues horizontally until finished. How would I crate new lines inside the g.drawString field?
Perhaps you could try something like this (Untested):
public static void draw(final Graphics g, final int startX, final int startY, final String... lines){
final FontMetrics metrics = g.getFontMetrics();
final int spacing = metrics.getHeight() + metrics.getMaxDescent();
draw(g, startX, startY, spacing, lines);
}
public static void draw(final Graphics g, final int startX, final int startY, final int vSpacing, final String... lines){
int y = startY;
for(final String line : lines){
g.drawString(line, startX, y);
y += vSpacing;
}
}
The first method will calculate the height (based on the height and descent of the current Font of your Graphics object). The second method allows you to input a custom vertical spacing value for more customizability.
I had to make an applet that shows its own source code.
Two alternatives:
Use AppletContext.showDocument(URL) to browse to the source file.
Use a JTextArea with JTextComponent.read(Reader,Object) to read the source.
BTW
Why code an applet? If it is due to spec. by teacher, please refer them to Why CS teachers should stop teaching Java applets.
Why AWT rather than Swing? See this answer on Swing extras over AWT for many good reasons to abandon using AWT components. If you need to support older AWT based APIs, see Mixing Heavyweight and Lightweight Components.
I have an assignment where I have to draw a circle in a panel and with that circle calculate the reaction time of the user when the circle changes size or color. I've got the paintComponent method. But now I have to call the method for the circles in another class and I don't know how to do that. Can someone please help me with this?
Here is my class where paintComponent is written:
public class ReactionPanel extends JPanel {
boolean setSmallCircle, setInitialCircle;
Color color = new Color (255,0,0); //color = red
Color c = new Color (255,255,0); //color = yellow
int size;
int x = 250;
int y = x;
public void paintComponent(Graphics g){
super.paintComponent(g);
if (setInitialCircle){
size = 50;
}
if (setSmallCircle) {
size = 50;
}
else {
size = 150;
}
g.drawOval(x,y,size,size);
g.fillOval(x,y,size,size);
}
void setInitialCircle(Graphics g, Color color){
g.setColor(color);
}
void setSmallCircle(Graphics g, Color c){
g.setColor(c);
}
void setBigCircle(Graphics g, Color c){
g.setColor(c);
}
}
Now I would need those (setInitialCircle etc) and call them in my main class ReactionExperiment like so:
void startTest(){
//draw red circle
}
How do I do this?
Thanks for the help!
I believe you want this ?
ReactionPanel reactionPanel = new ReactionPanel();
reactionPanel.setSmallCircle(x, x);
What this code does it instantiates ReactionPanel (it makes a new instance of it). As such you can then use its methods in another class.
I assume you have two classes, and you'd like to call a public function defined in one from the other. Since the method is not a static method, you'd have to instantiate an object for the class like -
ReactionPanel obj = new ReactionPanel();
then using this object, you can call any method defined in the first class, like
obj.paintComponent(g); // you'll have to define g first though