net.paulhertz.aifile
Class LayerComponent

java.lang.Object
  extended by net.paulhertz.aifile.DisplayComponent
      extended by net.paulhertz.aifile.LayerComponent
All Implemented Interfaces:
Visitable

public class LayerComponent
extends DisplayComponent

Instantiates a Layer component, immediately below the document (root) level. Layers can only be created as children of a DocumentComponent. Attempting to insert them elsewhere will lead to an UnsupportedOperationException. At the moment, we set the layer to be visible, previewed, enabled, and printing and not dimmed or containing multi-layer masks. Only visibility can be changed, and only for drawing, at the moment. The colorIndex can be a number from 0 to 26, at the moment there is no provision for custom colors. The layer name can be anything you want.

+Example
/**
 * January 29, 2012 3:03:31 PM CST
 * Sample code for IgnoCodeLib 0.3 Processing library by Paul Hertz
 * Updated June 25, 2013 for IgonoCodeLib 0.3 release.
 * The writeNoTransform call is only available in 0.3 and the packages have been renamed
 * from com.ignotus to net.paulhertz in the import section. Calls to component constructors
 * no longer require you to pass in a reference to the host PApplet, if you initialize
 * the library correctly as in "igno = new IgnoCodeLib(this);"
 * Shows how to create a document tree with layers, groups, and shapes and use it to draw 
 * to the screen, perform a global transform, and export to file. 
 */

import java.util.*;
import java.io.*;  
import java.awt.geom.Point2D;
import net.paulhertz.aifile.*;   // library that handles Adobe Illustrator document structure and export
import net.paulhertz.geom.*;     // library for geometric transforms and matrices

/** list of colors */
ArrayList farben;
/** a geometric transform */
Matrix3 aiTransform;
String fileName = "documentExport.ai";
/** document component, root of the document structure */
DocumentComponent doc;
/** IgnoCodeLib library */
IgnoCodeLib igno;


public void setup() {
  size(480,720);
  background(127);
  smooth();
  // Set up the library, which will store a reference to the host PApplet 
  // for other classes in the library to use.
  igno = new IgnoCodeLib(this);
  farben = new ArrayList();
  setupTransform();
  // we'll create the document up front and use it for drawing and saving
  createDocument();
  println("type 's' to output file");
}


public void draw() {
  // the document knows how to draw itself--so do layers and groups and shapes, but if they are 
  // part of the document, we just have to tell the document to draw.
  doc.draw();
}


/**
 * Processing and Illustrator use different coordinate systems. We can move from one to 
 * the other by applying a geometric transform to our graphics before outputting to Illustrator.
 * The DocumentComponent class now performs the transform automatically when you call write, so 
 * this method is here for informational purposes. 
 * See the SaveAI() method for more information.
 * 2-D geometric transforms can be captured by a matrix with three rows and three columns.
 * The class net.paulhertz.geom.Matrix3 handles transforms with such matrices.
 * In its initial state, a Matrix3 is the "identity matrix," to which we add various transforms.
 * The matrix transforms 2D geometry through the operation of matrix multiplication. The
 * nuts and bolts need not concern you: the essential thing to understand is that you can 
 * add a series of geometric transforms to the matrix and then execute them all at once.
 * The matrix is also referred to as the CTM or Current Transoformation Matrix.
 * This transform is also available directly from the document through the getAITransform() method.
 */
public void setupTransform() {
  // start with the identity matrix
  aiTransform = new Matrix3();
  // add a horizontal reflection around x = 0
  aiTransform.scaleCTM(1.0, -1.0);
  // and translate by "height" distance on the y-axis
  aiTransform.translateCTM(0, height);
}

/**
 * Creates a document tree with layers, groups, and shapes 
 * Note that the Document, Layer, and Group components need to be 
 * initialized with "this" (the PApplet that runs the show) as the first argument.
 */
public void createDocument() {
  float x, y, radius, h, w;
  int sides;
  color c;
  // initialize an integer array with values constrained to 0..255
  int[] channelValues = {34, 55, 89, 144, 233};
  float minX = width * 0.125;
  float maxX = width * 0.875;
  float minY = height * 0.125;
  float maxY = height * 0.875;
  // create a document
  doc = new DocumentComponent("Layers and Groups");
  // by setting verbose to true, we get some feedback as we add components
  doc.setVerbose(true);
  // create and add a layer
  LayerComponent bg = new LayerComponent("background");
  doc.add(bg);
  // add some geometry to the layer
  bg.add(bgRect());
  // create another layer and add it to the document
  LayerComponent polygons = new LayerComponent("Polygons");
  doc.add(polygons);
  // create some geometry and add it to the polygons layer
  ArrayList bezzies = new ArrayList();
  for (int i = 0; i < 10; i++) {
    x = random(minX, maxX);
    y = random(minY, maxY);
    radius = random(2, 48);
    sides = int(random(3, 18));
    BezShape bez = BezRegularPoly.makeCenterRadiusSides(x, y, radius, sides);
    c = Palette.randColor(channelValues);
    farben.add(c);
    bez.setFillColor(c);
    bez.setNoStroke();
    bezzies.add(bez);
    polygons.add(bez);
  }
  // create a group and add it to the polygons layer
  GroupComponent boxes = new GroupComponent(this);
  polygons.add(boxes);
  // step through the polygons we created and put a bounding box around each one
  // add the bounding boxes to the group
  for (BezShape b : bezzies) {
    float[] bounds = b.bounds(this);
    float left = bounds[0];
    float top = bounds[1];
    float right = bounds[2];
    float bottom = bounds[3];
    color s = b.fillColor();
    BezShape br = bezRect(left, top, right, bottom, color(0), s);
    br.setNoFill();
    br.setWeight(2);
    boxes.add(br);
  }
  // create a new layer and add it to the document 
  LayerComponent ellipses = new LayerComponent("Ellipses");
  doc.add(ellipses);
  // add some geometry to the layer
  for (int i = 0; i < 10; i++) {
    x = random(minX, maxX);
    y = random(minY, maxY);
    w = random(16, 96);
    h = random(16, 96);
    sides = int(random(4, 7));
    BezShape bez = BezEllipse.makeCenterWidthHeightSectors(x, y, w, h, sides);
    c = Palette.randColor(channelValues);
    farben.add(c);
    bez.setFillColor(c);
    bez.setNoStroke();
    ellipses.add(bez);
  }
}


void keyPressed() {
  if (key == 's') {
    saveAI(fileName, doc, farben);
  }  
}


/**
 * Creates a rectangle from four points, with fill and stroke colors
 */
public BezShape bezRect(float left, float top, float right, float bottom, color f, color s) {
  // instatiate a BezShape with a reference to our PApplet
  //  and the x and y coordinates of its starting vertex.
  BezShape r = new BezShape(left, top);
  r.setFillColor(f);
  r.setStrokeColor(s);
  r.setWeight(3.0);
  r.append(right, top);
  r.append(right, bottom);
  r.append(left, bottom);
  r.append(left, top);
  return r;
}


public BezShape bgRect() {
  color f = color(233, 220, 254);
  color s = color(21, 34, 55);
  return bezRect(0, height, width, 0, f, s);
}


/**
 * saves shapes to an Adobe Illustrator file
 */
public void saveAI(String aiFilename, DocumentComponent doc, ArrayList colors) {
  println("saving Adobe Illustrator file " + aiFilename + "...");
  PrintWriter output = createWriter(aiFilename);
  Palette pal = doc.getPalette();
  pal.addBlackWhiteGray();
  pal.addColors(colors);
  doc.setCreator("Ignotus");
  doc.setOrg("IgnoStudio");
  doc.setWidth(width);
  doc.setHeight(height);
  // the transform we created reflects everything around a horizontal line
  // it's a "symmetrical" transform: doing it a second time undoes it.
  // we do it once to flip graphics into Adobe Illustrator's coordinate system, 
  // and once more to restore Processing's coordinate system.
  // the new version of IgnoCodeLib (0.2) provides a single method, writeWithAITransform()
  // that creates and applies the Processing to Illustrator coordinate system transform.
  // "doc.writeWithAITransform(output)" could replace the next three lines, and you would 
  // not need to generate aiTransform.
  // As of IgnoCodeLib 0.3, write(output) performs the transform for you. The writeWithAITransform
  // method is superfluous and will be deprecated in the future. Use writeNoTransform if you
  // don't want the default transform applied.
  /*
  // the old way...or what to do if you want your own transform applied (however, it modifies 
  // the document geometry, so be prepared to run an inverse transform). 
  doc.transform(aiTransform);
  doc.writeNoTransform(output);
  doc.transform(aiTransform);
  */
  doc.write(output); 
}




Constructor Summary
LayerComponent()
          PApplet used for calls to the Processing environment is obtained from IgnoCodeLib, which must be correctly initialized in setup.
LayerComponent(PApplet parent)
           
LayerComponent(PApplet parent, String name)
           
LayerComponent(PApplet parent, String name, int colorIndex)
           
LayerComponent(String name)
          PApplet used for calls to the Processing environment is obtained from IgnoCodeLib, which must be correctly initialized in setup.
LayerComponent(String name, int colorIndex)
          PApplet used for calls to the Processing environment is obtained from IgnoCodeLib, which must be correctly initialized in setup.
 
Method Summary
 void accept(ComponentVisitor visitor)
          Accepts a ComponentVisitor that traverses a document structure tree.
 void accept(ComponentVisitor visitor, boolean order)
          Accepts a ComponentVisitor that traverses a document structure tree in preorder or postorder.
 void add(ArrayList<? extends DisplayComponent> comps)
          Adds all components in a list to this document
 void add(DisplayComponent component)
          Adds a component to children() of this component.
 void draw()
          Draws geometry or text to the Processing window.
 void draw(PGraphics pg)
          Draws a component to a supplied PGraphics.
 int getColorIndex()
          Returns the color index.
 String getName()
          Returns the namd of this layer.
 boolean isTerminal()
           
 void setColorIndex(int colorIndex)
          Sets the color index, used in Illustrator's Layers palette.
 void setName(String name)
          Sets the name of this layer.
 void transform(Matrix3 matx)
          Transforms geometry of shapes and location of text using the supplied matrix.
 void write(PrintWriter pw)
          Writes an Adobe Illustrator 7.0 file format encoding structure, geometry and text.
 
Methods inherited from class net.paulhertz.aifile.DisplayComponent
children, get, hide, id, isLocked, isVisible, iterator, parentComponent, remove, setLocked, setParentComponent, setVisible, show
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

LayerComponent

public LayerComponent(String name,
                      int colorIndex)
PApplet used for calls to the Processing environment is obtained from IgnoCodeLib, which must be correctly initialized in setup. If IgnoCodeLib does not have a reference to a PApplet, it throws a NullPointerException.

Parameters:
name - Name of this layer, shown in the AI Layers palette
colorIndex - number from 0 to 26, color to use for layer selections and Layers palette in AI

LayerComponent

public LayerComponent(PApplet parent,
                      String name,
                      int colorIndex)
Parameters:
parent - PApplet used for calls to the Processing environment
name - Name of this layer, shown in the AI Layers palette
colorIndex - number from 0 to 26, color to use for layer selections and Layers palette in AI

LayerComponent

public LayerComponent(PApplet parent)
Parameters:
parent - PApplet used for calls to the Processing environment

LayerComponent

public LayerComponent()
PApplet used for calls to the Processing environment is obtained from IgnoCodeLib, which must be correctly initialized in setup. If IgnoCodeLib does not have a reference to a PApplet, it throws a NullPointerException.


LayerComponent

public LayerComponent(PApplet parent,
                      String name)
Parameters:
parent - PApplet used for calls to the Processing environment
name - Name of this layer, shown in the AI Layers palette

LayerComponent

public LayerComponent(String name)
PApplet used for calls to the Processing environment is obtained from IgnoCodeLib, which must be correctly initialized in setup. If IgnoCodeLib does not have a reference to a PApplet, it throws a NullPointerException.

Parameters:
name - Name of this layer, shown in the AI Layers palette
Method Detail

getName

public String getName()
Returns the namd of this layer.

Returns:
the layer name

setName

public void setName(String name)
Sets the name of this layer.

Parameters:
name - the name of the layer to set

getColorIndex

public int getColorIndex()
Returns the color index.

Returns:
the colorIndex

setColorIndex

public void setColorIndex(int colorIndex)
Sets the color index, used in Illustrator's Layers palette.

Parameters:
colorIndex - the colorIndex to set, should be a number from 0 to 26. Light Blue = 0 Yellow = 4 Black = 8 Tan = 12 Dark Blue = 16 Olive Green = 20 Ochre = 24 Red = 1, Magenta = 5, Orange = 9, Brown = 13, Pink = 17, Peach = 21, Purple = 25, Green = 2, Cyan = 6, Dark Green = 10, Violet = 14, Lavender = 18, Burgundy = 22, Light Gray = 26, Blue = 3, Gray = 7, Teal = 11, Gold = 15, Brick Red = 19, Grass Green = 23

add

public void add(DisplayComponent component)
Adds a component to children() of this component. Overrides DisplayComponent. Throws an UnsupportedOperationException if an attempt is made to add a DocumentComponent or a LayerComponent.

Specified by:
add in class DisplayComponent
Parameters:
component - DisplayComponent to add to this component's children

add

public void add(ArrayList<? extends DisplayComponent> comps)
Adds all components in a list to this document

Specified by:
add in class DisplayComponent
Parameters:
comps - an ArrayList of DisplayComponents

draw

public void draw()
Description copied from class: DisplayComponent
Draws geometry or text to the Processing window. Component must be flagged as visible (the default).

Specified by:
draw in class DisplayComponent

draw

public void draw(PGraphics pg)
Description copied from class: DisplayComponent
Draws a component to a supplied PGraphics. Except for the document component, a component must be visible (the default) to draw. Structural components simply iterate over their children. Graphic components should call beginShape and endShape on their own. It's up to the user to call beginDraw() and endDraw() on the PGraphics instance.

Specified by:
draw in class DisplayComponent
Parameters:
pg - a PGraphics instance

isTerminal

public boolean isTerminal()
Specified by:
isTerminal in class DisplayComponent
Returns:
true if this is a terminal (leaf) component, false if it is a composite component (i.e. a component that can add sub-components to a children array)

write

public void write(PrintWriter pw)
Description copied from class: DisplayComponent
Writes an Adobe Illustrator 7.0 file format encoding structure, geometry and text.

Specified by:
write in class DisplayComponent
Parameters:
pw - a PrintWriter for file output.

transform

public void transform(Matrix3 matx)
Description copied from class: DisplayComponent
Transforms geometry of shapes and location of text using the supplied matrix.

Specified by:
transform in class DisplayComponent
Parameters:
matx - a Matrix3 that encapsulates an affine geometric transform.

accept

public void accept(ComponentVisitor visitor)
Description copied from interface: Visitable
Accepts a ComponentVisitor that traverses a document structure tree.

When called from an object that implements the Visitable interface:

  1. each visited object passes a reference to itself back to the visitor
  2. each visited object calls accept( visitor ) on all its children

The reference is passed back to the visitor through a method of the form visitor.visit<ComponentClassName>( this ); See ComponentVisitor

The order of steps 1 and 2 determines if traversal of the composite structure is preorder or postorder. As shown above, it's preorder. Depending on what you want to do, one traversal may be better suited than the other. Preorder visits parents first, postorder visits children first.

Parameters:
visitor - a ComponentVisitor

accept

public void accept(ComponentVisitor visitor,
                   boolean order)
Description copied from interface: Visitable
Accepts a ComponentVisitor that traverses a document structure tree in preorder or postorder.

Parameters:
visitor - a ComponentVisitor
order - boolean to determine if traversal is preorder or postorder accept( visitor ) should implement the default order of traversal, accept( visitor, <false> ) should implement the other order.


Processing library IgnoCodeLib by Paul Hertz. (C) 2013