Example usage for java.awt.geom GeneralPath moveTo

List of usage examples for java.awt.geom GeneralPath moveTo

Introduction

In this page you can find the example usage for java.awt.geom GeneralPath moveTo.

Prototype

public abstract void moveTo(double x, double y);

Source Link

Document

Adds a point to the path by moving to the specified coordinates specified in double precision.

Usage

From source file:org.amanzi.awe.render.network.NetworkRenderer.java

/**
 * Draw black border around selected sector
 * //from   w w w  .  j av a  2  s.  co  m
 * @param destination
 * @param point
 * @param model
 * @param sector
 */
private void renderSelectionBorder(Graphics2D destination, Point point, ISectorElement sector, int index,
        int count) {
    Pair<Double, Double> sectorParameters = getSectorParameters(sector, index, count);
    int size = getSize();
    double azimuth = sectorParameters.getLeft();
    double beamwidth = sectorParameters.getRight();

    GeneralPath path = new GeneralPath();
    path.moveTo(getSectorXCoordinate(point, size), getSectorYCoordinate(point, size));
    Arc2D a = createSector(point, networkRendererStyle.getLargeElementSize(), getAngle(azimuth, beamwidth),
            beamwidth);
    path.append(a.getPathIterator(null), true);
    path.closePath();
    destination
            .setColor(networkRendererStyle.changeColor(SELECTED_SECTOR_COLOR, networkRendererStyle.getAlpha()));
    destination.draw(path);
    destination.drawString(sector.getName(), (int) a.getEndPoint().getX() + 10, (int) a.getEndPoint().getY());
}

From source file:org.apache.fontbox.ttf.GlyphRenderer.java

private void moveTo(GeneralPath path, Point point) {
    path.moveTo(point.x, point.y);
    if (LOG.isDebugEnabled()) {
        LOG.trace("moveTo: " + String.format("%d,%d", point.x, point.y));
    }/*from   www.j av a  2 s .  c o  m*/
}

From source file:org.apache.pdfbox.pdfviewer.font.TTFGlyph2D.java

private void moveTo(GeneralPath path, Point point) {
    path.moveTo(point.x, point.y);
    LOG.debug("moveTo: " + String.format("%d,%d", point.x, point.y));
}

From source file:org.broad.igv.renderer.SpliceJunctionRenderer.java

/**
 * Draw a filled arc representing a single feature. The thickness and height of the arc are proportional to the
 * depth of coverage.  Some of this gets a bit arcane -- the result of lots of visual tweaking.
 *
 * @param pixelFeatureStart  the starting position of the feature, whether on-screen or not
 * @param pixelFeatureEnd    the ending position of the feature, whether on-screen or not
 * @param pixelJunctionStart the starting position of the junction, whether on-screen or not
 * @param pixelJunctionEnd   the ending position of the junction, whether on-screen or not
 * @param depth              coverage depth
 * @param trackRectangle/*www .j a  v  a 2 s.  c om*/
 * @param context
 * @param strand
 * @param junctionFeature
 * @param shouldHighlight
 * @param featureColor       the color specified for this feature.  May be null.
 */
protected void drawFeature(int pixelFeatureStart, int pixelFeatureEnd, int pixelJunctionStart,
        int pixelJunctionEnd, float depth, Rectangle trackRectangle, RenderContext context, Strand strand,
        SpliceJunctionFeature junctionFeature, boolean shouldHighlight, Color featureColor,
        boolean shouldShowFlankingRegions) {

    boolean isPositiveStrand = true;
    // Get the feature's direction, color appropriately
    if (strand != null && strand.equals(Strand.NEGATIVE))
        isPositiveStrand = false;

    //If the feature color is specified, use it, except that we set our own alpha depending on whether
    //the feature is highlighted.  Otherwise default based on strand and highlight.
    Color color;
    if (featureColor != null) {
        int r = featureColor.getRed();
        int g = featureColor.getGreen();
        int b = featureColor.getBlue();
        int alpha = shouldHighlight ? 255 : 140;
        color = new Color(r, g, b, alpha);
    } else {
        if (isPositiveStrand)
            color = shouldHighlight ? ARC_COLOR_HIGHLIGHT_POS : ARC_COLOR_POS;
        else
            color = shouldHighlight ? ARC_COLOR_HIGHLIGHT_NEG : ARC_COLOR_NEG;
    }

    Graphics2D g2D = context.getGraphic2DForColor(color);
    if (PreferenceManager.getInstance().getAsBoolean(PreferenceManager.ENABLE_ANTIALISING)) {
        g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    }
    //Height of top of an arc of maximum depth
    int maxPossibleArcHeight = (trackRectangle.height - 1) / 2;

    if (shouldShowFlankingRegions) {
        if (junctionFeature.hasFlankingRegionDepthArrays()) {
            //draw a wigglegram of the splice junction flanking region depth of coverage

            int startFlankingRegionPixelLength = pixelJunctionStart - pixelFeatureStart;
            int endFlankingRegionPixelLength = pixelFeatureEnd - pixelJunctionEnd;

            drawFlankingRegion(g2D, pixelFeatureStart, startFlankingRegionPixelLength,
                    junctionFeature.getStartFlankingRegionDepthArray(), maxPossibleArcHeight, trackRectangle,
                    isPositiveStrand);
            drawFlankingRegion(g2D, pixelJunctionEnd + 1, endFlankingRegionPixelLength,
                    junctionFeature.getEndFlankingRegionDepthArray(), maxPossibleArcHeight, trackRectangle,
                    isPositiveStrand);
        } else {
            //Draw rectangles indicating the overlap on each side of the junction
            int overlapRectHeight = 3;
            int overlapRectTopX = (int) trackRectangle.getCenterY() + (isPositiveStrand ? -2 : 0);
            if (pixelFeatureStart < pixelJunctionStart) {
                g2D.fillRect(pixelFeatureStart, overlapRectTopX, pixelJunctionStart - pixelFeatureStart,
                        overlapRectHeight);
            }
            if (pixelJunctionEnd < pixelFeatureEnd) {
                g2D.fillRect(pixelJunctionEnd, overlapRectTopX, pixelFeatureEnd - pixelJunctionEnd,
                        overlapRectHeight);
            }
        }
    }

    //Create a path describing the arc, using Bezier curves. The Bezier control points for the top and
    //bottom arcs are based on the boundary points of the rectangles containing the arcs

    //proportion of the maximum arc height used by a minimum-height arc
    double minArcHeightProportion = 0.33;

    int innerArcHeight = (int) (maxPossibleArcHeight * minArcHeightProportion);
    float depthProportionOfMax = Math.min(1, depth / maxDepth);
    int arcWidth = Math.max(1,
            (int) ((1 - minArcHeightProportion) * maxPossibleArcHeight * depthProportionOfMax));
    int outerArcHeight = innerArcHeight + arcWidth;

    //Height of bottom of the arc
    int arcBeginY = (int) trackRectangle.getCenterY() + (isPositiveStrand ? -1 : 1);
    int outerArcPeakY = isPositiveStrand ? arcBeginY - outerArcHeight : arcBeginY + outerArcHeight;
    int innerArcPeakY = isPositiveStrand ? arcBeginY - innerArcHeight : arcBeginY + innerArcHeight;
    //dhmay: I don't really understand Bezier curves.  For some reason I have to put the Bezier control
    //points farther up or down than I want the arcs to extend.  This multiplier seems about right
    int outerBezierY = arcBeginY + (int) (1.3 * (outerArcPeakY - arcBeginY));
    int innerBezierY = arcBeginY + (int) (1.3 * (innerArcPeakY - arcBeginY));

    //Putting the Bezier control points slightly off to the sides of the arc 
    int bezierXPad = Math.max(1, (pixelJunctionEnd - pixelJunctionStart) / 30);

    GeneralPath arcPath = new GeneralPath();
    arcPath.moveTo(pixelJunctionStart, arcBeginY);
    arcPath.curveTo(pixelJunctionStart - bezierXPad, outerBezierY, //Bezier 1
            pixelJunctionEnd + bezierXPad, outerBezierY, //Bezier 2
            pixelJunctionEnd, arcBeginY); //Arc end
    arcPath.curveTo(pixelJunctionEnd + bezierXPad, innerBezierY, //Bezier 1
            pixelJunctionStart - bezierXPad, innerBezierY, //Bezier 2
            pixelJunctionStart, arcBeginY); //Arc end

    //Draw the arc, to ensure outline is drawn completely (fill won't do it, necessarily). This will also
    //give the arc a darker outline
    g2D.draw(arcPath);
    //Fill the arc
    g2D.fill(arcPath);

    g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT);
    g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);

}

From source file:org.esa.snap.graphbuilder.gpf.ui.worldmap.NestWorldMapPane.java

public static ArrayList<GeneralPath> assemblePathList(GeoPos[] geoPoints) {
    final GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO, geoPoints.length + 8);
    final ArrayList<GeneralPath> pathList = new ArrayList<>(16);

    if (geoPoints.length > 1) {
        double lon, lat;
        double minLon = 0, maxLon = 0;

        boolean first = true;
        for (GeoPos gp : geoPoints) {
            lon = gp.getLon();/*from w w  w . j av  a 2s  .  c om*/
            lat = gp.getLat();
            if (first) {
                minLon = lon;
                maxLon = lon;
                path.moveTo(lon, lat);
                first = false;
            }
            if (lon < minLon) {
                minLon = lon;
            }
            if (lon > maxLon) {
                maxLon = lon;
            }
            path.lineTo(lon, lat);
        }
        path.closePath();

        int runIndexMin = (int) Math.floor((minLon + 180) / 360);
        int runIndexMax = (int) Math.floor((maxLon + 180) / 360);

        if (runIndexMin == 0 && runIndexMax == 0) {
            // the path is completely within [-180, 180] longitude
            pathList.add(path);
            return pathList;
        }

        final Area pathArea = new Area(path);
        final GeneralPath pixelPath = new GeneralPath(GeneralPath.WIND_NON_ZERO);
        for (int k = runIndexMin; k <= runIndexMax; k++) {
            final Area currentArea = new Area(
                    new Rectangle2D.Float(k * 360.0f - 180.0f, -90.0f, 360.0f, 180.0f));
            currentArea.intersect(pathArea);
            if (!currentArea.isEmpty()) {
                pathList.add(areaToPath(currentArea, -k * 360.0, pixelPath));
            }
        }
    }
    return pathList;
}

From source file:org.esa.snap.graphbuilder.gpf.ui.worldmap.NestWorldMapPane.java

public static GeneralPath areaToPath(final Area negativeArea, final double deltaX,
        final GeneralPath pixelPath) {

    final float[] floats = new float[6];
    // move to correct rectangle
    final AffineTransform transform = AffineTransform.getTranslateInstance(deltaX, 0.0);
    final PathIterator iterator = negativeArea.getPathIterator(transform);

    while (!iterator.isDone()) {
        final int segmentType = iterator.currentSegment(floats);
        if (segmentType == PathIterator.SEG_LINETO) {
            pixelPath.lineTo(floats[0], floats[1]);
        } else if (segmentType == PathIterator.SEG_MOVETO) {
            pixelPath.moveTo(floats[0], floats[1]);
        } else if (segmentType == PathIterator.SEG_CLOSE) {
            pixelPath.closePath();//from  ww  w  .j a va 2s .  c  o m
        }
        iterator.next();
    }
    return pixelPath;
}

From source file:org.jcurl.math.helpers.CurveShape.java

public static Shape approximateLinear(final CurveGhost c, final double[] sections)
        throws FunctionEvaluationException {
    final double[] x_1 = { c.getC(0, 0, sections[0]), c.getC(1, 0, sections[0]) };
    final double[] x_2 = { 0, 0 };
    final GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO, sections.length + 1);
    gp.moveTo((float) x_1[0], (float) x_1[1]);
    for (int i = 1; i < sections.length; i++) {
        x_2[0] = c.getC(0, 0, sections[i]);
        x_2[1] = c.getC(1, 0, sections[i]);
        gp.lineTo((float) x_2[0], (float) x_2[1]);
        x_1[0] = x_2[0];/*from w  ww.  ja va  2s .c o  m*/
        x_1[1] = x_2[1];
    }
    return gp;
}

From source file:org.jcurl.math.helpers.CurveShape.java

public static Shape approximateQuadratic(final CurveGhost c, final double[] sections)
        throws FunctionEvaluationException {
    final double[] p0 = { c.getC(0, 0, sections[0]), c.getC(1, 0, sections[0]) };
    final double[] v0 = { c.getC(0, 1, sections[0]), c.getC(1, 1, sections[0]) };
    final double[] p1 = { 0, 0 };
    final double[] v1 = { 0, 0 };
    final GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO, sections.length + 1);
    gp.moveTo((float) p0[0], (float) p0[1]);
    final double tmp_a[][] = { { 0, 0 }, { 0, 0 } };
    final double tmp_b[] = { 0, 0 };
    final double pc[] = { 0, 0 };
    for (int i = 1; i < sections.length; i++) {
        p1[0] = c.getC(0, 0, sections[i]);
        p1[1] = c.getC(1, 0, sections[i]);
        v1[0] = c.getC(0, 1, sections[i]);
        v1[1] = c.getC(1, 1, sections[i]);
        computeControlPoint(p0, v0, p1, v1, tmp_a, tmp_b, pc);
        gp.quadTo((float) pc[0], (float) pc[1], (float) p1[0], (float) p1[1]);
        p0[0] = p1[0];/* ww w.j  a  v a 2 s.  c o m*/
        p0[1] = p1[1];
        v0[0] = v1[0];
        v0[1] = v1[1];
    }
    return gp;
}

From source file:org.jcurl.math.ShaperUtils.java

/**
 * Compute the control points and add one <a
 * href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">Cubic Bezier Curve</a>
 * to a {@link GeneralPath}. Does <b>no</b> initial
 * {@link GeneralPath#moveTo(float, float)}.
 * /*from  w ww.  ja va 2 s.c  om*/
 * <h3>Approximation algorithm</h3>
 * <p>
 * This ansatz uses no adaptive optimisation but the nature of curves as
 * they're typical to curling:
 * <ul>
 * <li>continuous within [tmin:tmax] - at least C0, C1</li>
 * <li>smoothly increasing curvature</li>
 * <li>not meandering</li>
 * </ul>
 * So we use
 * <ul>
 * <li>the start- and endpoint of each interval als control points k0 and
 * k3</li>
 * <li>the directions (normalised velocities) in the control points k0 and
 * k3</li>
 * <li>a ratio 3:2:1 of the distances |k0-k1| : |k1-k2| : |k2-k3|</li>
 * </ul>
 * <p>
 * This causes quite a computation - without iteration/recursion though, but
 * 1 square root and many double multiplications - but this is well worth
 * while as we can reduce the curve segments to draw significantly. One
 * cubic bezier curve per seven meters curve length gives an error &lt; 2 mm
 * (using {@link CurlerDenny} with 24s draw-to-tee and 1m curl)!
 * </p>
 * <p>
 * TODO maybe re-use endpoint location and velocity. This can cause pain at
 * C1 discontinuous t's (collissions).
 * </p>
 * <h3><a href="http://en.wikipedia.org/wiki/Maxima_(software)">Maxima</a>
 * Solution</h3>
 * 
 * <pre>
 *    radsubstflag: true$
 *    k1_0 = k0_0 + l * v0_0;
 *    k1_1 = k0_1 + l * v0_1;
 *    k2_0 = k3_0 - n * v3_0;
 *    k2_1 = k3_1 - n * v3_1;
 *    l/n=a/c;
 *    ((k2_0 - k1_0)*(k2_0 - k1_0) + (k2_1 - k1_1)*(k2_1 - k1_1)) / (n*n) = b*b / (c*c);
 *    solve([%th(6), %th(5), %th(4), %th(3), %th(2), %th(1)],[k1_0, k1_1, k2_0, k2_1, l, n]);
 *    factor(%);
 *    ratsimp(%);
 *    ratsubst(V0, v0_1&circ;2+v0_0&circ;2, %);
 *    ratsubst(V3, v3_1&circ;2+v3_0&circ;2, %);
 *    ratsubst(A, k0_1-k3_1, %);
 *    ratsubst(B, k0_0-k3_0, %);
 *    ratsubst(T, 2*a*c*v0_0*v3_0+a&circ;2*v0_1&circ;2+a&circ;2*v0_0&circ;2-b&circ;2, %);
 *    ratsubst(Q, c&circ;2*V3+a&circ;2*V0+T+2*a*c*v0_1*v3_1-a&circ;2*v0_1&circ;2-a&circ;2*v0_0&circ;2, %);
 *    ratsubst(W, B&circ;2*T+B&circ;2*(b&circ;2-Q)+c&circ;2*(v3_0&circ;2*B&circ;2-v3_0&circ;2*A&circ;2)-a&circ;2*v0_1&circ;2*B&circ;2+v3_1*(2*c&circ;2*v3_0*A*B
 *    +2*a*c*v0_0*A*B)+v0_1*(2*a*c*v3_0*A*B+2*a&circ;2*v0_0*A*B)-2*a*c*v0_0*v3_0*A&circ;2-a&circ;2*v0_0&circ;2*A&circ;2
 *    +b&circ;2*A&circ;2, %);
 *    expand(%);
 *    factor(%);
 *    ratsubst(R, c*v3_0*B+a*v0_0*B+c*v3_1*A+a*v0_1*A, %);
 * </pre>
 */
static void curveTo(final R1RNFunction f, final double tmin, final double tmax, final GeneralPath gp,
        final float zoom) {
    final double eps = 1e-6;

    // first control point (startpoint). The same as gp.getCurrentPoint()
    final double k0_0 = f.at(tmin, 0, 0);
    final double k0_1 = f.at(tmin, 0, 1);
    // normalized startpoint velocity
    double v0_0 = f.at(tmin, 1, 0);
    double v0_1 = f.at(tmin, 1, 1);
    if (v0_0 * v0_0 + v0_1 * v0_1 < eps) {
        v0_0 = f.at(tmin + eps, 1, 0);
        v0_1 = f.at(tmin + eps, 1, 1);
    }
    double v = Math.sqrt(v0_0 * v0_0 + v0_1 * v0_1);
    v0_0 /= v;
    v0_1 /= v;

    // 4th control point (endpoint).
    final double k3_0 = f.at(tmax, 0, 0);
    final double k3_1 = f.at(tmax, 0, 1);
    // normalized endpoint velocity
    double v3_0 = f.at(tmax, 1, 0);
    double v3_1 = f.at(tmax, 1, 1);
    if (v3_0 * v3_0 + v3_1 * v3_1 < eps) {
        v3_0 = f.at(tmax - eps, 1, 0);
        v3_1 = f.at(tmax - eps, 1, 1);
    }
    v = Math.sqrt(v3_0 * v3_0 + v3_1 * v3_1);
    v3_0 /= v;
    v3_1 /= v;

    final double a = 3;
    final double b = 2;
    final double c = 1;
    final double V0 = v0_1 * v0_1 + v0_0 * v0_0;
    final double V3 = v3_1 * v3_1 + v3_0 * v3_0;
    final double A = k0_1 - k3_1;
    final double B = k0_0 - k3_0;
    final double T = 2 * a * c * v0_0 * v3_0 + a * a * v0_1 * v0_1 + a * a * v0_0 * v0_0 - b * b;
    final double Q = c * c * V3 + a * a * V0 + T + 2 * a * c * v0_1 * v3_1 - a * a * v0_1 * v0_1
            - a * a * v0_0 * v0_0;
    double W = B * B * T + B * B * (b * b - Q) + c * c * (v3_0 * v3_0 * B * B - v3_0 * v3_0 * A * A)
            - a * a * v0_1 * v0_1 * B * B + v3_1 * 2 * c * c * v3_0 * A * B + 2 * a * c * v0_0 * A * B
            + v0_1 * (2 * a * c * v3_0 * A * B + 2 * a * a * v0_0 * A * B) - 2 * a * c * v0_0 * v3_0 * A * A
            - a * a * v0_0 * v0_0 * A * A + b * b * A * A;
    if (W < 0) {
        if (log.isWarnEnabled()) {
            log.warn("Arithmetic trouble:");
            log.warn("v0=(" + v0_0 + ", " + v0_1 + ")");
            log.warn("v3=(" + v3_0 + ", " + v3_1 + ")");
            log.warn("V0=" + V0);
            log.warn("V3=" + V3);
            log.warn("A=" + A);
            log.warn("B=" + B);
            log.warn("T=" + T);
            log.warn("Q=" + Q);
            log.warn("W=" + W);
        }
        gp.moveTo(zoom * (float) k3_0, zoom * (float) k3_1);
        return;
    }
    W = Math.sqrt(W);
    final double R = c * v3_0 * B + a * v0_0 * B + c * v3_1 * A + a * v0_1 * A;

    final double l, n;
    if (true) {
        final double F = (W + R) / Q;
        l = -a * F;
        n = -c * F;
    } else {
        final double F = (W - R) / Q;
        l = a * F;
        n = c * F;
    }
    if (Double.isNaN(l) || Double.isNaN(n)) {
        log.warn("v0=(" + v0_0 + ", " + v0_1 + ")");
        log.warn("v3=(" + v3_0 + ", " + v3_1 + ")");
        log.warn("V0=" + V0);
        log.warn("V3=" + V3);
        log.warn("A=" + A);
        log.warn("B=" + B);
        log.warn("T=" + T);
        log.warn("Q=" + Q);
        log.warn("W=" + W);
        log.warn("R=" + R);
    }

    final float k1_0 = (float) (k0_0 + l * v0_0);
    final float k1_1 = (float) (k0_1 + l * v0_1);
    final float k2_0 = (float) (k3_0 - n * v3_0);
    final float k2_1 = (float) (k3_1 - n * v3_1);
    if (log.isDebugEnabled())
        log.debug("(" + k1_0 + ", " + k1_1 + "), (" + k2_0 + ", " + k2_1 + "), (" + (float) k3_0 + ", "
                + (float) k3_1 + ")");
    gp.curveTo(zoom * k1_0, zoom * k1_1, zoom * k2_0, zoom * k2_1, zoom * (float) k3_0, zoom * (float) k3_1);
}

From source file:org.jcurl.math.ShaperUtils.java

/**
 * Interpolate using <a/*from   w  w w  .ja v a 2s  .com*/
 * href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">Cubic Bezier Curves</a>.
 * <p>
 * Computes the required intermediate <code>t</code> samples and delegates
 * to {@link #curveTo(R1RNFunction, double, double, GeneralPath, float)} to
 * compute the interpolating curve segments.
 * </p>
 * 
 * @param src
 *            the (at least 2-dimensional) curve. Higher dimensions are
 *            ignored.
 * @param min
 *            the min input <code>t</code> to
 *            {@link R1RNFunction#at(double, int, int)}
 * @param max
 *            the max input <code>t</code> to
 *            {@link R1RNFunction#at(double, int, int)}
 * @param curves
 *            the number of interpolating cubic bezier curves - must be
 *            &gt;= 1.
 * @param zoom
 *            graphics zoom factor (typically 1)
 * @param ip
 *            the {@link Interpolator} to get the intermediate
 *            <code>t</code> sample values.
 * @see #curveTo(R1RNFunction, double, double, GeneralPath, float)
 */
public static Shape interpolateCubic(final R1RNFunction src, final double min, final double max,
        final int curves, final float zoom, final Interpolator ip) {
    // setup
    if (curves < 1)
        throw new IllegalArgumentException("Give me at least 1 (connect start + stop)");
    final float d = (float) (max - min);
    final GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO, 3 * curves + 1); // +1 just to be sure...
    // start
    final float x = (float) src.at(min, 0, 0);
    final float y = (float) src.at(min, 0, 1);
    gp.moveTo(zoom * x, zoom * y);

    double told = min;
    // intermediate
    final int n = curves;
    for (int i = 1; i < n; i++) {
        final double t = min + d * ip.interpolate((float) i / n);
        curveTo(src, told, t, gp, zoom);
        told = t;
    }

    // stop
    curveTo(src, told, max, gp, zoom);
    return gp;
}