// "JavaPlaid.java" version 0.9
//
// Copyright 1997 Thomas Insel
//
// You may redistribute this file provided it is unchanged and you
// include the entirety of this notice and disclaimer. You may
// distribute a compiled version of this file provided you reproduce
// the entirety of this notice and disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// Please contact the author if you wish to distribute this file under
// different conditions or have changes to the file.
//
// You may obtain the current version of this file from
// http://jaka.ece.uiuc.edu/~tinsel/Java/Tartan/src/JavaPlaid.java
//
// DISCLAIMER
//
// This software is provided "as is" and any express or implied
// warranties, including, but not limited to the implied warranties of
// merchantability and fitness for a particular purpose are
// disclaimed.
//
// In no event shall Thomas Insel be liable for any direct, indirect,
// special, exemplary, or consequential damages (including, but not
// limited to, procurement of substitute goods or services; loss of
// use, data, or profits; or business interruption) however caused an
// on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out
// of the use of this software, even if advised of the possibility of
// such damage.
// TODO -- preprocess string to deal with no spaces.
// -- put utility functions in their own classes.
import java.applet.Applet;
import java.awt.*;
import java.awt.image.*;
import java.util.StringTokenizer;
import java.net.*;
/**
* A tartan patterned component.
* @version 1.0, 1 June 1997
* @author Thomas Insel
*/
public class Plaid extends Canvas {
private Image tartan;
private int threadCount=0;
private String sett;
private int symmetry;
private boolean darkened;
/**
* NOSYMM -- the threads are used as given in the sett.
*/
public static final int NOSYMM = 0;
/**
* SINGLEPIVOT -- the middle bands are reflected around the rightmost band. For
* example, "R 1 O 1 Y 1 G 1" becomes "R 1 O 1 Y 1 G 1 Y 1 O 1".
*/
public static final int SINGLEPIVOT = 1;
/**
* DOUBLEPIVOT -- the first TWO bands are not repeated. For example,
* "R 1 O 1 Y 1 G 1" becomes "R 1 O 1 Y 1 G 1 Y 1". I'm not positive this is
* the proper meaning of double pivot.
*/
public static final int DOUBLEPIVOT = 2;
/**
* Creates the component with the given sett, symmetry, and darkened values.
* For example,
* Plaid("R 16 W 16 B 16", SINGLEPIVOT, true)
* @param sett an alternating list of color abbreviations and thread counts
* @param symmetry one of: NOSYMM, SINGLEPIVOT, or DOUBLEPIVOT
* @param darkened do we darken the colors?
*/
public Plaid(String sett, int symmetry, boolean darkened) {
sett = spaceify(sett);
StringTokenizer st = new StringTokenizer(sett);
int bandColors[] = new int[st.countTokens()];
int bandThreads[] = new int[st.countTokens()]; // we leave room for symmetry
int bandCount=0;
// Store these for future reference.
this.sett = sett;
this.symmetry = symmetry;
this.darkened = darkened;
// Convert string to bands (a list of colors and color counts).
while (st.countTokens() > 1) {
int color = string2RGB(st.nextToken());
int count = java.lang.Integer.valueOf(st.nextToken()).intValue();
if (count > 0) {
bandColors[bandCount] = color;
bandThreads[bandCount] = count;
threadCount += bandThreads[bandCount++];
}
}
// Adjust the bands for symmetry.
if (symmetry != NOSYMM)
for (int i = bandCount - ((symmetry==DOUBLEPIVOT) ? 3 : 2);
i > ((symmetry==DOUBLEPIVOT) ? 0 : 1);
i--) {
bandColors[bandCount] = bandColors[i];
bandThreads[bandCount++] = bandThreads[i];
threadCount += bandThreads[i];
}
// Expand bands to threads.
int threadColors[] = new int[threadCount];
int index = 0;
for (int i=0; i HHVV
// VHHV
int pix[] = new int[threadCount * threadCount];
index = 0;
for (int y = 0; y < threadCount; y++)
for (int x = 0; x < threadCount; x++)
pix[index++] = threadColors[ (((x%4) - (y%4) + 4) %4 > 1) ? x : y ];
// Finally, make an image from the weaving.
tartan = createImage(new MemoryImageSource(threadCount, threadCount, pix, 0, threadCount));
}
// ----- Color Functions -----
// Since we work with integers, we do these functions on our own instead of using Color.*.
private int rgb(int r, int g, int b) {
if (darkened) { // this algorithm is from XTartan.
if ((r==b && b==g) || (r==g && b==0) ||(b==0 && g==0)) { // gray, yellow, red
r = (r*2)/3;
g = (g*2)/3;
b = (b*2)/3;
} else { // other colors
r /= 2;
b = (b*2)/5;
g /= 2;
}
}
return (255<<24) + (r<<16) + (g<<8) + b;
}
private int string2RGB(String s) {
// I have copied these color abbreviations from XTartan, and the RGB values
// from /usr/X11/lib/X11/rgb.txt. I think that they're too bright as is, but
// look pretty good when darkened.
if (s.equalsIgnoreCase("r")) return rgb(255,0,0); // Red
else if (s.equalsIgnoreCase("cr")) return rgb(178,34,34); // Crimson (Firebrick)
else if (s.equalsIgnoreCase("mn")) return rgb(176,48,96); // Maroon
else if (s.equalsIgnoreCase("or")) return rgb(255,165,0); // Orange
else if (s.equalsIgnoreCase("y")) return rgb(255,255,0); // Yellow
else if (s.equalsIgnoreCase("g")) return rgb(34,139,34); // Green (Forest Green)
else if (s.equalsIgnoreCase("lg")) return rgb(152,251,152);// Light Green (Pale Green)
else if (s.equalsIgnoreCase("db")) return rgb(0,0,128); // Dark Blue (Navy)
else if (s.equalsIgnoreCase("b")) return rgb(0,0,205); // Medium Blue
else if (s.equalsIgnoreCase("az")) return rgb(135,206,235);// Azure (Sky Blue)
else if (s.equalsIgnoreCase("pu")) return rgb(221,160,221);// Purple (Plum)
else if (s.equalsIgnoreCase("lil"))return rgb(218,112,214);// Lilac (Orchid)
else if (s.equalsIgnoreCase("lv")) return rgb(230,230,250);// Lavendar
else if (s.equalsIgnoreCase("ma")) return rgb(255,0,255); // Magenta
else if (s.equalsIgnoreCase("br")) return rgb(165,42,42); // Brown
else if (s.equalsIgnoreCase("w")) return rgb(255,255,255);// White
else if (s.equalsIgnoreCase("gy")) return rgb(190,190,190);// Gray
else return rgb(0,0,0); // K, BK for black
// Cy: Cyan Cor: Coral ForGr: ForestGreen SlB: Slate Blue
// Glr: Goldenrod Mar: Maroon Trq: Turquoise Wh: Wheat
}
// ----- String Utilities -----
/**
* Gets rid of garbage and extra white space, and spaces the letter and number sections.
* @param s the string
* @returns the cleaned-up string
*/
private String spaceify(String s) {
int LETTER = 1;
int NUMBER = 2;
int OTHER = 3;
int kind, lastKind=OTHER;
StringBuffer t = new StringBuffer(2 * s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".indexOf(c) != -1)
kind = LETTER;
else if ("0123456789".indexOf(c) != -1)
kind = NUMBER;
else
kind = OTHER;
if ( kind != OTHER && (kind == lastKind || lastKind == OTHER))
t.append(c);
else if (kind == OTHER) {
if (lastKind != OTHER) t.append(' ');
} else
t.append(' ').append(c);
lastKind = kind;
}
return t.toString();
}
// ----- Necessary but Boring -----
/**
* Paints the tartan.
* @param g the specified Graphics window
*/
public void paint(Graphics g) {
g.drawImage(tartan, 0, 0, null);
}
/**
* Returns the size of the rendered tartan.
*/
public Dimension preferredSize() {
return new Dimension(threadCount, threadCount);
}
/**
* Returns the String representation of the tartan.
*/
public String toString() {
return getClass().getName() +
"[sett=" + sett + ",symmetry=" + symmetry + (darkened ? ",darkened" : "") + "]";
}
}
/**
* This applet is a wrapper for the Plaid class.
* @version 1.0, 1 June 1997
* @author Thomas Insel
* @see Tartan
*/
public class Tartan extends Applet {
private Plaid myPlaid;
/**
* Initialize the applet.
*/
public void init() {
String sett = getParameter("sett");
if (sett == null)
sett = "r 16 w 16 g 16 w 16 b 16";
String symmString = getParameter("symm");
int symm = ( symmString == null ? Plaid.SINGLEPIVOT
: java.lang.Integer.valueOf(symmString).intValue());
myPlaid = new Plaid(sett, symm, getParameter("darkened") != null);
add(myPlaid);
}
/**
* Go to the about page when clicked.
* @param evt the event
* @param x the x-coordinate
* @param y the y-coordinate
* @returns true since we always handle the click
* @throws MalformedURLException but this should never really happen
*/
public boolean mouseDown(Event evt, int x, int y) {
try {
URL u = new URL("http://jaka.ece.uiuc.edu/~tinsel/Java/Tartan/about.html");
getAppletContext().showDocument(u);
} catch(MalformedURLException e) {
System.out.println("Error " + e);
System.out.println(getAppletInfo());
}
return true;
}
/**
* Returns info on this applet.
*/
public String getAppletInfo() {
return "Tartan 1.0. Copyright 1997 by Thomas Insel (tinsel@jaka.ece.uiuc.edu)";
}
/**
* Returns parameter information
*/
public String[][] getParameterInfo() {
String[][] info = {
{"sett", "string", "alternating list of colors and counts"},
{"symm", "0,1,or 2", "symmetry"},
{"darkened", "anything", "darkens colors"}
};
return info;
}
}