Java: Making an outline of multiple shapes - java

Say I drew two circles 30 pixels radius and 20 pixels apart. You'd get a cross-over of lines. How can I prevent this crossover?
I've tried looking at various graphics filtering but I haven't found anything suitable.
(This question is not limited to 2 circles)

You can use java.awt.geom.Area class to do the operations. It has
add(), intersect(), subtract() methods.
Create one Area (sum of both ovals) and subtract another Area (intersection of both ovals).
Working code:
int x = 200; int y = 200;
Ellipse2D.Double first = new Ellipse2D.Double(x,y,75,75);
Ellipse2D.Double second = new Ellipse2D.Double(x+25,y,75,75);
Area circles = new Area(first);
circles.add(new Area(second));
graphics2D.draw(circles);

Related

(UPDATE)I want to draw circles within circles that get increasingly small by 10 pixels in diameter that are placed around a ring

So my ultimate goal is to draw 50 circles(with processing.core.PApplet) structured around a ring that transitions colors like a neon sign so that it would look like Psychadelics
The circles have to be random sizes and with a diameter of under 210 pixels the circles have to have 8 bars with each "shells" changing colors in order, and at the center, there must be an empty circle with the same color as the background.
Right now I am trying to break this problem into lots of small problems, and currently, I am struggling to make the spaces between the bars to be equally spaced.
Culprit:
(I found the problem to be the ratio between the bar size and the circle size, due to the undefined range random sizing it made seemingly empty circles)
Here is my next problem, The circles seem to be vibrating instead of remaining static, I want the 50 circles to be static while the colors on each shell change each frame.
Here is the part where I tell it to draw smaller and smaller circles
This is the "Drawing component"
public Donut(float x, float y , float d) { //constructor
this.x =x;
this.y =y;
diameter=d;
}
public void draw(PApplet p) {
p.circle(x, y, diameter);
float bar=(float)(Math.random()*(1-10)-1)+1;
for(int i =0; i<8; i++) {
bar+=10;
p.fill(REDS[i],GREENS[i],BLUES[i]);
p.circle(x, y, diameter-bar);
}
}
And here is the part where I tell it to have random sizes and positions(still haven't told it to be placed around a ring yet) //This is the Main Class
public class Psychadelics extends PApplet{
Donut [] DonutList = new Donut [50];
public static void main(String[] args) {
PApplet.main("test.Psychadelics");
}
public void settings() {
size(SCR_W, SCR_H);
}
public void setup() {
for(int i =0; i<DonutList.length;i++) {
float x = (float)(Math.random()*600);
float y = (float)(Math.random()*400);
float diameter = (float)(Math.random()*210);
DonutList [i]= new Donut(x,y,diameter);
}
I have another drawing method inside the main class to tell the Donut class to keep drawing and to keep updating it.
I expect each circle to remain static and to transition colors, each frame but my actual results were the circles each with different colors on each shell vibrating on their specified coordinates
The vibration is caused by float bar=(float)(Math.random()*(1-10)-1)+1;. Because bar is determined inside the draw function, the exact diameter will be slightly different on each frame. Instead, you should create an array of these random floats in the constructor and use random_diameter[i] in the draw loop, so the sizes of the inner circles are created random, but remain constant.
The color remaining constant is caused by p.fill(REDS[i],GREENS[i],BLUES[i]);. You assign specific colors, based on the index, to a circle that is also based on the index. This is where you should use random. For red, green and blue use int(Math.random(0,255));. That way, on each frame, a random color is generated for each circle. If you want more gradual color changes, you'll need to store the color for each circle and add/subtract a small random number. If you want to limit the number of colors, you can use the function you have now, but instead of i, use a random number with the size of the array.
I hope you see that, interestingly, the problems/solutions are each others inverse :)

Rotating Coordinates (Java and Geometry)

I am working on a 2D java game engine using AWT canvas as a basis. Part of this game engine is that it needs to have hitboxes with collision. Not just the built in rectangles (tried that system already) but I need my own Hitbox class because I need more functionality. So I made one, supports circular and 4-sided polygon shaped hitboxes. The way the hitbox class is setup is that it uses four coordinate points to serve as the 4 corner vertices that connect to form a rectangle. Lines are draw connecting the points and these are the lines that are used to detect intersections with other hitboxes. But I now have a problem: rotation.
There are two possibilities for a box hitbox, it can just be four coordinate points, or it can be 4 coordinate points attached to a gameobject. The difference is that the former is just 4 coordinates based on 0,0 as the ordin while the attached to gameobject stores offsets in the coordinates rather than raw location data, so (-100,-100) for example represents the location of the host gameobject but 100 pixels to the left, and 100 pixels up.
Online I found a formula for rotating points about the origin. Since Gameobject based hitboxes were centered around a particular point, I figured that would be the best option to try it on. This code runs each tick to update a player character's hitbox
//creates a rectangle hitbox around this gameobject
int width = getWidth();
int height = getHeight();
Coordinate[] verts = new Coordinate[4]; //corners of hitbox. topLeft, topRight, bottomLeft, bottomRight
verts[0] = new Coordinate(-width / 2, -height / 2);
verts[1] = new Coordinate(width / 2, -height / 2);
verts[2] = new Coordinate(-width / 2, height / 2);
verts[3] = new Coordinate(width / 2, height / 2);
//now go through each coordinate and adjust it for rotation
for(Coordinate c : verts){
if(!name.startsWith("Player"))return; //this is here so only the player character is tested
double theta = Math.toRadians(rotation);
c.x = (int)(c.x*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(c.x*Math.sin(theta)+c.y*Math.cos(theta));
}
getHitbox().vertices = verts;
I appologize for poor video quality but this is what the results of the above are: https://www.youtube.com/watch?v=dF5k-Yb4hvE
All related classes are found here: https://github.com/joey101937/2DTemplate/tree/master/src/Framework
edit: The desired effect is for the box outline to follow the character in a circle while maintaining aspect ratio as seen here: https://www.youtube.com/watch?v=HlvXQrfazhA . The current system uses the code above, the effect of which can be seen above in the previous video link. How should I modify the four 2D coordinates to maintain relative aspect ratio throughout a rotation about a point?
current rotation system is the following:
x = x*Cos(theta) - y *Sin(theta)
y = x*Sin(theta) + y *Cos(theta)
where theta is degree of rotation in raidians
You made classic mistake:
c.x = (int)(c.x*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(c.x*Math.sin(theta)+c.y*Math.cos(theta));
In the second line you use modified value of c.x. Just remember tempx = c.x
before calculations and use it.
tempx = c.x;
c.x = (int)(tempx*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(tempx*Math.sin(theta)+c.y*Math.cos(theta));
Another issue: rounding coordinates after each rotation causes distortions and shrinking after some rotations. It would be wise to store coordinates in floats and round them only for output, or remember starting values and apply rotation by accumulated angle to them.

Changing origin for circle in JPanel

I'm using the JPanel and JFrame to animate an example of something called Circle Packing, which essentially is just filling an object with continuously growing circles to fill the object with circles of different sizes.
I've been able to animate an arraylist of circle objects, but they grow in a way that is not desirable for my project. A circle growing, according to me, is a fixed point P from which a circle with radius R around it is created, and it expands solely by the R increasing. JPanel does not act this way. It changes the x and y positions as well, which I do not understand.
This is my repaint:
public void repaint(Graphics g) {
g.setColor(new Color(125, 0, 100));
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(new Color(255, 165, 0));
Circle myCircle = new Circle(rand.nextInt(500), rand.nextInt(500), 1);
circles.add(myCircle);
for (Circle c : circles) {
int newx = (int) c.getX();
int newy = (int) c.getY();
int newsize = (int) c.getSize();
c.grow();
c.growth(); // These are the growing functions
c.Edges();
g.drawOval(newx, newy, newsize, newsize);
}
}
and my grow, growth and Edges are to check for cases where the circles touches the sides of the screen.
Please edit my question to a more appropriate title if necessary, I'm still new to S.O.
A circle growing, according to me, is a fixed point P from which a circle with radius R around it is created, and it expands solely by the R increasing
Maybe, but you didn't write the Graphics API. So your code needs to work based on the methods of the API.
It changes the x and y positions as well, which I do not understand.
Read the API for the drawOval(...) method to understand how it works. Don't assume how it works.
The method works by specifying the top/left x/y point, not the center point.
So if the radius increases, the x/y values must decrease if you want the center point to remain constant. So you need to fix your grow logic.
I'm using the JPanel and JFrame to animate an example of something called Circle Packing,
Also, don't generate random values in a painting method. You can't control when the component will be repainted so the values can change unexpectedly. That is don't change the state of an object in a painting method.
So you need a method to "grow" each circle (which is separate from your painting code). This method will adjust the radius and x/y location of each object in the Array. Then you invoke repaint() on the panel. The painting code will then just iterate through the Array and paint the current state of each object in the array.

Convert from java.awt.geom.Area to java.awt.Polygon

I need to convert a java.awt.geom.Area or java.awt.Shape to java.awt.Polygon. What I know about the are is: isSingular = true, isPolygonal = true. So I think a polygon shuld be able to describe the same area.
I'm not sure that it is worth converting, because Polygon is an old Java 1.0 class that can store only integer coordinates, so you might lose some precision.
Anyway, you can get a PathIterator from the Shape, and as you iterate it, add new points to a Polygon:
public static void main(String[] args) {
Area a = new Area(new Rectangle(1, 1, 5, 5));
PathIterator iterator = a.getPathIterator(null);
float[] floats = new float[6];
Polygon polygon = new Polygon();
while (!iterator.isDone()) {
int type = iterator.currentSegment(floats);
int x = (int) floats[0];
int y = (int) floats[1];
if(type != PathIterator.SEG_CLOSE) {
polygon.addPoint(x, y);
System.out.println("adding x = " + x + ", y = " + y);
}
iterator.next();
}
}
EDIT As Bill Lin commented, this code may give you a wrong polygon if the PathIterator describes multiple subpaths (for example in the case of an Area with holes). In order to take this into account, you also need to check for PathIterator.MOVETO segments, and possibly create a list of polygons.
In order to decide which polygons are holes, you could calculate the bounding box (Shape.getBounds2D()), and check which bounding box contains the other. Note that the getBounds2D API says that "there is no guarantee that the returned Rectangle2D is the smallest bounding box that encloses the Shape, only that the Shape lies entirely within the indicated Rectangle2D", but in my experience for polygonal shapes it would be the smallest, and anyway it is trivial to calculate the exact bounding box of a polygon (just find the smallest and biggest x and y coordinates).

Plotting functions with using java GUI

I need to plot a polynomial given a start point and an end point. I've looked at using the paincomponent to do do it, but I'm getting confused because the origin is in the top left corner and I need my grid lines to be dynamic.
How do I make it so I can create a dynamic scale and what java class is best used for plotting a function?
For example if the user were to enter -2 2 x^2 the plotter would need to create a grid that goes from -2 has 0 in the middle and 2 on the right for the x coordinates. However if the user enters x^3 we have negative coordinates in the y plane and I'll need to slide the line containing the x coordinates up to accomidate.
Thanks!
The way I think you could do this(and I may be wrong) is to draw the y-line and x-line of your graph, and label the values for x and y using drawString at the correct position.
To illustrate this I did this example for you:
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Point2D.Double from = new Point2D.Double(300, 100);
Point2D.Double to = new Point2D.Double(300, 300);
Line2D.Double line = new Line2D.Double(from, to);
g2.draw(line);
Point2D.Double from2 = new Point2D.Double(150, 200);
Point2D.Double to2 = new Point2D.Double(450, 200);
Line2D.Double line2 = new Line2D.Double(from2, to2);
g2.draw(line2);
g2.drawString("-1", 290, 215);
}
The drawString method would draw "-1" below 0. So you could use the same thing to draw -2 below -1, etc.
I know this sounds inefficient, but it's the only way I can think of.
Hope someone else will have a better solution for you.
It shouldn't be too difficult to transform the y-coordinate if you know the size of area you want to paint to. But to be honest, why don't you use one of the plotting libs like JFreeChart, ...?

Categories

Resources