Beginner JavaFX, tracking a max radius generated randomly? - java

I have a project where I have to fill a 600x400 window (JavaFX) with 30 random sized circles with no filling. The largest circle must be filled with a translucent red (and if there are multiple large circles with the same radius only one can be filled). I'm able to get all the circles on the screen fine. My problem is getting the largest circle to be red. I haven't been taught arrays which were used in almost all of my many google searches. I cant figure out how exactly to track the largest circle. His hint to us is : "When it comes to keeping track of the largest circle, remember that two reference variables can point to the same Circle object. Maintain a separate Circle reference variable that always points to the largest circle (so far created). You may want to initialize this variable to a circle that has a radius of 0. You can get the radius of a circle using the getRadius method." I created a circle object and a largestCircle object but don't understand how to make the largestCircle object have the highest radius.
This is the code I have so far:
{
Random gen = new Random();
int x = 0;
int y = 0;
int radius = 0;
double largestRadius = Math.max(radius);
Circle largestCircle = null;
Group root = new Group();
//prints out 30 circles
for (int i = 0; i <= 30; i++)
{
Circle circle = new Circle(x, y, radius);
{
radius = gen.nextInt(66) + 10; //generates random radius from 10 to 75
x = gen.nextInt(600 - 2 * radius) + radius;
y = gen.nextInt(400 - 2 * radius) + radius;
}
if (circle.getRadius() == largestRadius)
{
largestCircle = circle;
largestCircle.setFill(Color.rgb(255, 0, 0, 0.3));
}
circle.setFill(null);
circle.setStroke(Color.rgb(gen.nextInt(256), + gen.nextInt(256), gen.nextInt(256)));
circle.setStrokeWidth(3);
root.getChildren().add(circle);
}
after I generate the random circles how to I find the max radius that was generated and set it to largestCircle? the highest radius a circle can be is 75, but sometimes none of the circles have a radius of 75. How do I set the max to be the highest number the program randomly generates?
Any help would be greatly appreciated! Thank you for your time

How about the following.
It has a two fixes.
-1, use > and not == when figuring if current circle is the largest.
-2, change the color of the largest circle at the end, after all the circles have been made... else you might make multiple circles red.
{
Random gen = new Random();
int x = 0;
int y = 0;
int radius = 0;
double largestRadius = Math.max(radius);
Circle largestCircle = null;
Group root = new Group();
//prints out 30 circles
for (int i = 0; i <= 30; i++)
{
Circle circle = new Circle(x, y, radius);
if (circle.getRadius() > largestRadius)
{
largestCircle = circle;
}
{
radius = gen.nextInt(66) + 10; //generates random radius from 10 to 75
x = gen.nextInt(600 - 2 * radius) + radius;
y = gen.nextInt(400 - 2 * radius) + radius;
}
circle.setFill(null);
circle.setStroke(Color.rgb(gen.nextInt(256), + gen.nextInt(256), gen.nextInt(256)));
circle.setStrokeWidth(3);
root.getChildren().add(circle);
}
largestCircle.setFill(Color.rgb(255, 0, 0, 0.3));

It is generally a good idea to initialize any max variable with a small number that is out of scope for your project. In this case, since radius can not be -1, I would do
double largestRadius = -1;
After this, it doesn't matter how big the radius can be, any radius bigger than -1 will change the largestRadius.
It looks to me like you are only missing one part and that is the if the newly created circle has a radius > largestRadius.
if(circle.getRadius() > largestRadius){
largestCircle = circle;
largestRadius = circle.getRadius();
}
After this, you have checked for if the new circle has a radius greater than AND you have checked if the new circle has a radius equal to. Keeping the if statement that you already have, you will always reference the newest circle with the largestRadius.

I would keep the circle objects in an array. Use a double (or whatever number type is appropriate for your random values) to track the high value with a simple comparison (is my current high value less than the new random value? if so, update high value) each time you generate a random value and create a circle of that size.
Once you have your 30 circles in your array simply loop through it until you find the first occurrence of your high value, when you find it make that circle whatever color.
Circle[] myCircles=new Circle[30];
double largestCircle;
for(int i=0;i<30;i++){
// determine your x,y, and radius here
myCircles[i]=new Circle(x,y,radius);
if(radius>largestCircle) largestCircle=radius;
}
Then to loop thru your myCircles and do things with each one
for(int i=0;i<30;i++){
if(myCircles[i].getRadius()==largestCircle){
// make myCircles[i] red here
}
}

Related

Incomplete Light Circle

I've made a lighting engine which allows for shadows. It works on a grid system where each pixel has a light value stored as an integer in an array. Here is a demonstration of what it looks like:
The shadow and the actual pixel coloring works fine. The only problem is the unlit pixels further out in the circle, which for some reason makes a very interesting pattern(you may need to zoom into the image to see it). Here is the code which draws the light.
public void implementLighting(){
lightLevels = new int[Game.WIDTH*Game.HEIGHT];
//Resets the light level map to replace it with the new lighting
for(LightSource lightSource : lights) {
//Iterates through all light sources in the world
double circumference = (Math.PI * lightSource.getRadius() * 2),
segmentToDegrees = 360 / circumference, distanceToLighting = lightSource.getLightLevel() / lightSource.getRadius();
//Degrades in brightness further out
for (double i = 0; i < circumference; i++) {
//Draws a ray to every outer pixel of the light source's reach
double radians = Math.toRadians(i*segmentToDegrees),
sine = Math.sin(radians),
cosine = Math.cos(radians),
x = lightSource.getVector().getScrX() + cosine,
y = lightSource.getVector().getScrY() + sine,
nextLit = 0;
for (double j = 0; j < lightSource.getRadius(); j++) {
int lighting = (int)(distanceToLighting * (lightSource.getRadius() - j));
double pixelHeight = super.getPixelHeight((int) x, (int)y);
if((int)j==(int)nextLit) addLighting((int)x, (int)y, lighting);
//If light is projected to have hit the pixel
if(pixelHeight > 0) {
double slope = (lightSource.getEmittingHeight() - pixelHeight) / (0 - j);
nextLit = (-lightSource.getRadius()) / slope;
/*If something is blocking it
* Using heightmap and emitting height, project where next lit pixel will be
*/
}
else nextLit++;
//Advances the light by one pixel if nothing is blocking it
x += cosine;
y += sine;
}
}
}
lights = new ArrayList<>();
}
The algorithm i'm using should account for every pixel within the radius of the light source not blocked by an object, so i'm not sure why some of the outer pixels are missing.
Thanks.
EDIT: What I found is, the unlit pixels within the radius of the light source are actually just dimmer than the other ones. This is a consequence of the addLighting method not simply changing the lighting of a pixel, but adding it to the value that's already there. This means that the "unlit" are the ones only being added to once.
To test this hypothesis, I made a program that draws a circle in the same way it is done to generate lighting. Here is the code that draws the circle:
BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, WIDTH, HEIGHT);
double radius = 100,
x = (WIDTH-radius)/2,
y = (HEIGHT-radius)/2,
circumference = Math.PI*2*radius,
segmentToRadians = (360*Math.PI)/(circumference*180);
for(double i = 0; i < circumference; i++){
double radians = segmentToRadians*i,
cosine = Math.cos(radians),
sine = Math.sin(radians),
xPos = x + cosine,
yPos = y + sine;
for (int j = 0; j < radius; j++) {
if(xPos >= 0 && xPos < WIDTH && yPos >= 0 && yPos < HEIGHT) {
int rgb = image.getRGB((int) Math.round(xPos), (int) Math.round(yPos));
if (rgb == Color.white.getRGB()) image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), 0);
else image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), Color.red.getRGB());
}
xPos += cosine;
yPos += sine;
}
}
Here is the result:
The white pixels are pixels not colored
The black pixels are pixels colored once
The red pixels are pixels colored 2 or more times
So its actually even worse than I originally proposed. It's a combination of unlit pixels, and pixels lit multiple times.
You should iterate over real image pixels, not polar grid points.
So correct pixel-walking code might look as
for(int x = 0; x < WIDTH; ++x) {
for(int y = 0; y < HEIGHT; ++y) {
double distance = Math.hypot(x - xCenter, y - yCenter);
if(distance <= radius) {
image.setRGB(x, y, YOUR_CODE_HERE);
}
}
}
Of course this snippet can be optimized choosing good filling polygon instead of rectangle.
This can be solved by anti-aliasing.
Because you push float-coordinate information and compress it , some lossy sampling occur.
double x,y ------(snap)---> lightLevels[int ?][int ?]
To totally solve that problem, you have to draw transparent pixel (i.e. those that less lit) around that line with a correct light intensity. It is quite hard to calculate though. (see https://en.wikipedia.org/wiki/Spatial_anti-aliasing)
Workaround
An easier (but dirty) approach is to draw another transparent thicker line over the line you draw, and tune the intensity as needed.
Or just make your line thicker i.e. using bigger blurry point but less lit to compensate.
It should make the glitch less obvious.
(see algorithm at how do I create a line of arbitrary thickness using Bresenham?)
An even better approach is to change your drawing approach.
Drawing each line manually is very expensive.
You may draw a circle using 2D sprite.
However, it is not applicable if you really want the ray-cast like in this image : http://www.iforce2d.net/image/explosions-raycast1.png
Split graphic - gameplay
For best performance and appearance, you may prefer GPU to render instead, but use more rough algorithm to do ray-cast for the gameplay.
Nonetheless, it is a very complex topic. (e.g. http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/ )
Reference
Here are more information:
http://what-when-how.com/opengl-programming-guide/antialiasing-blending-antialiasing-fog-and-polygon-offset-opengl-programming/ (opengl-antialias with image)
DirectX11 Non-Solid wireframe (a related question about directx11 with image)

Swing drawing sometimes works

I'm trying to draw functions using Java Swing and AWT. The problem is not always all of the 300 points of the graph are drawn. When I loop over the first points of the graph in debug mode, there is much more change the graph is drawn completely. I use the following code to create a JFrame and set the graphics object to the class member g.
jFrame = new JFrame();
jFrame.setSize(WIDTH, HEIGHT);
jFrame.setVisible(true);
g = jFrame.getContentPane().getGraphics();
Then I call this method for every function I want to draw.
private void drawGraph(IGraph graph, Bounds bounds, Ratios ratios) {
//contains visual information about the graph
GraphVisuals visuals = graph.getVisuals();
g.setColor(visuals.color);
//the previous point is remembered, to be able to draw a line from one point to the next
int previousXi = 0;
int previousYi = 0;
//a loop over every point of the graph. The graph object contains two arrays: the x values and the y values
for (int i = 0; i < graph.getSize(); ++i) {
//calculate the x value using the ratio between the graph's size on the x-axis and the window size and the starting point on the x-axis
int xi = (int) (ratios.xRatio * (graph.getX(i) - bounds.xMin) + 0.5);
//analogous for the y axis
int yi = HEIGHT - (int) (ratios.yRatio * (graph.getY(i) - bounds.yMin) + 0.5);
//draw
if (visuals.hasBullets) {
g.fillOval(xi, yi, visuals.bulletSize, visuals.bulletSize);
}
if (visuals.hasLine) {
if (i != 0) {
g.drawLine(previousXi, previousYi, xi, yi);
}
}
previousXi = xi;
previousYi = yi;
}
}

Flipping a polygon that contains many polygons to create an upside down mirror of everything

I have created a polygon with 6 vertices. Lets call this one, outside polygon. Inside the outside polygon I created smaller polygons. I want to flip all of it vertically one point at the time.
I know the vertices of the outside polygon and I have an ArrayList<Polygon> for the inner polygons. I was able to flip the outside polygon. but how do I flipped the inner polygons keeping their relative positions in the new one? I know the center of the outside polygon and the flipped version.
correction: I needed to flip horizontal.
I flipped the outer polygon (triangle shape), and I was able to move the inner polygons. but the distance is incorrect. this is a picture of what I have done,
(https://docs.google.com/drawings/d/1cPYJqxTWVu5gSHFQyHxHWSTysNzxJvNuJIwsgCQInfc/edit) https://docs.google.com/drawings/d/1cPYJqxTWVu5gSHFQyHxHWSTysNzxJvNuJIwsgCQInfc/edit
I tried this:
for (Polygon p : polygonList) {
Polygon tempP = new Polygon(p.xpoints, p.ypoints, p.npoints);
firstPointinPolygon = new Point(p.xpoints[0], p.ypoints[0]);
// find frist point in the polygon
float adjacent = (float) firstPointinPolygon.getX() - 400;
float opposite = (float) firstPointinPolygon.getY() - 400;
float hypotenuse = (float) Math.sqrt(opposite * opposite + adjacent * adjacent);
float cosine = adjacent / hypotenuse;
float sine = opposite / hypotenuse;
float endX = 400 * cosine;
float endY = 400 * sine;
float endXDelta =400-endX;
float endYDelta=400-endY;
Polygon pM = move(tempP, endX, endY);
polygonListMirror.add(pM);
tempP = new Polygon();
}
public Polygon move(Polygon p, double xMove, double yMove) {
// Change the values of the points for the Polygon
for (int i = 0; i < p.xpoints.length; i++) {
p.xpoints[i] += xMove;
p.ypoints[i] += yMove;
}
return p;
}
But did not get the result, I expected. What am I doing wrong? The end result should be like the picture in this link:
(https://docs.google.com/drawings/d/1vYdWkCelWW1_NUypNhtmckBYfEMzCf6bMVtoB-AyPkw/edit) https://docs.google.com/drawings/d/1vYdWkCelWW1_NUypNhtmckBYfEMzCf6bMVtoB-AyPkw/edit
I think something like this will do it:
Polygon outerPolygon, oldOuterPolygon;
ArrayList<Polygon> innerPolygons;
// set up objects
for (Polygon polygon: innerPolygons)
{
for (int i = 0; i < polygon.ypoints.length; i++)
{
polygon.ypoints[i] = center(outerPolygon) - polygon.ypoints[i] + center(oldOuterPolygon);
}
}
If you just to flip it vertically where it stands, such that the y-coordinate of top-most and bottom-most points just switch around, center for both should be the same (thus you can just say 2*center).
I'm pretty sure you can replace center(outerPolygon) and center(oldOuterPolygon) with any point from the applicable Polygon, as long as both use the same point.

Put points round into circular arc used in java

I have me math question: I have known a circle center and radius, and have some uncertain number of points called N, my question is how to put the points on the circular arc, I cannot like put the points around the whole circumference, other as this link: http://i.6.cn/cvbnm/2c/93/b8/05543abdd33b198146d473a43e1049e6.png
in this link, you can read point is circle center, other color is some points, you can see these points around the arc.
Edit - in short: I have known a circle center and radius, so I want to generate some point around the circle center
I am not sure, but I checked this with simple Swing JComponent and seems ok.
Point center = new Point(100, 100); // circle center
int n = 5; // N
int r = 20; // radius
for (int i = 0; i < n; i++)
{
double fi = 2*Math.PI*i/n;
double x = r*Math.sin(fi + Math.PI) + center.getX();
double y = r*Math.cos(fi + Math.PI) + center.getY();
//g2.draw(new Line2D.Double(x, y, x, y));
}
It's not entirely clear what you're trying to accomplish here. The general idea of most of it is fairly simple though. There are 2*Pi radians in a circle, so once you've decided what part of a circle you want to arrange your points over, you multiply that percentage by 2*pi, and divide that result by the number of points to get the angle (in radians) between the points.
To get from angular distances to positions, you take the cosine and sine of the angle, and multiply each by the radius of the circle to get the x and y coordinate of the point relative to the center of the circle. For this purpose, an angle of 0 radians goes directly to the right from the center, and angles progress counter-clockwise from there.

Draw different shape of polygon randomly

My program draw 10 polygon triangles in random sizes (width and height). The coordinate (points) of the polygon were generated using Random generator = new Random(). Since the points of the triangle and the width and height were randomly generated, how can I control the number of sizes drawn? e.g. there are 10 polygon in total, but I wanted to limit the number of different sizes e.g. only 2 or 4 different sizes.
for(int i = 0; i < 10; i++) {
double xWidth = generator.nextDouble() * 50.0 + 20.0; // range width of triangle
double yHeight = generator.nextDouble() * 50.0 + 20.0; // range height of triangle
xCoord[0] = generator.nextInt(300);
yCoord[0] = generator.nextInt(300);
xCoord[1] = (int) (xCoord[0] - xWidth);
xCoord[2] = (int) (xCoord[1] + (xWidth/2));
yCoord[1] = yCoord[0];
yCoord[2] = (int) (yCoord[1] - yHeight);
triangles.add( new Polygon(xCoord,yCoord, 3));
}
Why not just randomly generate 4 shapes and then run a different loop to pick randomly from those four shapes.
This code only generates the tringles, there has to be a .draw() somewhere - you just wrap that in some sort of code that picks one to four triangles - which again will need some sort of randomizer if you want those selected randomly.
int limit = generator.nextInt(4)+1; // [1,4]
for(int i = 0; i < limit; i++) {
//...
}

Categories

Resources