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