Using self-referential arrays, polygons are invisible - java

I used an array that refers to previous elements in the same array to determine what the next value will be. This is so that I can get relative values for position when drawing polygons.
There are no reported syntax errors, but the triangles I use here in the example are either invisible or don't exist.
For this example, I would like to make small black triangles randomly scattered in the top half of the window without regard for the window's edges and the other triangles.
The following is the code which includes an example of what I'm trying to achieve, but without using a self-referential array (I wrote this in BlueJ and have never written anything outside of BlueJ. I don't know how to write continuous code so please bear with me. I wrote where each of the two classes begin after each // :
//first class
import javax.swing.*;
public class patterns {
public static void main(String[] args) {
JFrame f = new JFrame("Example");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
example p = new example();
f.add(p);
f.setSize(400,400);
f.setVisible(true);
}
}
//next class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.Color;
public class example extends JPanel{
public void paintComponent (Graphics g){
super.paintComponent(g);
this.setBackground(Color.WHITE);
//The following is the part of the code that doesn't work.
g.setColor(Color.BLACK);
int x=0;//this x is used for the following while loop
int[] xC = new int[3];//these are the x coordinates of the random triangles
int[] yC = new int[3];//these are the y coordinates of the random triangles
while(x<14){//this while loop is used to make many triangles
xC[0]= (int)Math.random()*400;
xC[1]= xC[0]+(int)Math.random()*20;
xC[2]= xC[1]+(int)Math.random()*4;
yC[0]= (int)Math.random()*200;
yC[1]= yC[0]-(int)Math.random()*10;
yC[2]= yC[0]-(int)Math.random()*3;
g.fillPolygon(xC,yC,3);//I changed this to fillPolygon
x++;//this is so the loop will eventually end
}
//the following is the manual part that does work.
int[] xCe = new int[3];//this is the array of x coordinates for the triangle
xCe[0]= 200;
xCe[1]= 210;
xCe[2]= 213;
int[] yCe = new int[3];//this is the array of y coordinates for the triangle
yCe[0]= 300;
yCe[1]= 295;
yCe[2]= 299;
g.fillPolygon(xCe,yCe,3);//this polygon appears properly
//everything after this is just to help explain after compiling
g.drawString("There should be a whole bunch of little triangles that look",20,320);
g.drawString("sort of like this one, but on the top half of this window.", 40,340);
g.drawLine(170,270,200,290);
g.drawLine(194,289,200,290);
g.drawLine(197,285,200,290);
g.drawString("this one",140,260);
}
}
What is causing them to be invisible? I would like for them to be visible. I don't know what I am doing wrong. Is it the self-referential arrays? Is that not allowed for fillPolygon()?

You initialize the values in your arrays like this:
xC[0]= (int)Math.random()*400;
But the cast happens before the multiplication, so the value returned by Math.random() (which will be less than 1) gets cast to an int, so it becomes 0*400, therefore 0 gets stored into all the indices of your array.
To fix this, just put parentheses around the multiplication so it looks like:
xC[0]= (int)(Math.random()*400);
I should also note that your loop is just drawing the same triangle 14 times, so you still won't see a bunch of different triangles. To fix that, just put the code you use to generate your triangles inside of your loop, like so:
for (int i = 0; i < 14; i++) {
int[] xC = new int[3];
xC[0] = (int) (Math.random() * 400);
xC[1] = xC[0] + (int) (Math.random() * 200);
xC[2] = xC[1] + (int) (Math.random() * 4);
int[] yC = new int[3];
yC[0] = (int) (Math.random() * 200);
yC[1] = yC[0] - (int) (Math.random() * 10);
yC[2] = yC[0] - (int) (Math.random() * 3);
g.setColor(Color.BLACK);
g.fillPolygon(xC,yC,3);
}
I'd also suggest giving your triangles a more uniform size (sides of < 3 and 4 are kind of small), perhaps generate a random value between a low and high number (e.g. 10 to 20). And maybe look into the java.util.Random class while you're at it.

Related

Does Java Swing limit how many items it will draw?

I'm writing a recursive method in Java that creates essentially creates a circle tree. It draws a circle at the top and center and then the method gets called again and creates the circles one level lower on the y axis and half way to the left and right of the new circle. I was successful but only for a certain number of objects to be drawn This is what it looks like
public void test(Graphics g, int y, int num, double instance) {
if(num<50) {
int r = 20;
for(int i=1;i<=instance;i++) {
if(i%2==1) {
g.fillOval(getWidth() * i / num, y, r, r);
}
}
if(instance==1){
instance= 2* instance;
}
test(g, y + 20, num * 2, Math.pow(instance,2.0));
}
Everything works perfectly until I try to increase the number in "if(num<50)" to exactly "if(num<65)". When I change that the JFrame appears but now it is empty and it seems like the program is frozen. I want to increase that so that I can fill the Jframe with the circle tree. Why is it doing that? Looking forward to your response! Thank you!
I found the issue. I don't know why I choose to use Math power when I only had to use *2 and that fixed the whole program.

Java Drawing Frame: Refreshing?

just to preface, I am very new to java. So expect dumb mistakes.
I am trying to do a project with java's drawing panel, within BlueJ, and I cannot figure out how to make a program that has a moving object. This is a project, so the code is provided. We are having to modify it in whatever way we want. We are not able to add any other packages.
I know it has to do with some sort of loop, but I am making some type of mistake where it is just printing a ton of circles, instead of a new type every time I press refresh. Here is the code.
import java.awt.*;
import javax.swing.*;
public class DrawingPanel extends JPanel {
public void paintComponent(Graphics g)
{
// clear screen
g.setColor(Color.white);
g.clearRect(0,0,500,500);
{
System.out.printf("Spring Design Barker Spring 2018%n");
int x = 125;
int y = 125;
int w = 50;
int h =80;
int b = 50;
int rd = 255 ;
int gn = 255 ;
int bl = 0 ;
Circle c1,c2;
Rectangle r1,r2;
Triangle t1,t2;
Color clr1,c;
clr1 = new Color(rd,gn,bl);
r1 = new Rectangle(x,y,w,h,clr1);
clr1 = new Color(106,96,200);
t1=new Triangle(x,y,w,h,clr1);
clr1 = new Color(220,15,15);
c1=new Circle(x,25,25,clr1);
r1.draw(g); /*display the rectangle */
t1.draw(g); /*display the triangle */
c1.draw(g); /*display the circle */
t1.setH(-h); /*display the triangle */
t1.setColor(new Color(15,220,15)); /*display the triangle */
t1.draw(g); /*display the triangle */
x=200;
y=200;
for(int k=0;k<9;k++)
{
c=new Color(255-k*20,0+k*15,0+k*25); // vary color
c1=new Circle(200,10 * k,50,c);
c1.draw(g); /*display the new circle */
}
//c=new Color(0,255,0); // change paint in can to green
//c2=new Circle(300,50,10,c);
//c2.draw(g); /*display the new circle */
}
}
}
The mistake is that you are drawing the circle again and again. Every time the code in the loop runs a new circle is drawn. You have to understand that when you draw the circle you are not actually redrawing the same circle but drawing a new circle. What I understand you want to do is to make a circle moving. You can do that by running this whole method again and again. The way I prefer to do this is by using the Swing Timer. It is a way to run a loop calling the paintComponent() method in simple words.
I am actually working on something and I am using this library to display graphics. The only thing I don't like about that is that it uses a lot of CPU. Maybe there is better way to do this.

Color filling a shape using Turtle in Java

I've been looking for a while now at how to fill a shape with a certain color using Turtle in java.
Let's say I have something like this:
private static void test(Turtle t1) {
for (int count = 0; count < 4; count++) {
t1.fd(100);
t1.right(90);
}
}
Where t1 is: Turtle t1 = new Turtle();
The code above creates a simple rectangle, and what I'm trying to figure out, is how to fill that rectangle with color (red, green, blue) . I've looked at the documentation in this link But so far I couldn't figure it out.
Thanks.
I've seen more useful methods like begin_fill then "do something" and end_fill for Turtle Graphics in Python and it seems that the Java implementation works different but I believe I achieved what you need (but I'm not sure if that's the best approach though) but I agree with you, I couldn't find info about this plus, the methods described in the link that you provided are not the same as the ones from the Turtle object in the Java code. Why? because your Turtle object is using the fd method to move forward while the provided documentation says that there's a forward method to do so (make sure you are using the correct library, in my case I'm using jturtle-0.1.1.jar and the methods are accurate to the code snippet from the OP).
Java code:
package com.turtle.main;
import java.awt.Color;
import ch.aplu.turtle.Turtle;
public class TurtleMain {
public static void main(String[] args) {
Turtle turtle = new Turtle();
// Init config
turtle.setColor(Color.RED);
turtle.setPenColor(Color.BLUE);
turtle.setFillColor(Color.GREEN);
// Draw rectangle
for (int count = 0; count < 4; count++) {
turtle.fd(100);
turtle.right(90);
}
// Fill rectangle
turtle.fill(1, 1);
}
}
So, when using the fill method (which makes the trick) you will see that there's one without parameters and another one expecting X and Y coordinates.
Obtained from the Turtle class:
/** Fills the region the Turtle is in.
A Region is bounded by lines
of any other color than the background color and by the border of
the Window. <br>
#return the turtle to allow chaining.
*/
public Turtle fill(){
getPlayground().fill(this);
return this;
}
/** Fills the region with coordinates <code>x</code> and <code>y</code>.
A Region is bounded by lines
of any other color than the background color and by the border of
the Window. <br>
#return the turtle to allow chaining.
*/
public Turtle fill(double x, double y){
double oldX = getX();
double oldY = getY();
boolean hidden = isHidden();
ht().setPos(x,y);
getPlayground().fill(this);
setPos(oldX, oldY);
if(!hidden){
st();
}
return this;
}
However, when I invoke just fill() it doesn't work but when specifying X=1 and Y=1 in the fill(x, y) method, it works (could be good to debug the core methods to see what's going on?) anyway, I didn't do it but when using above code, this is the output:

Java: Making an outline of multiple shapes

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);

Java Rectangles and Casting

Obviously based on the class assignment this is homework..so help me as much as you can/want, don't flame me for posting HW okay?
I have been dying, reading through my book, reading through online for the past two hours and can't find for the love of god WHY this stupid rectangle says "Cannot find Method setX()". Also is there a way to make the doubles, be ints without casting them as int? It looks really messy, and we aren't supposed to add anything except in the method enclosing...I think I have to cast??
Thanks for any help you can give..
import java.awt.Rectangle;
import java.util.ArrayList;
public class Homework18A
{
public static void main(String[] args)
{
ArrayList<Rectangle> test = new ArrayList<Rectangle>();
test.add(new Rectangle(10, 20, 30, 40));
test.add(new Rectangle(20, 10, 30, 40));
test.add(new Rectangle(10, 20, 40, 50));
test.add(new Rectangle(20, 10, 50, 30));
Rectangle enc = enclosing(test);
System.out.println(enc);
System.out.println("Expected: java.awt.Rectangle[x=10,y=10,width=60,height=60]");
}
/**
Computes the smallest rectangle enclosing all rectangles in
an array list.
#param rects an array list of rectangles of size >= 1
#return the smallest rectangle enclosing all rectangles in rect
*/
public static Rectangle enclosing(ArrayList<Rectangle> rects)
{
Rectangle containRec = new Rectangle(0, 0, 0, 0);
for(int i = 0; i < rects.size(); i++) {
if(rects.get(i).getX() < containRec.getX())
containRec.setX((int)rects.get(i).getX());
if(rects.get(i).getY() < containRec.getY())
containRec.setY((int)rects.get(i).getY());
if(rects.get(i).getX() + rects.get(i).getWidth() > containRec.getWidth())
containRec.setWidth(((int)rects.get(i).getX() + rects.get(i).getWidth()));
if(rects.get(i).getY() + rects.get(i).getHeight() > containRec.getHeight())
containRec.setHeight(((int)rects.get(i).getY() + rects.get(i).getHeight()));
}
return containRec;
}
}
Because Rectangle does not have a method setX() or setY(). If you're trying to set the position you want to use setLocation(x,y).
Edit: there is no setWidth() or setHeight() methods either, you want to use setSize(width, height). Even though the Rectangle class has fields for x, y, width, and height it does not follow the normal Java conventions where the fields are made private and public getter and setter methods are used. In this case you could access the fields directly and just say containRec.x = whatever, but it's a bad habit to get in to.
You don't want to remove the (int) casts, but you can definitely clean up that section. Instead of calling rects.get(i) you could put a line at the beginning of the loop that says Rectangle currentRect = rects.get(i); or better yet use a for-each loop.
Sorry but I had to lauch :D
Poor Matt :-*
Here is the link for the api: http://download.oracle.com/javase/1,5,0/docs/api/java/awt/Rectangle.html
There is no setX() or setY()
I assume you're using the java.awt.Rectangle class. It does not have a setX method (take a look at the Javadocs to confirm this), but it does declare it's x field to be public, so you can just set it directly:
containRec.x = whatever;
The same goes for y, of course. Directly setting public fields is generally A Bad Thing (as #Jordan Bently pointed out), but it'll work in this case.
Or you can use some combination of setLocation, setBounds, setSize, setRect or setFrame.
EDIT: You can get rid of all those nasty casts by using entirely integer arithmetic. Instead of using getX(), which returns a double, just look up the x field directly - it's an int.
The java.awt.Rectangle class is somewhat cumbersome to use.

Categories

Resources