How to draw multiple objects on a canvas? - java

I'm trying to draw multiple objects in a canvas but keep getting a runtime error, below is my GraphicalObject Class:
/*import javafx.scene.canvas.Canvas;*/
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import java.util.Scanner;
public class GraphicalObject { //class
private Scanner scan;
private int x;
private int y;
private int width;
private int height;
//private double xPoints;
//private double yPoints;
//private int numPoints;
/*
* constructor
*/
public GraphicalObject(){
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
//this.xPoints = 0;
//this.yPoints = 0;
//this.numPoints = 0;
}
public GraphicalObject(int x, int y, int width, int height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
//think of get/set methods ie acessor/mutators
//get x
//get y
//get width
//get height
public void draw(GraphicsContext gc){
//int numPoints = 5;
//double[] xPoints = new double[numPoints];
//double[] yPoints = new double[numPoints];
//xPoints = [x + (width/2), x + width, x + .8333 width, x + .1667 width, x]
//yPoints = [y, y + (height/2), y + height, y + height, y + (height/2)]
` gc.setFill(Color.PINK);
gc.fillRect(this.x, this.y, this.width, this.height);
//gc.fillPolygon(xPoints, yPoints, numPoints);
}
}
I can't figure out where I'm going wrong, I think my for loops are okay... I'm able to draw one rectangle but if I say I want to draw two, it lets me input info for one object and then gives a runtime error. This is my canvas class:
/**
* A basic canvas object that can store and
* draw graphical object
*/
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
import javafx.scene.canvas.GraphicsContext;
import java.util.Scanner;
public class GraphicalObjectCanvas extends Canvas {
// data fields
// constants
public static final int C_WIDTH = 500;
public static final int C_HEIGHT = 500;
// instance variables
/**
* a scanner object to make the Canvas interactive
*/
private Scanner scan;
// TO DO: DECLARE YOUR ARRAY OF GRAPHICAL OBJECTS HERE
// (AND ANY OTHER INSTANCE VARIABLES YOU NEED TO MAINTAIN YOUR ARRAY)
GraphicalObject[] graphobs;
private int index;
private int numObjects;
/**
* Creates a canvas for drawing graphical objects
* with a size of C_WIDTHxC_HEIGHT pixels
*/
public GraphicalObjectCanvas() {
super(C_WIDTH, C_HEIGHT);
// initialize the scanner object
this.scan = new Scanner(System.in);
// find out how many objects the user wants to add
System.out.println("How many graphical objects do you want?");
numObjects = scan.nextInt();
// TO DO: DEFINE YOUR ARRAY OF GRAPHICAL OBJECTS HERE
graphobs = new GraphicalObject[numObjects];
// for each object they wanted to add...
for (int i = 0; i < numObjects; i++) {
this.add();
}
}
public void draw() {
// clear the picture
this.clear();
// get the graphics context from the canvas
GraphicsContext gc = this.getGraphicsContext2D();
// TO DO: LOOP THROUGH YOUR ARRAY OF GRAPHICAL OBJECTS
// AND TELL EACH ONE TO DRAW PASSING THE GRAPHICS CONTEXT (gc) AS INPUT
for(int i = 0; i < numObjects; i++){
graphobs[i].draw(gc);
System.out.println("Object drawn: " + i); //or 1??);
}
}
private void clear() {
GraphicsContext gc = this.getGraphicsContext2D();
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, C_WIDTH, C_HEIGHT);
}
private void add() {
System.out.println("What is the x location of the object?");
int x = scan.nextInt();
System.out.println("What is the y location of the object?");
int y = scan.nextInt();
System.out.println("What is the width of the object?");
int width = scan.nextInt();
System.out.println("What is the height of the object?");
int height = scan.nextInt();
// TO DO: USE THE INFORMATION ABOVE TO CREATE A NEW GRAPHICAL OBJECT
// AND ADD IT TO THE ARRAY OF OBJECTS.
GraphicalObject gob = new GraphicalObject( x, y, width, height);
graphobs[index] = gob;
index++;
// after adding new object, redraw the canvas
this.draw();
}
}

The problem is that you are invoking GraphicalObject.draw(GraphicsContext) on a null object.
This occurs because you call GraphicalObjectCanvas.draw() at the end of the GraphicalObjectCanvas.add() method and the for loop in GraphicalObjectCanvas.draw() uses numObjects to determine the range of indices. However, you have yet to create and allocate an object to all the indices of the array graphobs when this for loop executes.
To fix this, either do not invoke GraphicalObjectCanvas.draw() at the end of your GraphicalObjectCanvas.add() method, or change the for loop in GraphicalObjectCanvas.draw() to i < index rather than i < numObjects.
For example:
for(int i = 0; i < index; i++){
graphobs[i].draw(gc);
System.out.println("Object drawn: " + i); //or 1??);
}

Related

Trying to create a 5x5 grid of squares with std draw but squares are at duplicate coordinates

I am trying to create a 5x5 board of rectangles(squares) with a 2d array but my code draws the 25 squares in only 5 places so it looks like there's only 5 squares diagonally on the "board". I'm assuming something is wrong with the logic in the nested loop but after tinkering around for a while I can't figure out what it is. Thanks for any help!!
Object class:
public class Card
{
private double x, y, wd, ht;
private int cardNum;
private boolean faceUp;
private double space;
private Color bsC, fsC;
Random gen = new Random();
public Card(double x, double y, double width, double height, int cN, double sP)
{
this.x = x;
this.y = x;
wd = width;
ht = height;
faceUp = false;
this.cardNum = cN;
space = 0.1;
bsC = new Color(178, 178, 178);
fsC = new Color(211, 172, 250);
}
public void drawMe()
{
StdDraw.setPenColor(bsC);
StdDraw.filledRectangle(x, y, wd, ht);
}
}
Tester class:
public class ClientCardJordanHubbard
{
public static void ClientCardJordanHubbard()
{
Random gen = new Random();
Card[][] cards = new Card[5][5];
int count = 0;
StdDraw.setFont(new Font("Arial", Font.BOLD, 20));
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.text(0.5,0.5, "Press w a s d to move");
StdDraw.pause(2000);
StdDraw.clear();
for(int i = 0; i < cards.length; i++)
{
double x = 0.25+0.14*i;
for (int j = 0; j < cards[i].length; j++)
{
double y = 0.25+0.14*j;
double w = 0.07;
double h = 0.07;
int cN = gen.nextInt(5)+1;
cards[i][j] = new Card(x, y, w, h, cN, 0.1);
cards[i][j].drawMe();
System.out.println("The value of the card at index " +i+" " +j
+ " is: " +cards[i][j].getcN());
System.out.println("The coordinates of the card at index " +i+" " +j
+ " is: " +cards[i][j].getX() +" "+cards[i][j].getY());
}
}
}
Since your cards are displayed diagonally, the first thing you need to check whether your x will get an y value or vice-versa at some point. Knowing this, it is easy to find the error, which is the line of
this.y = x;
since your this.y gets an x value.

How to load pixel from one image in another

I'm new to Java and ImageJ and I'm trying to write a PluginFilter with ImageJ and Java. I want it to crop the right and left side of an image (500 pixel each), turn those parts 90 degrees to the outside and load them in a new image.
I already tried couple of options and now I got totally confused. I don't think there is any mistake in the algorith itself, but in the handling of ImageProcessor etc..
import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.filter.*;
public class Cropping28_Plugin implements PlugInFilter {
ImagePlus imp;
public int setup(String arg, ImagePlus imp){
imp = IJ.getImage();
this.imp = imp;
return DOES_ALL;
}
public void run(ImageProcessor ip){
// int[] p = null;
// int[] q = null;
int height = imp.getHeight();
int width = imp.getWidth();
// New Image
ImagePlus new_image = IJ.createImage("Nr1", "RGB", height, 500, 1);
// turning the picture for y=0:500 (left side of picture)
for(int x = 0; x < height; x++){
for(int y = 0; y < 500; y++){
int k = 0;
// loading pixel
int q = imp.getProcessor().getPixel(x, y);
int [] convert = {q, q, q};
// pixel in newimage
int a = height - k;
int b = x;
new_image.getProcessor().putPixel(a, b, convert);
k++;
}
}
// turning the picture for y=get.Length:get.Length-500 (right side of picture)
for(int x = 0; x < height; x++){
for(int y = width -500; y < width; y++){
int k = 0;
// loading pixel
int q = imp.getProcessor().getPixel(x, y);
int [] convert = {q, q, q};
// pixel in new image
int a = height - k;
int b = x;
new_image.getProcessor().putPixel(a, b, convert);
k++;
}
}
// draw new picture
new_image.show();
}
}
I expect the output to be a picture containing the pixel of the right and left edge of the original image. The actual output is a write image of the size I expect.
It would be awesome if someone had an idea!

How do I fill a shape created by random points (drawLine)?

I'm creating a game that has randomly drawn Asteroids (to give the Asteroids a jagged look). After research I've only found that you can fill primitive shapes. Does anyone know a method I could use to fill these shapes?
package view.game_object;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Asteroid extends BaseGameObject {
public static final int BASE_SIZE = 10;
private final int fragmentCount;
private final int[][] points;
private final int level;
public Asteroid(int level, Random r) {
this.level = level;
this.setBound(level * Asteroid.BASE_SIZE);
int sizeRange = (int) (this.getBound() / 2);
this.fragmentCount = this.level * 6;
// generate random points to draw
this.setPosition(0, 0);
this.points = new int[fragmentCount][2];
ArrayList<Float> angleList = new ArrayList<>();
for (int i = 0; i < fragmentCount; i++) {
angleList.add(r.nextFloat() * (float) (Math.PI * 2));
}
Collections.sort(angleList);
for (int i = 0; i < this.points.length; i++) {
// base point
float x = r.nextInt(sizeRange) + this.getBound() - sizeRange / 3;
// rotate
float[] point = BaseGameObject.rotate(x, 0, this.getPosx(), this.getPosy(),
angleList.get(i));
this.points[i][0] = (int) point[0];
this.points[i][1] = (int) point[1];
}
}
public int getLevel() {
return level;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.gray);
for (int i = 0; i < this.points.length; i++) {
int nextPoint = i + 1;
if (nextPoint >= this.points.length) {
nextPoint = 0;
}
g.drawLine(Math.round(this.getPosx()) + this.points[i][0],
Math.round(this.getPosy()) + this.points[i][1],
Math.round(this.getPosx()) + this.points[nextPoint][0],
Math.round(this.getPosy()) + this.points[nextPoint][1]
);
}
}
}
you can use the Graphics methods to draw a polygon. but you must 'transform' your points into a proper format getXs(), i didn't point that out, i'm pretty sure you can do this as good as i can =)
#Override
public void draw(Graphics g) {
g.setColor(Color.gray); //fillColor
int[] xPoints = getXs(this.points);
int[] yPoints = getYs(this.points);
int nPoints = xPoints.length;
g.fillPolygon(xPoints, yPoints, nPoints);
}

Implement a subclass Square that extends the Rectangle class

//Implement a subclass Square that extends the Rectangle class. In the constructor,
accept the x- and y-positions of the center and the side length of the square. Call the
setLocation and setSize methods of the Rectangle class. Look up these methods in the
documentation for the Rectangle class. Also supply a method getArea that computes
and returns the area of the square. Write a sample program that asks for the center
and side length, then prints out the square (using the toString method that you
inherit from Rectangle) and the area of the square.
//Ok... So this is last minute, but I don't understand what is wrong with my code it is giving me the error that square cannot be resolved to a type... So here is my Class:
import java.awt.Rectangle;
public class Squares22 extends Rectangle
{
public Squares22(int x, int y, int length) {
setLocation(x - length / 2, y - length / 2);
setSize(length, length);
}
public int getArea() {
return (int) (getWidth() * getHeight());
}
public String toString() {
int x = (int) getX();
int y = (int) getY();
int w = (int) getWidth();
int h = (int) getHeight();
return "Square[x=" + x + ",y=" + y + ",width=" + w + ",height=" + h
+ "]";
}
}
//And this is my tester class...
import java.util.Scanner;
public class Squares22Tester
{
public static void main(String[] args)
{
Scanner newScanx = new Scanner(System.in);
Scanner newScany = new Scanner(System.in);
Scanner newScanl = new Scanner(System.in);
System.out.println("Enter x:");
String x2 = newScanx.nextLine();
System.out.println("Enter y:");
String y2 = newScany.nextLine();
System.out.println("Enter length:");
String l2 = newScanl.nextLine();
int x = Integer.parseInt(x2);
int y = Integer.parseInt(y2);
int length = Integer.parseInt(l2);
Square sq = new Square(x, y, length);
System.out.println(sq.toString());
}
}
//Can anyone please help my assignment is due at midnight.. It says square cannot be resolved to a type on the tester class when compliling....
Square isn't the name of your class. The name of the class is 'Squares22'. This is why 'Square' cannot be recognized.
Change Square in the test to Squares22 or vice versa. This should solve your issues.

How to create an array of Rectangles with a Rectangle class?

I'm working on an assignment that is supposed to return an array of 10 rectangles with a random height, random width, and random color selected from a string.
The program works fine to return the objects for ONE rectangle, but how would I implement this to create an array of 10 rectangles and THEN return each one in a loop?
Here's my class file with my objects:
import java.util.*;
public class Rectangle
{
private double width;
private double height;
public static String color = "White";
private Date date;
Rectangle() {
width = 1;
height = 1;
date = new Date();
}
Rectangle (double w, double h) {
width = w;
height = h;
date = new Date();
}
public double getHeight() {
return height;
}
public void setHeight(double h) {
height = h;
}
public double getWidth() {
return width;
}
public void setWidth(double w) {
width = w;
}
public static String getColor() {
return color;
}
public static void setColor(String c) {
color = c;
}
public Date getDate() {
return date;
}
public void setDate (Date d) {
date = d;
}
public double getArea() {
return width * height;
}
public double getPerimeter() {
return 2 * (width + height);
}
public String toString() {
String S;
S = "Rectangle with width of " + width;
S = S + " and height of " + height;
S = S + " was created on " + date.toString();
return S;
}
}
Here is my client program so far. I am setting a random height and a random width and selecting a random color from the colors String.
I would like to be able to do this for an array of 10 different rectangles:
import java.util.*;
public class ClientRectangle
{
public static void main(String[] args)
{
String[] colors = {"White","Blue","Yellow","Red","Green"};
Rectangle r = new Rectangle();
int k;
for(int i = 0; i < 10; i++)
{
r.setWidth((Math.random()*40)+10);
r.setHeight((Math.random()*40)+10);
System.out.println(r.toString() + " has area of " + r.getArea() + " and perimeter of " + r.getPerimeter());
k = (int)(Math.random()*4)+1;
System.out.println(colors[k]);
}
}
}
Thanks!
Create an array of rectangles and add a rectangle to each index.
Rectangle[] arr = new Rectangle[10];
for(int i = 0; i < 10; i++)
{
Rectangle r = new Rectangle();
r.setWidth((Math.random()*40)+10);
r.setHeight((Math.random()*40)+10);
arr[i] = r;
}
Move the Rectangle r = new Rectangle(); inside the for loop. Initialise a Array(List) outside the loop, and keep adding the Rectangles in the loop to the array.
You already seem to know how to declare an array of objects because you did so with an array of Strings. The declartion for an array of Rectangles is very similar:
Rectangle[] rects;
Note that you must also initialize the array. Since arrays are themselves objects you use the new operator, somewhat like when you initialize a reference variable to a single Rectangle:
Rectangle[] rects = new Rectangle[SIZE];
The only difference, as you can see, is that you put the size of the array inside the []s. This only creates an array of references to Rectangle objects. The references are all automatically set to null. This means that you need to create the Rectangles themselves. You can do this in for loop:
for (int i = 0; i <= SIZE; ++i) {
rects[i] = new Rectangle();
}
You can also set the width and height of each Rectangle as you want. (I will leave the exact details about how to do this to the reader.)
Finally, you need to put this all in a method other than main() so that you can return the whole array (You don't return one Rectangle at a time) as the instructions state:
return rects;

Categories

Resources