998 lines · 36.7 KB · Java
RawDownload
                    } else {                        result.setLocation(fp);                        return false; // associate with following                    }                } else if (havePrev) {                    result.setLocation(x, y);                    calcoffset(ci - 3, doExtend, result);                    return true;                } else {                    result.setLocation(x, y);                    calcoffset(ci, doExtend, result);                    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.         */        private void calcoffset(int index, boolean doExtend, Point2D result) {            double bx = data[index-3];            double by = data[index-2];            double px = result.getX() - bx;            double py = result.getY() - by;            double dx = data[index] - bx;            double dy = data[index+1] - by;            double l = data[index+2] - data[index - 1];             // rx = A dot B / |B|            // ry = A dot invB / |B|            double rx = (px * dx + py * dy) / l;            double ry = (px * -dy + py * dx) / l;            if (!doExtend) {                if (rx < 0) rx = 0;                else if (rx > l) rx = l;            }            rx += data[index-1];            result.setLocation(rx, ry);        }         //        // LayoutPathImpl API        //         public Shape mapShape(Shape s) {            return new Mapper().mapShape(s);        }         public double start() {            return data[2];        }         public double end() {            return data[data.length - 1];        }         public double length() {            return data[data.length-1] - data[2];        }         //        // Utilities        //         /**         * Get the 'modulus' of an advance on a closed path.         */        private double getClosedAdvance(double a, boolean preceding) {            if (etype.isClosed()) {                a -= data[2];                int count = (int)(a/length());                a -= count * length();                if (a < 0 || (a == 0 && preceding)) {                    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.         */        private int getSegmentIndexForAdvance(double a, boolean preceding) {            // 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;            for (i = 5, lim = data.length-1; i < lim; i += 3) {                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.         */        private void map(int seg, double a, double o, Point2D pt) {            double dx = data[seg] - data[seg-3];            double dy = data[seg+1] - data[seg-2];            double dl = data[seg+2] - data[seg-1];             double ux = dx/dl; // could cache these, but is it worth it?            double uy = dy/dl;             a -= data[seg-1];             pt.setLocation(data[seg-3] + a * ux - o * uy,                           data[seg-2] + a * uy + o * ux);        }         /**         * Map the point, and return the segment index.         */        private int locateAndGetIndex(Point2D loc, boolean preceding, Point2D result) {            double a = loc.getX();            double o = loc.getY();            int seg = getSegmentIndexForAdvance(a, preceding);            map(seg, a, o, result);             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 {            double sx, sy; // start            double lx, ly; // limit            double m;      // slope dy/dx             /**             * Set the lineinfo to this line             */            void set(double sx, double sy, double lx, double ly) {                this.sx = sx;                this.sy = sy;                this.lx = lx;                this.ly = ly;                double dx = lx - sx;                if (dx == 0) {                    m = 0; // we'll check for this elsewhere                } else {                    double dy = ly - sy;                    m = dy / dx;                }            }             void set(LineInfo rhs) {                this.sx = rhs.sx;                this.sy = rhs.sy;                this.lx = rhs.lx;                this.ly = rhs.ly;                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.             */            boolean pin(double lo, double hi, LineInfo result) {                result.set(this);                if (lx >= sx) {                    if (sx < hi && lx >= lo) {                        if (sx < lo) {                            if (m != 0) result.sy = sy + m * (lo - sx);                            result.sx = lo;                        }                        if (lx > hi) {                            if (m != 0) result.ly = ly + m * (hi - lx);                            result.lx = hi;                        }                        return true;                    }                } else {                    if (lx < hi && sx >= lo) {                        if (lx < lo) {                            if (m != 0) result.ly = ly + m * (lo - lx);                            result.lx = lo;                        }                        if (sx > hi) {                            if (m != 0) result.sy = sy + m * (hi - sx);                            result.sx = hi;                        }                        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).             */            boolean pin(int ix, LineInfo result) {                double lo = data[ix-1];                double hi = data[ix+2];                switch (SegmentPath.this.etype) {                case PINNED:                    break;                case EXTENDED:                    if (ix == 3) lo = Double.NEGATIVE_INFINITY;                    if (ix == data.length - 3) hi = Double.POSITIVE_INFINITY;                    break;                case CLOSED:                    // not implemented                    break;                }                 return pin(lo, hi, result);            }        }         /**         * Each segment will construct its own general path, mapping the provided lines         * into its own simple space.         */        class Segment {            final int ix;        // index into data array for this segment            final double ux, uy; // unit vector             final LineInfo temp; // working line info             boolean broken;      // true if a moveto has occurred since we last added to our path            double cx, cy;       // last point in gp            GeneralPath gp;      // path built for this segment             Segment(int ix) {                this.ix = ix;                double len = data[ix+2] - data[ix-1];                this.ux = (data[ix] - data[ix-3]) / len;                this.uy = (data[ix+1] - data[ix-2]) / len;                this.temp = new LineInfo();            }             void init() {                if (LOGMAP) LOG.format("s(%d) init\n", ix);                broken = true;                cx = cy = Double.MIN_VALUE;                this.gp = new GeneralPath();            }             void move() {                if (LOGMAP) LOG.format("s(%d) move\n", ix);                broken = true;            }             void close() {                if (!broken) {                    if (LOGMAP) LOG.format("s(%d) close\n[cp]\n", ix);                    gp.closePath();                }            }             void line(LineInfo li) {                if (LOGMAP) LOG.format("s(%d) line %g, %g to %g, %g\n", ix, li.sx, li.sy, li.lx, li.ly);                 if (li.pin(ix, temp)) {                    if (LOGMAP) LOG.format("pin: %g, %g to %g, %g\n", temp.sx, temp.sy, temp.lx, temp.ly);                     temp.sx -= data[ix-1];                    double sx = data[ix-3] + temp.sx * ux - temp.sy * uy;                    double sy = data[ix-2] + temp.sx * uy + temp.sy * ux;                    temp.lx -= data[ix-1];                    double lx = data[ix-3] + temp.lx * ux - temp.ly * uy;                    double ly = data[ix-2] + temp.lx * uy + temp.ly * ux;                     if (LOGMAP) LOG.format("points: %g, %g to %g, %g\n", sx, sy, lx, ly);                     if (sx != cx || sy != cy) {                        if (broken) {                            if (LOGMAP) LOG.format("[mt %g, %g]\n", sx, sy);                            gp.moveTo((float)sx, (float)sy);                        } else {                            if (LOGMAP) LOG.format("[lt %g, %g]\n", sx, sy);                            gp.lineTo((float)sx, (float)sy);                        }                    }                    if (LOGMAP) LOG.format("[lt %g, %g]\n", lx, ly);                    gp.lineTo((float)lx, (float)ly);                     broken = false;                    cx = lx;                    cy = ly;                }            }        }         class Mapper {            final LineInfo li;                 // working line info            final ArrayList<Segment> segments; // cache additional data on segments, working objects            final Point2D.Double mpt;          // last moveto source point            final Point2D.Double cpt;          // current source point            boolean haveMT;                    // true when last op was a moveto             Mapper() {                li = new LineInfo();                segments = new ArrayList<Segment>();                for (int i = 3; i < data.length; i += 3) {                    if (data[i+2] != data[i-1]) { // a new segment                        segments.add(new Segment(i));                    }                }                 mpt = new Point2D.Double();                cpt = new Point2D.Double();            }             void init() {                if (LOGMAP) LOG.format("init\n");                haveMT = false;                for (Segment s: segments) {                    s.init();                }            }             void moveTo(double x, double y) {                if (LOGMAP) LOG.format("moveto %g, %g\n", x, y);                mpt.x = x;                mpt.y = y;                haveMT = true;            }             void lineTo(double x, double y) {                if (LOGMAP) LOG.format("lineto %g, %g\n", x, y);                 if (haveMT) {                    // prepare previous point for no-op check                    cpt.x = mpt.x;                    cpt.y = mpt.y;                }                 if (x == cpt.x && y == cpt.y) {                    // lineto is a no-op                    return;                }                 if (haveMT) {                    // current point is the most recent moveto point                    haveMT = false;                    for (Segment s: segments) {                        s.move();                    }                }                 li.set(cpt.x, cpt.y, x, y);                for (Segment s: segments) {                    s.line(li);                }                 cpt.x = x;                cpt.y = y;            }             void close() {                if (LOGMAP) LOG.format("close\n");                lineTo(mpt.x, mpt.y);                for (Segment s: segments) {                    s.close();                }            }             public Shape mapShape(Shape s) {                if (LOGMAP) LOG.format("mapshape on path: %s\n", LayoutPathImpl.SegmentPath.this);                PathIterator pi = s.getPathIterator(null, 1); // cheap way to handle curves.                 if (LOGMAP) LOG.format("start\n");                init();                 final double[] coords = new double[2];                while (!pi.isDone()) {                    switch (pi.currentSegment(coords)) {                    case SEG_CLOSE: close(); break;                    case SEG_MOVETO: moveTo(coords[0], coords[1]); break;                    case SEG_LINETO: lineTo(coords[0], coords[1]); break;                    default: break;                    }                     pi.next();                }                if (LOGMAP) LOG.format("finish\n\n");                 GeneralPath gp = new GeneralPath();                for (Segment seg: segments) {                    gp.append(seg.gp, false);                }                return gp;            }        }         //        // for debugging        //         public String toString() {            StringBuilder b = new StringBuilder();            b.append("{");            b.append(etype.toString());            b.append(" ");            for (int i = 0; i < data.length; i += 3) {                if (i > 0) {                    b.append(",");                }                float x = ((int)(data[i] * 100))/100.0f;                float y = ((int)(data[i+1] * 100))/100.0f;                float l = ((int)(data[i+2] * 10))/10.0f;                b.append("{");                b.append(x);                b.append(",");                b.append(y);                b.append(",");                b.append(l);                b.append("}");            }            b.append("}");            return b.toString();        }    }      public static class EmptyPath extends LayoutPathImpl {        private AffineTransform tx;         public EmptyPath(AffineTransform tx) {            this.tx = tx;        }         public void pathToPoint(Point2D location, boolean preceding, Point2D point) {            if (tx != null) {                tx.transform(location, point);            } else {                point.setLocation(location);            }        }         public boolean pointToPath(Point2D pt, Point2D result) {            result.setLocation(pt);            if (tx != null) {                try {                    tx.inverseTransform(pt, result);                }                catch (NoninvertibleTransformException ex) {                }            }            return result.getX() > 0;        }         public double start() { return 0; }         public double end() { return 0; }         public double length() { return 0; }         public Shape mapShape(Shape s) {            if (tx != null) {                return tx.createTransformedShape(s);            }            return s;        }    }}

Lines 501–998 of 998. Previous lines