/*
* 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 Jun 11, 2010.
*/
package com.scriptographer.ai;
/**
* CurveLocation objects describe a location on {@Curve} objects, as
* defined by the curve {@link #getParameter()}, a value between {@code 0}
* (beginning of the curve) and {@code 1} (end of the curve). If the curve is
* part of a {@link Path} item, its {@link #getIndex()} inside the
* {@link Path#getCurves()} list is also provided.
*
* The class is in use in many places, such as {@link Path#getLocation(double)},
* {@link Path#getPoint(double)}, {@link Path#split(CurveLocation)},
* {@link PathItem#getIntersections(PathItem)}, etc.
*
* @author lehni
*/
public class CurveLocation {
private Curve curve;
private double parameter;
private Point point;
private Segment segment;
protected CurveLocation() {
}
protected CurveLocation(Curve curve, double parameter, Point point) {
init(curve, parameter, point);
}
public CurveLocation(Curve curve, double parameter) {
init(curve, parameter, null);
}
public CurveLocation(Path path, int index, double parameter) {
init(path.getCurves().get(index), parameter, null);
}
protected void init(Curve curve, double parameter, Point point) {
this.curve = curve;
this.parameter = parameter;
this.point = point;
}
/**
* The segment of the curve which is closer to the described location.
*/
public Segment getSegment() {
if (segment == null) {
// Determine the segment closest to the hit point
Double parameter = getParameter();
if (parameter == null) {
return null;
} else if (parameter == 0) {
segment = curve.getSegment1();
} else if (parameter == 1) {
segment = curve.getSegment2();
} else {
// Determine the closest segment by comparing curve lengths
segment = curve.getLength(0, parameter)
< curve.getLength(parameter, 1)
? curve.getSegment1()
: curve.getSegment2();
}
}
return segment;
}
/**
* The curve by which the location is defined.
*/
public Curve getCurve() {
return curve;
}
/**
* The item this curve belongs to, if any.
*/
public Item getItem() {
return curve != null ? curve.getPath() : null;
}
/**
* The index of the curve within the {@link Path#getCurves()} list, if the
* curve is part of a {@link Path} item.
*/
public Integer getIndex() {
return curve != null ? curve.getIndex() : null;
}
/**
* The length of the path from its beginning up to the location described
* by this object.
*/
public Double getOffset() {
if (curve != null) {
Path path = curve.getPath();
if (path != null)
return path.getOffset(this);
}
return null;
}
/**
* @deprecated
*/
public Double getLength() {
return getOffset();
}
/**
* The length of the curve from its beginning up to the location described
* by this object.
*/
public Double getCurveOffset() {
if (curve != null) {
Double parameter = getParameter();
if (parameter != null)
return curve.getLength(0, parameter);
}
return null;
}
/**
* @deprecated
*/
public Double getCurveLength() {
return getCurveOffset();
}
/**
* The curve parameter, as used by various bezier curve calculations. It is
* value between {@code 0} (beginning of the curve) and {@code 1} (end of
* the curve).
*/
public Double getParameter() {
if (parameter == -1 && point != null && curve != null)
parameter = curve.getParameter(point);
return parameter != -1 ? parameter : null;
}
/**
* The point which is defined by the {@link #getCurve()} and
* {@link #getParameter()}.
*/
public Point getPoint() {
if (point == null && curve != null) {
Double parameter = getParameter();
if (parameter != null)
point = curve.getPoint(parameter);
}
return point;
}
/**
* The tangential vector to the {@link #getCurve()} at the given location.
*/
public Point getTangent() {
Double parameter = getParameter();
return parameter != null && curve != null
? curve.getTangent(parameter)
: null;
}
/**
* The normal vector to the {@link #getCurve()} at the given location.
*/
public Point getNormal() {
Double parameter = getParameter();
return parameter != null && curve != null
? curve.getNormal(parameter)
: null;
}
public double getCurvature() {
Double parameter = getParameter();
return parameter != null && curve != null
? curve.getCurvature(parameter)
: null;
}
public String toString() {
StringBuffer buf = new StringBuffer(32);
Point point = getPoint();
if (point != null)
buf.append(", point: ").append(getPoint());
Integer index = getIndex();
if (index != null)
buf.append(", index: ").append(index);
Double parameter = getParameter();
if (parameter != null)
buf.append(", parameter: ").append(parameter);
// Replace the first ',' with a '{', no matter which one came first.
buf.setCharAt(0, '{');
buf.append(" }");
return buf.toString();
}
public boolean equals(Object object) {
if (object instanceof CurveLocation) {
CurveLocation loc = (CurveLocation) object;
return getPoint().equals(loc.getPoint());
}
return false;
}
}