/*
* Scriptographer
*
* This file is part of Scriptographer, a Scripting Plugin for Adobe Illustrator
* http://scriptographer.org/
*
* Copyright (c) 2002-2010, Juerg Lehni
* http://scratchdisk.com/
*
* All rights reserved. See LICENSE file for details.
*
* File created on 26.07.2005.
*/
package com.scriptographer.ai;
import java.awt.geom.GeneralPath;
import com.scratchdisk.list.ExtendedArrayList;
import com.scratchdisk.list.List;
import com.scratchdisk.list.Lists;
import com.scratchdisk.list.ReadOnlyList;
import com.scriptographer.ScriptographerException;
/**
* A compound path contains two or more paths, holes are drawn where the paths
* overlap. All the paths in a compound path take on the style of the backmost
* path.
*
* @author lehni
*/
public class CompoundPath extends PathItem {
/**
* Wraps an AIArtHandle in a Path object
*/
protected CompoundPath(int handle, int docHandle, boolean created) {
super(handle, docHandle, created);
}
/**
* Creates a compound path item.
*/
public CompoundPath() {
super(TYPE_COMPOUNDPATH);
}
public CompoundPath(ReadOnlyList<? extends Item> children) {
this();
for (Item item : children)
this.appendBottom(item);
}
public CompoundPath(Item[] children) {
this(Lists.asList(children));
}
/**
* Specifies whether the compound path is used as a guide.
* @return {@true if the compound path is used as a guide}
*/
public boolean isGuide() {
Item child = getFirstChild();
return child != null && ((Path) child).isGuide();
}
public void setGuide(boolean guide) {
for (Item item : getChildren())
((Path) item).setGuide(guide);
}
/*
* Setting selected attribute on Groups and CompoundPaths only works when
* also explicitly applying the same attributes to all the children, even
* when using setFully selected. So override both here.
*/
public void setSelected(boolean selected) {
Item child = getFirstChild();
while (child != null) {
child.setSelected(selected);
child = child.getNextSibling();
}
super.setSelected(selected);
}
public void setFullySelected(boolean selected) {
Item child = getFirstChild();
while (child != null) {
child.setFullySelected(selected);
child = child.getNextSibling();
}
super.setFullySelected(selected);
}
private Path getCurrentPath() {
Path current = (Path) getFirstChild();
if (current == null)
throw new ScriptographerException("Use a moveTo() command first");
return current;
}
@Override
public void moveTo(double x, double y) {
// moveTo always creates a new path:
Path path = new Path();
appendTop(path);
path.moveTo(x, y);
}
@Override
public void lineTo(double x, double y) {
getCurrentPath().lineTo(x, y);
}
@Override
public void cubicCurveTo(double c1x, double c1y, double c2x, double c2y,
double x, double y) {
getCurrentPath().cubicCurveTo(c1x, c1y, c2x, c2y, x, y);
}
@Override
public void quadraticCurveTo(double cx, double cy, double x, double y) {
getCurrentPath().quadraticCurveTo(cx, cy, x, y);
}
@Override
public void curveTo(double throughX, double throughY,
double toX, double toY, double parameter) {
getCurrentPath().curveTo(throughX, throughY, toX, toY, parameter);
}
@Override
public void arcTo(double x, double y, boolean clockwise) {
getCurrentPath().arcTo(x, y, clockwise);
}
@Override
public void arcTo(double throughX, double throughY,
double toX, double toY) {
getCurrentPath().arcTo(throughX, throughY, toX, toY);
}
public void moveBy(double x, double y) {
Point current = getCurrentPath().getSegments().getCurrentSegment().point;
moveTo(current.add(x, y));
}
public void moveBy(Point pt) {
if (pt == null) moveTo(0, 0);
else moveBy(pt.x, pt.y);
}
@Override
public void lineBy(double x, double y) {
getCurrentPath().lineBy(x, y);
}
@Override
public void curveBy(double throughX, double throughY,
double toX, double toY, double parameter) {
getCurrentPath().curveBy(throughX, throughY, toX, toY, parameter);
}
@Override
public void arcBy(double x, double y, boolean clockwise) {
getCurrentPath().arcBy(x, y, clockwise);
}
@Override
public void arcBy(double throughX, double throughY, double toX, double toY) {
getCurrentPath().arcBy(throughX, throughY, toX, toY);
}
@Override
public void closePath() {
Path prevPath = getCurrentPath();
prevPath.setClosed(true);
}
/**
* Converts to a Java2D shape.
*
* @jshide
*/
@Override
public GeneralPath toShape() {
Path path = (Path) getFirstChild();
GeneralPath shape = path.toShape();
while ((path = (Path) path.getNextSibling()) != null) {
shape.append(path.toShape(), false);
}
return shape;
}
/**
* If this is a compound path with only one path inside,
* the path is moved outside and the compound path is erased.
* Otherwise, the compound path is returned unmodified.
*
* @return the simplified compound path.
*/
public PathItem simplify() {
Path path = (Path) getFirstChild();
if (path.getNextSibling() == null) {
path.moveAbove(this);
this.remove();
return path;
}
return this;
}
protected List<Curve> getAllCurves() {
Item child = getFirstChild();
ExtendedArrayList<Curve> curves = new ExtendedArrayList<Curve>();
while (child != null) {
curves.addAll(((Path )child).getCurves());
child = child.getNextSibling();
}
return curves;
}
}