问题
I've gotten some help in another one of my questions to get me this far but I'd like to know how to make my squares generate behind one another rather than on top of each other. The below code is what I've got so far.
This is the code that places them behind each other recursively:
import java.awt.image.*;
import java.awt.Color;
import java.io.*;
import javax.imageio.*;
import java.util.*;
public class FractalDriver {
static final int SIDE = 1000; // image is SIDE X SIDE
static BufferedImage image = new BufferedImage(SIDE, SIDE, BufferedImage.TYPE_INT_RGB);
static final int WHITE = Color.WHITE.getRGB();
static final int BLACK = Color.BLACK.getRGB();
static Scanner kbd = new Scanner(System.in);
public static void main(String[] args) throws IOException {
String fileOut = "helloSquares.png";
// make image black
for (int i = 0; i < SIDE; i++) {
for (int j = 0; j < SIDE; j++) {
image.setRGB(i, j, BLACK);
}
}
Square square = new Square(SIDE / 2, SIDE / 2, SIDE / 2, WHITE);
drawSquare(square);
// save image
File outputfile = new File(fileOut);
ImageIO.write(image, "jpg", outputfile);
}
public static void drawSquare(Square square) { // center of square is x,y length of side is s
if (square.side <= 0) { // base case
return;
} else {
// determine corners
int left = square.center_x - (square.side / 2);
int top = square.center_y - (square.side / 2);
int right = square.center_x + (square.side / 2);
int bottom = square.center_y + (square.side / 2);
int newColor = square.color - 100000;
Square newSquareA = new Square(left, top, square.side / 2, newColor);
Square newSquareB = new Square(left, bottom, square.side / 2, newColor);
Square newSquareC = new Square(right, top, square.side / 2, newColor);
Square newSquareD = new Square(right, bottom, square.side / 2, newColor);
// recursively paint squares at the corners
drawSquare(newSquareA);
drawSquare(newSquareB);
drawSquare(newSquareC);
drawSquare(newSquareD);
//placing the for loop here starts at the end and moves toward the beginning
//it appears in the png that the squares are behind eachother
for (int i = left; i < right; i++) {
for (int j = top; j < bottom; j++) {
image.setRGB(i, j, square.color);
}
}
}
}
}
This is the code that prints them on top of eachother:
import java.awt.image.*;
import java.awt.Color;
import java.io.*;
import javax.imageio.*;
import java.util.*;
public class FractalDriver {
static final int SIDE = 1000; // image is SIDE X SIDE
static BufferedImage image = new BufferedImage(SIDE, SIDE, BufferedImage.TYPE_INT_RGB);
static final int WHITE = Color.WHITE.getRGB();
static final int BLACK = Color.BLACK.getRGB();
static Scanner kbd = new Scanner(System.in);
public static void main(String[] args) throws IOException {
String fileOut = "helloSquares.png";
// make image black
for (int i = 0; i < SIDE; i++) {
for (int j = 0; j < SIDE; j++) {
image.setRGB(i, j, BLACK);
}
}
Square square = new Square(SIDE / 2, SIDE / 2, SIDE / 2, WHITE);
drawSquare(square);
// save image
File outputfile = new File(fileOut);
ImageIO.write(image, "jpg", outputfile);
}
public static void drawSquare(Square square) { // center of square is x,y length of side is s
if (square.side <= 0) { // base case
return;
} else {
// determine corners
int left = square.center_x - (square.side / 2);
int top = square.center_y - (square.side / 2);
int right = square.center_x + (square.side / 2);
int bottom = square.center_y + (square.side / 2);
int newColor = square.color - 100000;
Square newSquareA = new Square(left, top, square.side / 2, newColor);
Square newSquareB = new Square(left, bottom, square.side / 2, newColor);
Square newSquareC = new Square(right, top, square.side / 2, newColor);
Square newSquareD = new Square(right, bottom, square.side / 2, newColor);
for (int i = left; i < right; i++) {
for (int j = top; j < bottom; j++) {
image.setRGB(i, j, square.color);
}
}
// recursively paint squares at the corners
drawSquare(newSquareA);
drawSquare(newSquareB);
drawSquare(newSquareC);
drawSquare(newSquareD);
//placing the for loop here starts at the end and moves toward the beginning
//it appears in the png that the squares are behind eachother
}
}
}
The only difference here is the placement of the for loop (one before recursive calls, one after recursive calls)
Here is the same program but without the recursion:
import java.awt.image.*;
import java.awt.Color;
import java.io.*;
import javax.imageio.*;
import java.util.*;
public class TSquare {
static final int SIDE = 1000; // image is SIDE X SIDE
static final int WHITE = Color.WHITE.getRGB();
static final int BLACK = Color.BLACK.getRGB();
static Scanner kbd = new Scanner(System.in);
public static void main(String[] args) throws IOException{
BufferedImage image = new BufferedImage(SIDE, SIDE, BufferedImage.TYPE_INT_RGB);
drawImage(SIDE, image);
saveImage(image);
}
//#########################################################################
protected static void drawImage(final int SIDE, BufferedImage image) {
final int HALF = SIDE / 2;
//Draw background
new Square(HALF, HALF, SIDE, BLACK).draw(image);
//Draw foreground starting with centered half sized square
Square square = new Square(HALF, HALF, HALF, WHITE);
drawSquare(square, image);
}
//#########################################################################
protected static void drawSquare(Square square,BufferedImage image) {
LinkedStack<Square> stack = new LinkedStack<>();
stack.push(square);
square.draw(image);
while (!stack.isEmpty()) {
square = stack.top();
stack.pop();
int half = square.half();
if (half > 1) {
int left = square.left();
int top = square.top();
int right = square.right();
int bottom = square.bottom();
int newColor = square.color - 100000;
stack.push(new Square(left, top, half, newColor,square));
stack.push(new Square(left, bottom, half, newColor,square));
stack.push(new Square(right, top, half, newColor,square));
stack.push(new Square(right, bottom, half, newColor,square));
}
square.draw(image);
}
}
//#########################################################################
public static void saveImage(BufferedImage image) throws IOException {
String fileOut = "helloSquares.png";
File outputfile = new File(fileOut);
ImageIO.write(image, "jpg", outputfile);
}
}
THE SQUARE CLASS:
import java.awt.Color;
import java.awt.image.BufferedImage;
public class Square {
{
final int BLACK = Color.BLACK.getRGB();
final int WHITE = Color.WHITE.getRGB();
protected int center_x;
protected int center_y;
protected int side;
protected int color;
protected Square parentSquare;
public Square() {
this.center_x = 0;
this.center_y = 0;
this.side = 0;
this.color = WHITE;
this.parentSquare = null;
}
public Square(int center_x, int center_y, int side, int color) {
this.center_x = center_x;
this.center_y = center_y;
this.side = side;
this.color = color;
this.parentSquare = null;
}
public Square(int center_x, int center_y, int side, int color, Square parentSquare) {
this.center_x = center_x;
this.center_y = center_y;
this.side = side;
this.color = color;
this.parentSquare = parentSquare;
}
public void setX(int center_x) {
this.center_x = center_x;
}
public int getX() {
return center_x;
}
public void setY(int center_y) {
this.center_x = center_y;
}
public int getY() {
return center_y;
}
public void setSide(int side) {
this.side = side;
}
public int getSide() {
return side;
}
public void setColor(int color) {
this.color = color;
}
public int getColor() {
return color;
}
public void setParent(Square parentSquare) {
this.parentSquare = parentSquare;
}
public Square getParent() {
return parentSquare;
}
public int half() {
return side / 2;
}
public int left() {
return center_x - half();
}
public int top() {
return center_y - half();
}
public int right() {
return center_x + half();
}
public int bottom() {
return center_y + half();
}
public void draw(BufferedImage image) {
int left = left();
int top = top();
int right = right();
int bottom = bottom();
for (int i = left; i < right; i++) {
for (int j = top; j < bottom; j++) {
image.setRGB(i, j, color);
}
}
}
public boolean contains(int x, int y) {
int s = this.side;
// If at least one of the dimensions is negative
if (s < 0) {
return false;
}
//if coordiante is top left and outside of square
if (x < (this.center_x / 2) && (y < (this.center_y / 2))) {
return false;
}
//if coordinate is bottom left and outside of square
if ((x < (this.center_x / 2)) && (y > (this.center_y + (this.center_y / 2)))) {
return false;
} //checks up and down from x bounds
else if (((x > (this.center_x / 2)) && (x < this.center_x + (this.center_x / 2)))
&& (y < (this.center_y / 2)) || y > this.center_y + (this.center_y / 2)) {
return false;
}
//if coordiante is top right and outside of square
if ((x > (this.center_x + (this.center_x / 2))) && (y < (this.center_y / 2))) {
return false;
}
//if coordinate is bottom right and outside of square
if ((x > (this.center_x + (this.center_x / 2))) && (y > (this.center_y + (this.center_y / 2)))) {
return false;
} //checks left and right from y bounds
else if (((y > (this.center_y / 2)) && (y < this.center_y + (this.center_y / 2)))
&& (x < (this.center_x / 2)) || x > this.center_x + (this.center_x / 2)) {
return false;
}
return true;
}
}
THE LINKED STACK CLASS:
public class LinkedStack<T> implements StackInterface<T>
{
protected LLNode<T> top; // reference to the top of this stack
public LinkedStack()
{
top = null;
}
public void push(T element)
// Places element at the top of this stack.
{
LLNode<T> newNode = new LLNode<T>(element);
newNode.setLink(top);
top = newNode;
}
public void pop()
// Throws StackUnderflowException if this stack is empty,
// otherwise removes top element from this stack.
{
if (isEmpty())
throw new StackUnderflowException("Pop attempted on an empty stack.");
else
top = top.getLink();
}
public T top()
// Throws StackUnderflowException if this stack is empty,
// otherwise returns top element of this stack.
{
if (isEmpty())
throw new StackUnderflowException("Top attempted on an empty stack.");
else
return top.getInfo();
}
public boolean isEmpty()
// Returns true if this stack is empty, otherwise returns false.
{
return (top == null);
}
public boolean isFull()
// Returns false - a linked stack is never full
{
return false;
}
}
STACK OVERFLOW CLASS:
public class StackOverflowException extends RuntimeException
{
public StackOverflowException()
{
super();
}
public StackOverflowException(String message)
{
super(message);
}
}
STACK UNDERFLOW CLASS:
public class StackUnderflowException extends RuntimeException
{
public StackUnderflowException()
{
super();
}
public StackUnderflowException(String message)
{
super(message);
}
}
STACK INTERFACE:
public interface StackInterface<T>
{
void push(T element) throws StackOverflowException;
// Throws StackOverflowException if this stack is full,
// otherwise places element at the top of this stack.
void pop() throws StackUnderflowException;
// Throws StackUnderflowException if this stack is empty,
// otherwise removes top element from this stack.
T top() throws StackUnderflowException;
// Throws StackUnderflowException if this stack is empty,
// otherwise returns top element of this stack.
boolean isEmpty();
// Returns true if this stack is empty, otherwise returns false.
boolean isFull();
// Returns true if this stack is full, otherwise returns false.
}
THE LLNODE CLASS:
public class LLNode<T> {
{
protected LLNode<T> link;
protected T info;
public LLNode(T info) {
this.info = info;
link = null;
}
public void setInfo(T info) {
this.info = info;
}
public T getInfo() {
return info;
}
public void setLink(LLNode<T> link) {
this.link = link;
}
public LLNode<T> getLink() {
return link;
}
/**
*Adds a link to a Node
*
* @param newLink The Link to be added
*/
public void addLink(LLNode<T> newLink){
if (link == null){
this.link = newLink;
}else{
LLNode<T> temp = link;
LLNode<T> pre = null;
while (temp != null){
pre = temp;
temp = temp.link;
}
}
}
}
Basically what I'm trying to achieve is I want to modify my above code (code without recursion) to paint the squares behind eachother rather than on top of eachother similarly to how the very first FractalDriver class I posted (very top recursive one) paints them
回答1:
Here's an iterative solution that is slower than recursion but is pixel perfect.
I'd like to work on making it faster but I'm outta time right now.
Hope it helps.
package com.stackoverflow.candied_orange;
import java.awt.image.*;
import java.awt.Color;
import java.io.*;
import javax.imageio.*;
import java.util.*;
public class InFrontInterative {
public static void main(String[] args) throws IOException{
final int SIDE = 1000; // image is SIDE X SIDE
BufferedImage image = new BufferedImage(SIDE,SIDE,BufferedImage.TYPE_INT_RGB);
drawImage(SIDE, image);
saveImage(image, "helloSquares.png");
}
//Removed IO to enable unit testing
protected static void drawImage(final int SIDE, BufferedImage image) {
final int BLACK = Color.BLACK.getRGB();
final int WHITE = Color.WHITE.getRGB();
final int HALF = SIDE / 2;
//Draw background on whole image
new Square(HALF, HALF, SIDE, BLACK).draw(image);
//Draw foreground starting with centered half sized square
Square square = new Square(HALF, HALF, HALF, WHITE);
drawFractal(square, image);
}
private static void drawFractal(Square square, BufferedImage image){
Stack<Square> squares = new Stack<>();
Queue<Square> breeders = new LinkedList<>();
breeders.add(square);
//Produce
while (breeders.size() > 0) {
square = breeders.remove();
int half = square.half();
if (half > 0) {
System.out.println(half);//TODO remove debugging code
int left = square.left();
int top = square.top();
int right = square.right();
int bottom = square.bottom();
int newColor = square.color - 100000;
breeders.add(new Square(left, top, half, newColor));
breeders.add(new Square(left, bottom, half, newColor));
breeders.add(new Square(right, top, half, newColor));
breeders.add(new Square(right, bottom, half, newColor));
squares.push(square);
}
}
//Consume
while (squares.size() > 0) {
square = squares.pop();
square.draw(image);
}
}
protected static void saveImage(BufferedImage image, String fileOut)
throws IOException {
File outputfile = new File(fileOut);
ImageIO.write(image, "jpg", outputfile);
}
}
来源:https://stackoverflow.com/questions/57946906/how-do-i-make-my-squares-generate-behind-each-other-rather-than-on-top-of-eachot