/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* (C) Copyright IBM Corp. 2005, All Rights Reserved.
*/
//
// This is the 'simple' mapping implementation. It does things the most
// straightforward way even if that is a bit slow. It won't
// handle complex paths efficiently, and doesn't handle closed paths.
//
//
// Convenience APIs
//
return pt;
}
return pt;
}
pt.setLocation(x, y);
}
pt.setLocation(a, o);
}
//
// extra utility APIs
//
public abstract double start();
public abstract double end();
public abstract double length();
//
// debugging flags
//
private static final boolean LOGMAP = false;
/**
* Indicate how positions past the start and limit of the
* path are treated. PINNED adjusts these positions so
* as to be within start and limit. EXTENDED ignores the
* start and limit and effectively extends the first and
* last segments of the path 'infinitely'. CLOSED wraps
* positions around the ends of the path.
*/
public static enum EndType {
};
//
// Top level construction.
//
/**
* Return a path representing the path from the origin through the points in order.
*/
throw new IllegalArgumentException("odd number of points not allowed");
}
}
/**
* Use to build a SegmentPath. This takes the data and preanalyzes it for
* information that the SegmentPath needs, then constructs a SegmentPath
* from that. Mainly, this lets SegmentPath cache the lengths along
* the path to each line segment, and so avoid calculating them over and over.
*/
public static final class SegmentPathBuilder {
private double[] data;
private int w;
private double px;
private double py;
private double a;
private boolean pconnect;
/**
* Construct a SegmentPathBuilder.
*/
public SegmentPathBuilder() {
}
/**
* Reset the builder for a new path. Datalen is a hint of how many
* points will be in the path, and the working buffer will be sized
* to accomodate at least this number of points. If datalen is zero,
* the working buffer is freed (it will be allocated on first use).
*/
} else if (datalen == 0) {
}
w = 0;
pconnect = false;
}
/**
* Automatically build from a list of points represented by pairs of
* doubles. Initial advance is zero.
*/
}
}
/**
* Move to a new point. If there is no data, this will become the
* first point. If there is data, and the previous call was a lineTo, this
* point is checked against the previous point, and if different, this
* starts a new segment at the same advance as the end of the last
* segment. If there is data, and the previous call was a moveTo, this
* replaces the point used for that previous call.
*
* Calling this is optional, lineTo will suffice and the initial point
* will be set to 0, 0.
*/
public void moveTo(double x, double y) {
nextPoint(x, y, false);
}
/**
* Connect to a new point. If there is no data, the previous point
* is presumed to be 0, 0. This point is checked against
* the previous point, and if different, this point is added to
* the path and the advance extended. If this point is the same as the
* previous point, the path remains unchanged.
*/
public void lineTo(double x, double y) {
nextPoint(x, y, true);
}
/**
* Add a new point, and increment advance if connect is true.
*
* This automatically rejects duplicate points and multiple disconnected points.
*/
// if zero length move or line, ignore
return;
}
if (w == 0) { // this is the first point, make sure we have space
data = new double[6];
}
if (connect) {
w = 3; // default first point to 0, 0
}
}
// if multiple disconnected move, just update position, leave advance alone
return;
}
// grow data to deal with new point
double[] t = new double[w * 2];
data = t;
}
if (connect) {
}
// update data
data[w++] = x;
data[w++] = y;
data[w++] = a;
// update state
px = x;
py = y;
}
}
/**
* Complete building a SegmentPath. Once this is called, the builder is restored
* to its initial state and information about the previous path is released. The
* end type indicates whether to treat the path as closed, extended, or pinned.
*/
return null;
}
} else {
double[] dataToAdopt = new double[w];
}
return result;
}
}
/**
* Represents a path built from segments. Each segment is
* represented by a triple: x, y, and cumulative advance.
* These represent the end point of the segment. The start
* point of the first segment is represented by the triple
* at position 0.
*
* The path might have breaks in it, e.g. it is not connected.
* These will be represented by pairs of triplets that share the
* same advance.
*
* The path might be extended, pinned, or closed. If extended,
* the initial and final segments are considered to extend
* 'indefinitely' past the bounds of the advance. If pinned,
* they end at the bounds of the advance. If closed,
* advances before the start or after the end 'wrap around' the
* path.
*
* The start of the path is the initial triple. This provides
* the nominal advance at the given x, y position (typically
* zero). The end of the path is the final triple. This provides
* the advance at the end, the total length of the path is
* thus the ending advance minus the starting advance.
*
* Note: We might want to cache more auxiliary data than the
* advance, but this seems adequate for now.
*/
}
/**
* Internal, use SegmentPathBuilder or one of the static
* helper functions to construct a SegmentPath.
*/
}
//
// LayoutPath API
//
}
// the path consists of line segments, which i'll call
// 'path vectors'. call each run of path vectors a 'path segment'.
// no path vector in a path segment is zero length (in the
// data, such vectors start a new path segment).
//
// for each path segment...
//
// for each path vector...
//
// we look at the dot product of the path vector and the vector from the
// origin of the path vector to the test point. if <0 (case
// A), the projection of the test point is before the start of
// the path vector. if > the square of the length of the path vector
// (case B), the projection is past the end point of the
// path vector. otherwise (case C), it lies on the path vector.
// determine the closeset point on the path vector. if case A, it
// is the start of the path vector. if case B and this is the last
// path vector in the path segment, it is the end of the path vector. If
// case C, it is the projection onto the path vector. Otherwise
// there is no closest point.
//
// if we have a closest point, compare the distance from it to
// the test point against our current closest distance.
// (culling should be fast, currently i am using distance
// squared, but there's probably better ways). if we're
// closer, save the new point as the current closest point,
// and record the path vector index so we can determine the final
// info if this turns out to be the closest point in the end.
//
// after we have processed all the segments we will have
// tested each path vector and each endpoint. if our point is not on
// an endpoint, we're done; we can compute the position and
// offset again, or if we saved it off we can just use it. if
// we're on an endpoint we need to see which path vector we should
// associate with. if we're at the start or end of a path segment,
// we're done-- the first or last vector of the segment is the
// one we associate with. we project against that vector to
// get the offset, and pin to that vector to get the length.
//
// otherwise, we compute the information as follows. if the
// dot product (see above) with the following vector is zero,
// we associate with that vector. otherwise, if the dot
// product with the previous vector is zero, we associate with
// that vector. otherwise we're beyond the end of the
// previous vector and before the start of the current vector.
// we project against both vectors and get the distance from
// the test point to the projection (this will be the offset).
// if they are the same, we take the following vector.
// otherwise use the vector from which the test point is the
// _farthest_ (this is because the point lies most clearly in
// the half of the plane defined by extending that vector).
//
// the returned position is the path length to the (possibly
// pinned) point, the offset is the projection onto the line
// along the vector, and we have a boolean flag which if false
// indicates that we associate with the previous vector at a
// junction (which is necessary when projecting such a
// location back to a point).
// start with defaults
// determine sign of dot product of vectors from bx, by
// if < 0, we're before the start of this vector
int vi; // hold index of line, is data.length if last point on path
do { // use break below, lets us avoid initializing vcx, vcy...
(!etype.isExtended() ||
i != 3))) { // closest point is start of vector
vi = i;
} else {
vi = i;
} else {
} else {
break; // typical case, skip point, we'll pick it up next iteration
}
}
}
}
} while (false);
}
// we have our closest point, get the info
}
return false;
} else { // on endpoint, we need to resolve which segment
return true; // associate with previous
} else {
return false; // associate with following
}
} else if (havePrev) {
result.setLocation(x, y);
return true;
} else {
result.setLocation(x, y);
return false;
}
}
}
/**
* Return the location of the point passed in result as mapped to the
* line indicated by index. If doExtend is true, extend the
* x value without pinning to the ends of the line.
* this assumes that index is valid and references a line that has
* non-zero length.
*/
// rx = A dot B / |B|
// ry = A dot invB / |B|
if (!doExtend) {
}
}
//
// LayoutPathImpl API
//
}
public double start() {
return data[2];
}
public double end() {
}
public double length() {
}
//
// Utilities
//
/**
* Get the 'modulus' of an advance on a closed path.
*/
a -= data[2];
a += length();
}
a += data[2];
}
return a;
}
/**
* Return the index of the segment associated with advance. This
* points to the start of the triple and is a multiple of 3 between
* 3 and data.length-3 inclusive. It never points to a 'moveto' triple.
*
* If the path is closed, 'a' is mapped to
* a value between the start and end of the path, inclusive.
* If preceding is true, and 'a' lies on a segment boundary,
* return the index of the preceding segment, else return the index
* of the current segment (if it is not a moveto segment) otherwise
* the following segment (which is never a moveto segment).
*
* Note: if the path is not closed, the advance might not actually
* lie on the returned segment-- it might be before the first, or
* after the last. The first or last segment (as appropriate)
* will be returned in this case.
*/
// must have local advance
a = getClosedAdvance(a, preceding);
// note we must avoid 'moveto' segments. the first segment is
// always a moveto segment, so we always skip it.
int i, lim;
double v = data[i];
if (a < v || (a == v && preceding)) {
break;
}
}
return i-2; // adjust to start of segment
}
/**
* Map a location based on the provided segment, returning in pt.
* Seg must be a valid 'lineto' segment. Note: if the path is
* closed, x must be within the start and end of the path.
*/
}
/**
* Map the point, and return the segment index.
*/
return seg;
}
//
// Mapping classes.
// Map the path onto each path segment.
// Record points where the advance 'enters' and 'exits' the path segment, and connect successive
// points when appropriate.
//
/**
* This represents a line segment from the iterator. Each target segment will
* interpret it, and since this process needs slope along the line
* segment, this lets us compute it once and pass it around easily.
*/
class LineInfo {
/**
* Set the lineinfo to this line
*/
if (dx == 0) {
m = 0; // we'll check for this elsewhere
} else {
}
}
this.m = rhs.m;
}
/**
* Return true if we intersect the infinitely tall rectangle with
* lo <= x < hi. If we do, also return the pinned portion of ourselves in
* result.
*/
}
}
return true;
}
} else {
}
}
return true;
}
}
return false;
}
/**
* Return true if we intersect the segment at ix. This takes
* the path end type into account and computes the relevant
* parameters to pass to pin(double, double, LineInfo).
*/
switch (SegmentPath.this.etype) {
case PINNED:
break;
case EXTENDED:
break;
case CLOSED:
// not implemented
break;
}
}
}
/**
* Each segment will construct its own general path, mapping the provided lines
* into its own simple space.
*/
class Segment {
}
void init() {
broken = true;
this.gp = new GeneralPath();
}
void move() {
broken = true;
}
void close() {
if (!broken) {
}
}
if (broken) {
} else {
}
}
broken = false;
}
}
}
class Mapper {
Mapper() {
}
}
}
void init() {
haveMT = false;
s.init();
}
}
void moveTo(double x, double y) {
mpt.x = x;
mpt.y = y;
haveMT = true;
}
void lineTo(double x, double y) {
if (haveMT) {
// prepare previous point for no-op check
}
// lineto is a no-op
return;
}
if (haveMT) {
// current point is the most recent moveto point
haveMT = false;
s.move();
}
}
}
cpt.x = x;
cpt.y = y;
}
void close() {
s.close();
}
}
init();
final double[] coords = new double[2];
default: break;
}
}
}
return gp;
}
}
//
// for debugging
//
StringBuilder b = new StringBuilder();
b.append("{");
b.append(" ");
if (i > 0) {
b.append(",");
}
b.append("{");
b.append(x);
b.append(",");
b.append(y);
b.append(",");
b.append(l);
b.append("}");
}
b.append("}");
return b.toString();
}
}
}
} else {
}
}
try {
}
catch (NoninvertibleTransformException ex) {
}
}
}
return tx.createTransformedShape(s);
}
return s;
}
}
}