I am trying to make a stick figure in java - java

I got the head, one arm and the body. I am trying to make another arm using the same first two coordinates, which starts at the bottom of the head, but a negative last (but same number) last two coordinates. I assumed that if I made a negative version, it would just make an opposite version of the line. Instead, its just sticking straight up! I am confused on why this is happening.
import javax.swing.JComponent;
import java.awt.*;
import java.awt.geom.*;
public class StickFigure extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double head = new Ellipse2D.Double(5, 10, 50, 50);
g2.draw(head);
Line2D.Double body=new Line2D.Double(30,60, 30,150);
g2.draw(body);
Line2D.Double arm1=new Line2D.Double(30,60,75,75);
g2.draw(arm1);
Line2D.Double arm2=new Line2D.Double(30,60,-75,-75);
g2.draw(arm2);
}
}
That is the code that is giving me trouble. I am using a viewer which is the following:
import javax.swing.JFrame;
public class Viewer
{
public static void main(String[] arg)
{
JFrame frame = new JFrame();
frame.setSize(1000,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
StickFigure fig1=new StickFigure();
frame.add(fig1);
frame.setVisible(true);
}
}
Please let me know what I am doing wrong, I would greatly appreciate it.

Line2D.Double arm2=new Line2D.Double(30,60,-75,-75);
You need to think about what you're saying with -75 and -75. Remember those make a coordinate, and (0, 0) represents the top left corner in Swing (unless you're explicitly telling it not to). Those coordinates are offscreen to the northwest.
Try something like:
Line2D.Double arm2=new Line2D.Double(30,60, 45,75);

Try using a positive y last coordinate for both:
Line2D.Double arm1=new Line2D.Double(30,60,75,75);
g2.draw(arm1);
Line2D.Double arm2=new Line2D.Double(30,60,-75,75);
g2.draw(arm2);
You are right that -75 -75 "would just make an opposite version of the line", but when you alter both coordinates you get radial simmetry, that is simmetry around a point (the neck) hence one of your arm is low and the other is up. You want axial symmetry in this case, and for that you only need to flip one coordinate; since people's axis of symmetry is the spine, and it is vertical (y-direction) you need to flip coordinate x only.

Related

How to dynamically center a Graphic

Although in this example, the X-Y values are hard-coded, lets assume the user entered the values dynamically and clicked a button to view the results on the screen.
It wouldn't make sense to calculate the frame based on the largest size as the Frame would be too large for the monitor.
What is required to take the X-Y values entered (not matter how large or small) and have the image appear centered within the frame?
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ZoomToXY extends JPanel
{
int x = 0;
public void paint(Graphics g)
{
//Can't see this.
int[] xs2 = {5308, 5306, 4143, 4143, 4120, 4119, 4118, 4117, 4116, 4114, 4112};
int[] ys2 = {4474, 5329, 5306, 5171, 5171, 5173, 5175, 5177, 5179, 5181, 5182};
BasicStroke traceStroke = new BasicStroke (1); //Line thickness
Graphics2D gc = (Graphics2D) g.create();
gc.setColor(Color.RED);
gc.drawPolyline(xs2, ys2, 11);
gc.setStroke(traceStroke);
x++;
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.add(new ZoomToXY());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(20,20, 250,250);
frame.setVisible(true);
}
}
The reason we can't see the polygon or whatever you're making, is because it's outside the frame's bounds. Let's take a look.
frame.setBounds(20,20, 250,250);
This line indicates we will only see what's inside these bounds, though everything outside will also be drawn but not shown. Try drawing a rectangle inside the bounds and see.
g.fillRect(20, 20, 100, 100);
You will see a rectangle. But how can I solve this issue? Since having a frame being 5000px by 5000px isn't going to work on most monitors, either you work with smaller resolutions and therefore smaller coordinates, or you implement a camera. Having a camera you can have as big world as you want and being able to move around in it. But if your frame can only show 100 pixels and your polygon is 1000px, we will only see 10% of it, this problem can easily be solved with zooming. Here is a topic how to implement a gamecamera. With the gameCamera you can simply calculate the center of your image, then translate it, quite simple. If you need assistance just ask.
A frame that is 250x250 is quite small, consider it being a little bigger. Also why set the coordinates as (20, 20)? If you want to center the JFrame to the current monitor just call:
frame.setLocationRelativeTo(null);

Drawing in java with JPanel

I'm making a program where you have a server and a client, and the idea is that you draw on the client jpanel, and the coordinates will then be sent to the server, which will sort of mimic the drawing. I've done that, but the problem is now, that my drawing mechanism is pretty bad. Right now I'm just using an oval that gets drawn over and over again on the coordinate of the mouse, which sometimes leaves spaces between the ovals if you move the mouse too fast.
To better illustrate, here's an SS: http://gyazo.com/6ed1017e9efd6beaa4b5d56052fda260
As you can see, it's only consistent when you move the mouse relatively slow, but as soon as you move it a bit fast, it leaves spaces.
How do I prevent this from happening?
Right now the client just sends x and y coordinates, so here's the server side code:
package com.company;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server extends JPanel{
static MouseData mouseReceive;
static Draw draw;
static int x;
static int y;
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Server server = new Server();
JFrame frame = new JFrame("Server");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(server);
frame.setSize(1024, 600);
frame.setVisible(true);
draw = new Draw(x,y);
ServerSocket serverSock = new ServerSocket(1234);
Socket s = serverSock.accept();
ObjectInputStream in = new ObjectInputStream(s.getInputStream());
while(true) {
mouseReceive = (MouseData) in.readObject();
draw = new Draw(mouseReceive.mouseX,mouseReceive.mouseY);
}
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
draw.display(g);
repaint();
}
}
And here's my draw class:
package com.company;
import java.awt.*;
/**
* Created by John on 21/04/2015.
*/
public class Draw {
int xLoc;
int yLoc;
Draw(int x, int y){
xLoc = x;
yLoc = y;
}
public void display(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.fillOval(xLoc,yLoc,7,7);
}
}
I tried finding someone else having the same problem on this site through the search function, but I had no luck in doing so :( If I missed it however, please direct me to that topic!
If anyone could help me out, I'd appreciate it a whole lot! Have a nice day :)
Presuming the Client is using a MouseListener (or MouseMotionListener): the MouseListener can only fire as fast as a certain interval. For example when the mouse is constantly moved your listener will receive a MouseEvent for every interval rather than every pixel. As a result, moving the mouse fast may result in drawing items that are not adjacent to each other. AFAIK, you cannot increase the speed, but you can draw lines between two sequential points making them look continuous (eg by using a List of each event location and using g.drawLine on each two adjacent points in the List).
Other notes:
You should override paintComponent rather than the paint method.
I would recommend calling super.paintComponent in this method. This will clear the component (hence your code will then only draw the last point - see (3))
I would recommend keeping a List of locations to use for drawing, which you can iterate over and draw each circle (or draw a line between adjacent points)
Do NOT call repaint within your painting methods. The idea here is that when a new item is received from the Client, add it to the List in (3) and then call repaint.

Issues with drawing multiple circles (drawOval / Java)

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.

Java Upside Down Text - Bug or Feature?

While playing around with the Java font class and Swing, I set the font size to a negative value.
I discovered that this makes the text be drawn upside down. Is this a bug or a feature? Can anyone explain why this behavior happens?
Try it out:
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class UpsideDown extends JFrame{
public UpsideDown(){
setSize(500,500);
setContentPane(new Panel());
setVisible(true);
}
public class Panel extends JPanel{
public void paintComponent(Graphics g){
Font f = new Font("Sans-Serif", Font.PLAIN, -50);
g.setFont(f);
g.drawString("Upside Down", 400, 100);
}
}
public static void main(String args[]){
new UpsideDown();
}
}
Seems like this is happening:
Swing draws your font's height downwards, because it multiplies the font size with the glyph height of the font. -50 * glyph_height is negative -> drawing downwards instead of upwards.
It also draws the glyph's (the letter's) width to the left, again because it multiplies your font size with the glyph width specified by the font.
It is a feature.
In Swing there are very few, if any, absolute quantities. Virtually all quantities are algebraic, meaning that they can be negative, and they can participate in algebraic calculations which may change their sign, as the case is when you multiply by -1. For example, a rectangle can have a negative width, and that's perfectly fine. A font is not an exception to this rule.
By all means, do try this at home:
Take any piece of code that you might have lying around which draws 2D graphics in a Graphics2D graphics context. (That would be a component that overrides paintComponent( Graphics g ) and begins with Graphics2D g2 = (Graphics2D)g;) For example, you might have a component that draws a graph, like so:
Before the drawing operations, insert the following two lines:
g2.scale( -1.0, -1.0 );
g2.translate( -getWidth(), -getHeight() );
Now check the result. It will all be perfectly up-side down, like this:
Needless to say, if you double the x scale without doubling the y scale, everything will be elongated, including the characters of the text, like so:
This demonstrates how everything, all the way down to the individual coordinates of character glyphs, is an algebraic quantity in Swing.
This gives a great degree of freedom. If you want to invert the graph but keep the text upright, one way to achieve it is to make the font size negative.

circle packing - java

I have a task to draw a circle and then fill in with the most amount of circles without touching the sides. I can draw the circle, and I can make loops to pack the circle in a hexagonal/honeycomb format, but can't control whether they are inside or outside the circle.
I have used this: g.drawOval(50, 50, 300, 300); to specify my circle. Given I'm actually specifying a square as my boundaries I can't actually determine where the circle boundaries are. So I'm basically packing the square full of circles rather than the circle full of circles.
Can some please point me in the right direction? I'm new to java so not sure if I have done this the complete wrong way. My code is below. I have another class for the frame and another with the main in it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class DrawCircle extends JPanel
{
private int width, height, diameter;
public DrawFrame d;
public DrawCircle()
{
width = 400;
height = 400;
diameter = 300;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.blue);
g.drawOval(50, 50, 300, 300);
for(int i=50; i<200; i=i+20)
{
for(int j=50; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=60; i<200; i=i+20)
{
for(int j=55; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=330; i>190; i=i-20)
{
for(int j=340; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=340; i>190; i=i-20)
{
for(int j=345; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
}
}
All those magic numbers make me cringe a bit. You're new to Java, and it's homework, so I understand why you're doing it, but I would not recommend it if you do much programming in the future.
You need an algorithm or recipe for deciding when a small circle on the inside falls outside the big one you're trying to pack. Think about the ways you might do this:
If the distance between the center of the big circle and the small circle is is greater than the difference in their radii, the small circle will overlap the big circle or fall completely outside it.
You can add this check to your code: Just before you draw the circle, perform this check. Only draw if that circle passes.
Don't worry about Java for a second; draw yourself a picture on a piece of paper, draw that enclosing and packed circle, and see if that statement is correct. Then think about any corner situations that it might not cover, just as a check.
I'll make two more recommendations. First, do this by hand without a computer once so you'll see what the "right" answer might look like. Second, see if you can separate the calculation of the circles from the drawing part. It might make your job easier, because you can concentrate on one thing at a time. It's called "decomposition". You solve complex problems by breaking them up into smaller, more manageable pieces. In this case, it's also called "model-view separation". You might need to know that someday.
Maybe another way to think about this problem would be to imagine a 2D arrangement of circles, packed in their closest arrangement, extending to infinity in both the x- and y-directions. Now take your enclosing circle, put it on top of the 2D arrangement, and eliminate all the circles that overlap the big circle. I don't know if it'll be optimal, but it's easy to visualize.

Categories

Resources