/**
* March 14, 2012 3:35:47 PM CDT
* Sample code for IgnoCodeLib Processing library by Paul Hertz
* for IgnoCodeLib version 0.2.x and above
* January 29, 2012 3:35:28 PM CST
* Shows how to create multi-segment lines and curves.
* Also: hide and show layers, set opacity on lists of shapes,
* use document as a display list in the draw() method.
*/
import com.ignotus.aifile.*;
import java.io.*;
import java.util.ArrayList;
/** list of straight line shapes */
public ArrayList multiLines;
/** list of curved line shapes */
public ArrayList multiCurves;
/** layers we put the shapes into */
public LayerComponent zigzagLayer;
public LayerComponent curvyLayer;
/** the document, top of the display list hierarchy */
public DocumentComponent document;
/** random number utility */
public com.ignotus.util.RandUtil rand;
/** storage for colors (as Integers) */
public ArrayList farben;
/** grid spacing */
int spacer = 40;
/** number of horizontal grid cells */
int horizontalGrid = 20;
/** number of vertical grid cells */
int verticalGrid = 16;
/** color channel values in range 0..255 to use for our curves and lines */
int[] zigzagChannelValues = {34, 47, 55, 76, 89};
int[] curvyChannelValues = {89, 123, 144, 199, 233};
public void setup() {
size(spacer * horizontalGrid, spacer * verticalGrid);
smooth();
multiLines = new ArrayList();
multiCurves = new ArrayList();
farben = new ArrayList();
rand = new com.ignotus.util.RandUtil();
createMultiLines();
createMultiCurves();
// create the document up front because
// we're going to use its display list functionality
createDocument();
printHelp();
}
public void draw() {
background(233, 233, 246);
document.draw();
}
public void printHelp() {
println("\nType 's' to save file");
println("Type 'x' to change colors");
println("Type '1' or '2' to show and hide layers");
println("Press '3,' '4,' '5,' or '6' to fade lines in or out");
println("Type 'h' to show this help message");x
}
public void keyReleased() {
if (key == 's' || key == 'S') {
// save file, put shapes in two layers
String filename = "Multi.ai";
saveAI(filename, farben, document);
println("saved" + "");
}
else if (key == 'x' || key == 'X') {
// make colors, multiCurves and multiLines again
farben.clear();
changeStroke(multiCurves, curvyChannelValues, 4, 12);
changeStroke(multiLines, zigzagChannelValues, 2, 8);
}
else if (key == '1') {
// hide or show curvyLayer
if (curvyLayer.isVisible()) {
curvyLayer.hide();
}
else {
curvyLayer.show();
}
}
else if (key == '2') {
// hide or show zigzagLayer
if (zigzagLayer.isVisible()) {
zigzagLayer.hide();
}
else {
zigzagLayer.show();
}
}
else if (key == 'h' || key == 'H') {
printHelp();
}
else {
;
}
}
public void keyPressed() {
// key presses are used to fade layers in and out by steps
// holding a key down repeats the fade action
int fadeStep = 8;
if (key == '3') {
fadeOut(multiCurves, fadeStep);
}
else if (key == '4') {
fadeIn(multiCurves, fadeStep);
}
else if (key == '5') {
fadeOut(multiLines, fadeStep);
}
else if (key == '6') {
fadeIn(multiLines, fadeStep);
}
}
/**
* Create some multi-segment lines, save them in {@code multiLines}.
*/
private void createMultiLines() {
int numberOfPoints = horizontalGrid;
float[] gridCoords = new float[numberOfPoints * 2];
int j = 0;
for (int i = 0; i < numberOfPoints; i++) {
gridCoords[j++] = i * spacer + spacer * 0.5f;
gridCoords[j++] = (i % 2) == 1 ? spacer * 0.5f : spacer * 1.5f;
}
int count = 0;
while (count < verticalGrid - 1) {
multiLines.add(ziggyLine(gridCoords));
for (int i = 0; i < gridCoords.length;) {
i++; // step over x-coord
float y = gridCoords[i] + spacer; // y = spacer + y-coord
gridCoords[i++] = y; // set y-coord
}
count++;
}
}
/**
* @param coords coordinate points for a multi-segment line
* @return a BezMultiLine instance created from coords
*/
private BezMultiLine ziggyLine(float[]coords) {
// int[] zigzagChannelValues = {34, 47, 55, 76, 89};
int c = Palette.randColor(zigzagChannelValues);
farben.add(c);
stroke(c);
strokeWeight(rand.randomInRange(2, 8));
BezMultiLine mul = BezMultiLine.makeMultiLine(this, coords);
return mul;
}
/**
* create some multi-segment curves, save them in {@code multiCurves}
*/
public void createMultiCurves() {
// bias determines the amount of curvature
float bias = 0.5f;
int numberOfPoints = horizontalGrid;
float[] gridCoords = new float[numberOfPoints * 2];
int j = 0;
// fill a list with grid points
for (int i = 0; i < numberOfPoints; i++) {
gridCoords[j++] = i * spacer + spacer * 0.5f;
gridCoords[j++] = (i % 2) == 1 ? spacer * 1.5f : spacer * 0.5f;
}
// Set aside storage for curve vertices. the first vertex uses
// 2 coordinates for one anchor point, subsequent vertices require 6
// for two control points and one anchor point
float[] curveCoords = new float[2 + (numberOfPoints -1) * 6];
float x = gridCoords[0];
float y = gridCoords[1];
curveCoords[0] = x;
curveCoords[1] = y;
j = 2;
float offset = spacer * bias;
// create the first curvy line
for (int i = 2; i < gridCoords.length;) {
// first control point, offset from most recent anchor point
curveCoords[j++] = x + offset;
curveCoords[j++] = y;
// set x and y to coordinates of the next anchor point
x = gridCoords[i++];
y = gridCoords[i++];
// second control point, offset from next anchor point
curveCoords[j++] = x - offset;
curveCoords[j++] = y;
// store next anchor point
curveCoords[j++] = x;
curveCoords[j++] = y;
}
multiCurves.add(curvyLine(curveCoords));
int count = 1;
// create the rest of the curvy lines
while (count < verticalGrid - 1) {
for (int i = 0; i < gridCoords.length;) {
i++; // step over x-coord
y = gridCoords[i] + spacer; // y = spacer + y-coord
gridCoords[i++] = y; // set y-coord
}
x = gridCoords[0];
y = gridCoords[1];
curveCoords[0] = x;
curveCoords[1] = y;
j = 2;
for (int i = 2; i < gridCoords.length;) {
// first control point
curveCoords[j++] = x + offset;
curveCoords[j++] = y;
x = gridCoords[i++];
y = gridCoords[i++];
// second control point
curveCoords[j++] = x - offset;
curveCoords[j++] = y;
// anchor point
curveCoords[j++] = x;
curveCoords[j++] = y;
}
multiCurves.add(curvyLine(curveCoords));
count++;
}
}
/**
* @param coords coordinate points for a multi-segment curve
* @return a BezMultiLine instance created from coords
*/
private BezMultiCurve curvyLine(float[]coords) {
// int[] curvyChannelValues = {89, 123, 144, 199, 233};
int c = Palette.randColor(curvyChannelValues);
farben.add(c);
stroke(c);
strokeWeight(rand.randomInRange(4, 12));
BezMultiCurve mul = BezMultiCurve.makeMultiCurve(this, coords);
return mul;
}
public void createDocument() {
document = new DocumentComponent(this, "MultiCurves and MultiLines");
// get lots of feedback as we save
document.setVerbose(true);
document.setCreator("Ignotus");
document.setOrg("IgnoStudio");
document.setWidth(width);
document.setHeight(height);
curvyLayer = new LayerComponent(this, "Curvy");
curvyLayer.add(multiCurves);
document.add(curvyLayer);
zigzagLayer = new LayerComponent(this, "Zigzag");
zigzagLayer.add(multiLines);
document.add(zigzagLayer);
}
/**
* @param shapes list of BezShape
* @param step amount to fade
* @return true when fade out is complete (opacity == 0)
*/
public boolean fadeOut(ArrayList extends BezShape> shapes, int step) {
int opacity = shapes.get(0).strokeOpacity();
opacity = opacity < step ? 0 : opacity - step;
//println("fade out opacity = " + opacity);
boolean isFadedOut = (opacity == 0);
for (BezShape sh : shapes) {
sh.setStrokeOpacity(opacity);
}
return isFadedOut;
}
/**
* @param shapes list of BezShape
* @param step amount to fade
* @return true when fade in is complete (opacity == 255)
*/
public boolean fadeIn(ArrayList extends BezShape> shapes, int step) {
int opacity = shapes.get(0).strokeOpacity();
opacity = opacity + step > 255 ? 255 : opacity + step;
//println("fade in opacity = " + opacity);
boolean isFadedIn = (opacity == 255);
for (BezShape sh : shapes) {
sh.setStrokeOpacity(opacity);
}
return isFadedIn;
}
/**
* @param shapes list of shapes to change
* @param channelValues possible values for color channels
* @param weightLo low end of range for stroke weight
* @param weightHi high end of range for stroke weight
*/
public void changeStroke(ArrayList extends BezShape> shapes, int[] channelValues, float weightLo, float weightHi) {
for (BezShape sh : shapes) {
int c = Palette.randColor(channelValues);
farben.add(c);
sh.setStrokeColor(c);
sh.setWeight(rand.randomInRange(weightLo, weightHi));
}
}
/**
* Saves shapes to an Adobe Illustrator file.
* @param aiFilename name of the file, should end with ".ai"
* @param paletteColors a list of Integers (colors)
* @param document the DocumentComponent to save
*/
public void saveAI(String aiFilename, ArrayList paletteColors, DocumentComponent document) {
// tell BezShape to use opacity values when exporting to AI
AIFileWriter.setUseTransparency(true);
println("saving Adobe Illustrator file " + aiFilename + "...");
PrintWriter output = createWriter(aiFilename);
Palette pal = document.getPalette();
// include black and white in the palette
pal.addBlackWhiteGray();
// add our colors
pal.addColors(paletteColors);
// write the file, transforming geometry from the Processing coordinate system
// into the Adobe Illustrator coordinate system
document.writeWithAITransform(output);
}