Finding pixels covered by an oval in Java Canvas - java

I'm creating a graphical display to show whether a user is approaching a danger zone. For this i'm using a display similar to that of an archery board. The idea is to start in the center, but as the user gets closer to the danger zone enter the orange zone. And once the user breaks the 'safety threshold' enter the red zone. My idea is to draw a point on the board depending on what value the user gives me.
To draw this board I do the following.
Graphics2D g2d = (Graphics2D) bs.getDrawGraphics();
g2d.setColor(Color.white);
g2d.fillRect(0, 0, 800, 600); //set screen to white
g2d.setColor(Color.red);
g2d.fillOval(250, 250, 175, 175); //draw outerlayer of board as red
g2d.setColor(Color.black);
g2d.drawOval(250, 250, 175, 175);//give this red an outline
g2d.setColor(Color.orange);
g2d.fillOval(275, 275, 125, 125); //draw innerlayer as orange
g2d.setColor(Color.black);
g2d.drawOval(275, 275, 125, 125);//give this orange an outline
g2d.setColor(Color.green);
g2d.fillOval(300, 300, 75, 75); //draw innermost layer as green
g2d.setColor(Color.black);
g2d.drawOval(300, 300, 75, 75); //give the green an outline
First of all I could probably improve this, but that's not the main issue for now.
Instead my issue is finding exactly the pixels covered by each part of the board.
I've been using x+(width/2), y+(height/2) to get the center point
Thus using:
g2d.drawString(String.valueOf("X"), 338, 338);
To draw the center point of my green oval. This doesn't seem overly accurate but anyway.
I thought I would be able to simply give the outer edge as the x,y co-ords and the inner edge as the x+height, y+width co-ords as so:
g2d.drawOval(500, 500, 75, 75);
g2d.drawString(String.valueOf("X"), 537, 537); //centre???
g2d.drawString(String.valueOf("X"), 575, 575); //inneredge?x+width, y+height
g2d.drawString(String.valueOf("X"), 500, 500); //outer edge x+y co-ords
However, I think due to the oval shape this doesn't work.
I would be very grateful if someone could show me how to find the pixel range that each oval covers.
EDIT: Below is the board that i'm using, is it possible to find the pixel range for each color(Red,Orange,Green)?

Understanding a bit more what you wanted, here is the trick (using trigonometry):
int force = ...; // from 0 to 250
int radius = ...; // radius of the target (50 for example)
int centerX = ...; // X-coordinate of the center of the target
int centerY = ...; // Y-coordinate of the center of the target
double direction = Math.toRadians(Math.random() * 360); // a random angle between 0° and 360°
double x = (force * radius / 250.0d) * Math.cos(direction) + centerX; // X-coordinate of the new point
double y = (force * radius / 250.0d) * Math.sin(direction) + centerY; // Y-coordinate of the new point
Point2D point = new Point2D.Double(x,y); // Then you can plot this point on your target

All of your ovals appear to be circles. So, let's create a Circle model class.
You would call the draw method from a JPanel paintComponent method.
You would call the contains method when you want to see if a point is inside or on the edge of a circle.
You would keep track of all of the circles in a List, so you can maintain the order of the circles.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public class Circle {
private final int radius;
private final Color color;
private final Point location;
public Circle(int x, int y, int radius, Color color) {
this.location = new Point(x, y);
this.radius = radius;
this.color = color;
}
public boolean contains(int x, int y) {
double distance = Point.distance(x, y, location.x, location.y);
double radiusD = radius;
if (radiusD >= distance) {
return true;
} else {
return false;
}
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(location.x - radius, location.y - radius, radius + radius,
radius + radius);
}
}

Use a concrete Ellipse2D for each zone. Then you can use g2d.fill() to draw the zone. Since an Ellipse2D is also a Shape, you can use the contains(Point2D p) method to check if a point is in bounds. Since the circles overlap, you'll have to check them in front-to-back order.

Related

How could I make my Snowmans arms wave using Graphics 2D?

So I am currently creating a drawing that creates a Snowman, as well as some other objects in the background. I got the drawing part down, it looks just as it should, but I wanted to add a little bit of movement within it. I used Graphics2D to draw all my shapes, lines, ellipses, etc., but I'm not sure how/if I can make the Snowmans arms wave back and forth with the drawLine method.
I provided the code for the entire Snowman here. It's very simple, as I said it just uses Graphics2D to draw everything. The arm1 and arm2 are near the bottom.
public class Snowman {
private int x;
private int y;
private int width;
private int height;
public Snowman(int x, int y, int width, int height) {
this.x=x;
this.y=y;
this.width=width;
this.height=height;
}
public void draw(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// the body of the snowman
g2.setColor(Color.WHITE);
g2.fillOval(x+125, y+40, 200, 200);
g2.fillOval(x+75, y+140, 300, 300);
g2.fillOval(x+25, y+290, 400, 400);
// the buttons
g2.setColor(Color.BLACK);
g2.fillOval(x+210, y+210, 40, 40);
g2.fillOval(x+210, y+270, 40, 40);
g2.fillOval(x+210, y+330, 40, 40);
// the eyes and mouth
g2.fillOval(x+190, y+98, 20, 20);
g2.fillOval(x+245, y+98, 20, 20);
g2.drawArc(x+180, y+120, 100, 50, 200, 140);
// arm1
g2.drawLine(x+75, y+270, x, y+90);
//arm2
g2.drawLine(x+375, y+270, x+450, y+90);
// the hat
g2.setColor(Color.BLACK);
g2.fillRect(x+177, y+40, 100, 30);
g2.fillRect(x+202, y, 50, 50);
}
}
Is there a way I can implement something to make them move? Or would I have to draw these another way?
you can add a method that adjusts the coordinates of the hand, and this method might contain some if statement so say if the hand reached specific x it will subtract from x to go to the other direction. And then call this method inside the draw function

Rotate a rect about an arc in java swing

I want to move this small rectangle about the circumference of the circle, so that I looks and moves like a canon.
Code
private void doDrawing(Graphics g){
g.setColor(Color.BLUE);
g.fillArc(-CANON_RADIUS/2, this.getHeight()-CANON_RADIUS/2, CANON_RADIUS, CANON_RADIUS, 0, 90);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
Rectangle rect = new Rectangle(CANON_RADIUS/2, this.getHeight()-CANON_RADIUS/2, CANON_WIDTH, CANON_HEIGHT);
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(-60), rect.getX() + rect.width/2, rect.getY() + rect.height/2);
Shape transformed = transform.createTransformedShape(rect);
g2d.fill(transformed);
}
This code rotates rectangle about its centre. How can I rotate rectangle around the circumference?
First things first, you can use a transformation matrix for this, like you are already using:
http://en.wikipedia.org/wiki/Transformation_matrix
Edit:
looking at your code, you want to rotate your canon around an anchor. Please look at the javadocs:
http://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.html
public void rotate(double theta,
double anchorx,
double anchory)
the first argument is your rotation, the last two arguments have to be the middle of your cannon base! like screen.height and 0 for your example:
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(-60), 0, Screen.height);
Shape transformed = transform.createTransformedShape(rect);
g2d.fill(transformed);
second approach could be move the middle of your rotated rectangle around the radius of your base.
like (pseudocode):
Point p = circle.getPoint();
shape.moveto(p.x-(shape.width/2),p.y-(shape.height/2));
g2d.fill(shape);

How to draw a circle with given X and Y coordinates as the middle spot of the circle?

I have developed a telecommunication application for locating signal strengths from the towers. I have used java swing and I'm having a problem when drawing the circle around the given point of the mobile signal transmitter tower location. I have already calculated the X, Y coordinates and also the radius value.
Please find the below code which I've used to draw the circle and it is having issues.
JPanel panelBgImg = new JPanel() {
public void paintComponent(Graphics g) {
g.drawOval(X, Y, r, r);
}
}
The issue is, it creates the circle but it didn't take the X and Y coordinates as the center point. It took the X and Y coordinates as the top left point of the circle.
Could anyone please help me to draw the circle by having the given X and Y coordinates as the center point of the circle.
The fillOval fits an oval inside a rectangle, with width=r, height = r you get a circle.
If you want fillOval(x,y,r,r) to draw a circle with the center at (x,y) you will have to displace the rectangle by half its width and half its height.
public void drawCenteredCircle(Graphics2D g, int x, int y, int r) {
x = x-(r/2);
y = y-(r/2);
g.fillOval(x,y,r,r);
}
This will draw a circle with center at x,y
So we are all doing the same home work?
Strange how the most up-voted answer is wrong. Remember, draw/fillOval take height and width as parameters, not the radius. So to correctly draw and center a circle with user-provided x, y, and radius values you would do something like this:
public static void drawCircle(Graphics g, int x, int y, int radius) {
int diameter = radius * 2;
//shift x and y by the radius of the circle in order to correctly center it
g.fillOval(x - radius, y - radius, diameter, diameter);
}
Replace your draw line with
g.drawOval(X - r, Y - r, r, r)
This should make the top-left of your circle the right place to make the center be (X,Y),
at least as long as the point (X - r,Y - r) has both components in range.
drawCircle(int X, int Y, int Radius, ColorFill, Graphics gObj)
JPanel pnlCircle = new JPanel() {
public void paintComponent(Graphics g) {
int X=100;
int Y=100;
int d=200;
g.drawOval(X, Y, d, d);
}
};
you can change X,Y coordinates and radius what you want.
both answers are is incorrect. it should read:
x-=r;
y-=r;
drawOval(x,y,r*2,r*2);
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Graphiic
{
public Graphics GClass;
public Graphics2D G2D;
public void Draw_Circle(JFrame jf,int radius , int xLocation, int yLocation)
{
GClass = jf.getGraphics();
GClass.setPaintMode();
GClass.setColor(Color.MAGENTA);
GClass.fillArc(xLocation, yLocation, radius, radius, 0, 360);
GClass.drawLine(100, 100, 200, 200);
}
}
This draws an arc with the center in the specified rectangle. You can draw, half-circles, quarter-circles, etc.
g.drawArc(x - r, y - r, r * 2, r * 2, 0, 360)
The only thing that worked for me:
g.drawOval((getWidth()-200)/2,(getHeight()-200)/2, 200, 200);

How to draw a circle within a circle?

I'm trying to get a bunch of small circles that have varying shades of green to be drawn within a big circle to get a "bush" look, but I can't figure out how to get all the small circles within the shape of a big circle. I can only figure out how to get it within a rectangle.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i = 0; i < 1000; i++){
int redV = (int) ((Math.random() * 100) + 27);
g.setColor(new Color(red, red + 31, red - 15));
int x = (int) ((Math.random() * 400) + 150);
int y = (int) ((Math.random() * 500) + 200);
g.fillOval(x, y, 50, 50);
}
}
I guess you have to do some geometry here, and verify whether the x and y coordinates generated randomly are within your circle. As you said, within a rectangle is easy (because you just check that x > left, x+50 < right, y > top, y+50 < bottom), however for a circle you have to use the equation of a circle and check that (x,y) and (x+50,y+50) are within it before actually doing the fillOval().
I think you have a simple way out by using the Java 2D Shape.contains(), which is implemented by Ellipse2D. So essentially you create an instance of Ellipse2D.Double or Ellipse2D.Float for the greater circle, and then just call contains() each time you generate the coordinates to check they are within it before drawing them.
I think you can just change the Color slightly, and increment/decrement x, y, width, and height slightly to get them to be within the older circle. The new oval should be painted over the old one.
Choose the point that should be the center of the big circle, and draw the big circle relative to that (e.g. using java.awt.geom.Ellipse2D).
You can then use the center of the big circle and its radius to position the other smaller circles relative to that also, inside the circumference.

Java - Draw a ruler (line with tick marks at 90 degree angle)

I'm using Java AWT to draw lines on a panel (Line2D and Graphics2D.drawLine()) and I'm wondering how I can draw a line with tick marks, similar to:
|----|----|----|----|----|
I know the positions I'd like to draw the ticks at in advance.
The lines could be in any position, so the ticks must be drawn at an angle releative to the line itself.
My basic geometry & ability to apply it in Java is failing me. :)
I suggest you
implement a ruler-drawing-method that draws a simple horizontal ruler from left to right
Figure out the desired angle using Math.atan2.
Apply an AffineTransform with translation and rotation before invoking the ruler-drawing-method.
Here is a complete test-program. (The Graphics.create method is used to create a copy of the original graphics object, so we don't mess up the original transform.)
import java.awt.*;
public class RulerExample {
public static void main(String args[]) {
JFrame f = new JFrame();
f.add(new JComponent() {
private final double TICK_DIST = 20;
void drawRuler(Graphics g1, int x1, int y1, int x2, int y2) {
Graphics2D g = (Graphics2D) g1.create();
double dx = x2 - x1, dy = y2 - y1;
double len = Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
at.concatenate(AffineTransform.getRotateInstance(Math.atan2(dy, dx)));
g.transform(at);
// Draw horizontal ruler starting in (0, 0)
g.drawLine(0, 0, (int) len, 0);
for (double i = 0; i < len; i += TICK_DIST)
g.drawLine((int) i, -3, (int) i, 3);
}
public void paintComponent(Graphics g) {
drawRuler(g, 10, 30, 300, 150);
drawRuler(g, 300, 150, 100, 100);
drawRuler(g, 100, 100, 120, 350);
drawRuler(g, 50, 350, 350, 50);
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 400);
f.setVisible(true);
}
}
Note, that you could just as easily draw numbers above the ticks. The drawString-calls would go through the same transformation and get nicely "tilted" along the line.
Things that need noting:
A perpendicular line has a slope of -1/oldslope.
In order to support lines in any direction, you need to do it parametrically
Thus, you have dy and dx across the original line, which means that newdx=dy; newdy=-1*dx.
If you have it such that <dx, dy> is a unit vector (sqrt(dx*dx+dy+dy)==1, or dx==cos(theta); dy=sin(theta) for some theta), you then just need to know how far apart you want the tick marks.
sx, sy are your start x and y
length is the length of the line
seglength is the length of the dashes
dx, dy is the slopes of the original line
newdx, newdy are the (calculated above) slopes of the cross lines
Thus,
Draw a line from <sx,sy> (start x,y) to <sx+dx*length,sy+dy*length>
Draw a set of lines (for(i=0;i<=length;i+=interval) from <sx+dx*i-newdx*seglength/2,sy+dy*i-newdy*seglength/2> to <sx+dx*i+newdx*seglength/2,sy+dy*i+newdy*seglength/2>
I hope you know matrix multiplication. In order to rotate a line you need to multiple it by rotation matrix. (I coudln't draw a proper matrix but assume both line are not separated)
|x'| = |cos(an) -sin(an)| |x|
|y`| = |sin(an) cos(an)| |y|
The old points are x,y and the new is x',y'. Let us illustrate by an example, lets say you have a vertical line from (0,0) to (0,1), now you want to rotate it by 90 degrees. (0,0) will remain zero so lets just see what happens to (0,1)
|x'| = |cos(90) -sin(90)| |0|
|y`| = |sin(90) cos(90)| |1|
==
|1 0| |0|
|0 1| |1|
==
| 1*0 + 0*1|
| 0*0 + 1*1|
== |0|
|1|
you get to horizontal line (0,0),(0,1) like you would expect.
Hope it helps,
Roni

Categories

Resources