/*
* Pseudo-Mondrian Art Generator
*
* Copyright (C) 2002 J. David Eisenberg
*
*/
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.Graphics2D;
import java.util.Random;
class Artist {
static final Color bright[] = {
Color.white, Color.black, Color.green, Color.magenta,
Color.orange, Color.yellow, Color.red
};
static final Color pastel[] = {
new Color(0xcccccc), new Color(0x999999),
new Color(0xccffcc), new Color(0xffccff),
new Color(0xffcc99), new Color(0xffffcc),
new Color(0xffcccc)
};
static final int BRIGHT = 0;
static final int PASTEL = 1;
static final int VERTICAL = 0;
static final int HORIZONTAL = 1;
int width, height;
int currentColor;
Color palette[];
Random rand;
int depth;
/**
* Artist no-argument constructor
* Constructs a 200 by 200 canvas with bright color palette.
*/
public Artist()
{
this( 200, 200, BRIGHT );
}
/**
* Artist two-argument constructor
* Constructs a canvas of the given width and height
* with a bright color palette.
* @param width Width of the painting
* @param height Height of the painting
*
*/
public Artist( int width, int height )
{
this( width, height, BRIGHT );
}
/**
* Artist three-argument constructor
* Constructs a canvas of the given width and height
* with the desired color palette
* (BRIGHT or PASTEL)
* @param width Width of the painting
* @param height Height of the painting
* @param colorType Palette to use
*
*/
public Artist( int width, int height, int colorType )
{
this.width = width;
this.height = height;
if (colorType == BRIGHT)
{
palette = bright;
}
else if (colorType == PASTEL)
{
palette = pastel;
}
rand = new Random();
currentColor = rand.nextInt(palette.length);
}
/**
* Paint a Mondrian-style artwork
* @param g The Graphics2D environment into which
* to draw.
*/
public void paint( Graphics2D g )
{
depth = 0;
partition( g, new Rectangle(5, 5, width, height),
(rand.nextInt(2) == 0) ? VERTICAL : HORIZONTAL );
g.setColor( Color.black );
g.draw( new Rectangle( 5, 5, width, height ) );
}
/**
* Partition a rectangle into draw-able sections
* If a rectangle is too small, or is the result of the
* fourth subdivision of a larger rectangle, we paint it.
* Otherwise, we divide it in the direction perpendicular
* to the direction in which its parent was divided.
* This happens 70% of the time - the other 30% we decide
* not to subdivide it, and paint it instead.
* The rectangle is divided into either two slices (approx. 75%
* of the time) or three slices (the rest of the time).
* @param g The Graphics2D environment into which
* to draw.
* @param r The initial Rectangle2D to be partitioned.
* @param direction One of VERTICAL or HORIZONTAL.
*/
public void partition( Graphics2D g, Rectangle2D r, int direction )
{
boolean subdivide;
/*
* If an area is too small, or if we've nested to deep,
* don't subdivide it; otherwise, subdivide it 70% of the time
* or if it's the top level.
*/
if (r.getWidth() < 60 || r.getHeight() < 60 || depth > 4 )
{
subdivide = false;
}
else
{
subdivide = (rand.nextFloat() < 0.70) || (depth == 0);
}
if (subdivide)
{
int i;
int nSlices;
double percentage[] = new double[3];
double x, y, height, width;
/*
* change slice direction
*/
direction = (direction == VERTICAL) ? HORIZONTAL : VERTICAL;
/*
* Randomly establish the width or height of the slices.
*/
if (rand.nextFloat() < 0.75)
{
nSlices = 2;
percentage[0] = .20 + (rand.nextDouble() * 0.60);
percentage[1] = 1 - percentage[0];
}
else
{
nSlices = 3;
percentage[0] = .20 + (rand.nextDouble() * 0.60);
percentage[1] = rand.nextDouble() * (1 - percentage[0]);
percentage[2] = 1 - (percentage[0]+percentage[1]);
}
x = r.getX();
y = r.getY();
width = r.getWidth();
height = r.getHeight();
/*
* Partition each of the slices.
*/
depth++;
if (direction == HORIZONTAL)
{
for (i=0; i < nSlices; i++)
{
r.setRect( x, y, width, height * percentage[i] );
partition( g, r, direction );
y += height * percentage[i];
}
}
else
{
for (i=0; i < nSlices; i++)
{
r.setRect( x, y, width * percentage[i], height );
partition(g, r, direction);
x += width * percentage[i];
}
}
}
else
{
/*
* Paint this rectangle and outline it in black.
*/
g.setColor( palette[currentColor] );
g.fill( r );
g.setColor( Color.black );
g.draw( r );
currentColor = (currentColor + 1) % palette.length;
}
}
}