Search This Blog

Friday, August 2, 2013

Java app to draw SVG Bezier curves

I'm in the midst of writing the control program for an Ardunio powered CNC machine.

I've decided I'll use SVG format to drive the CNC machine from the PC.

I can generate SVG files from other pictures with this online free tool:
http://www.autotracer.org/

This tool allows you to view and edit them, and draw my own directly.
http://svg-edit.googlecode.com/svn/branches/2.6/editor/svg-editor.html

Here is the spec on the SVG file format
http://www.w3.org/TR/2011/REC-SVG11-20110816/paths.html#PathDataMovetoCommands

This is a little graphic with some letters and a square I made.

<?xml version="1.0" standalone="yes"?>
<svg width="161" height="150">
<path style="fill:#ffffff; stroke:none;" d="M0 0L0 150L161 150L161 0L0 0z"/>
<path style="fill:#010101; stroke:none;" d="M1 1L1 109L117 109L117 1L1 1z"/>
<path style="fill:#ffffff; stroke:none;" d="M3 3L3 107L115 107L115 85C87.676 91.5053 87.5147 47.4563 115 54L115 3L3 3z"/>
<path style="fill:#010101; stroke:none;" d="M41 43L41 85L49 85L49 69C54.56 69 61.8856 70.2342 66.9568 67.5432C74.8268 63.3671 75.3453 49.6136 67.956 44.7423C61.5192 40.4989 48.4628 43 41 43M80 43L80 50L88 50L88 43L80 43z"/>
<path style="fill:#ffffff; stroke:none;" d="M49 50L49 62C66.8383 61.9882 66.8383 50.0118 49 50z"/>
<path style="fill:#010101; stroke:none;" d="M80 54L80 85L88 85L88 54L80 54z"/>
<path style="fill:#ffffff; stroke:none;" d="M107.043 59.9707C98.9687 61.792 101.299 81.8813 109.794 79.1489C117.684 76.611 116.364 57.8683 107.043 59.9707z"/>
</svg>

I need to be able to interpret the Bezier curve commands and calculate the points to drive the Arduino to.

Some References:




The last one has the code at the end that I ended up starting with.

First I want to make the Java program to compute all the points, and draw them.
Here is the initial implementation of the code at the end of this post



It worked and drew a curve!   Now I need to draw curves with two control points that are entered, and control the number of points in the curve.   Looks like those functions are here.

A little fooling around and I figured out the functions and made a GUI to draw the curves and the control points

Posted the source code and jar file here:
https://code.google.com/p/arduino-java-xyzcnc/downloads/list
https://code.google.com/p/arduino-java-xyzcnc/downloads/detail?name=BezierDraw.jar

This is the guts of the routine:

package bezierdraw;

import java.awt.geom.Point2D;

public class BezierCurve {
    
    Point2D.Double[] cp;
    int numberOfPoints;
    Point2D.Double[] curvePoints;

    public BezierCurve(Point2D.Double[] cp, int numPoints) {
        this.cp = cp;
        numberOfPoints = numPoints;
        curvePoints = new Point2D.Double[numPoints];
        computeBezier();
    }

    protected Point2D.Double[] getCurvePoints() {
        return curvePoints;
    }

    private void computeBezier() {
        double dt = 1.0 / (numberOfPoints - 1);

        for(int j = 0; j < numberOfPoints; j++)
            curvePoints[j] = getCurvePoint(j*dt);
    }
    
    private Point2D.Double getCurvePoint(double t)
    {
        Point2D.Double result = new Point2D.Double();

        /* calculate the polynomial coefficients */
        double cx = 3.0 * (cp[1].x - cp[0].x);
        double bx = 3.0 * (cp[2].x - cp[1].x) - cx;
        double ax = cp[3].x - cp[0].x - cx - bx;

        double cy = 3.0 * (cp[1].y - cp[0].y);
        double by = 3.0 * (cp[2].y - cp[1].y) - cy;
        double ay = cp[3].y - cp[0].y - cy - by;

        /* calculate the curve point at parameter value t */
        double tSquared = t * t;
        double tCubed = tSquared * t;

        result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
        result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;

        return result;
    }
    
}

private void drawBezierPath(Point2D.Double p1, Point2D.Double cp1, Point2D.Double cp2, Point2D.Double p2, int numPoints) {
        Point2D.Double[] points = { p1, cp1, cp2, p2 };
        BezierCurve curve = new BezierCurve(points, numPoints);
        Point2D.Double[] p = curve.getCurvePoints();
        path = new GeneralPath();
        for(int j = 0; j < p.length; j++) {
            if(j == 0)
                path.moveTo((float)p[j].x, (float)p[j].y);
            else
                path.lineTo((float)p[j].x, (float)p[j].y);
        }
        g2d.setColor(Color.red);
        g2d.draw(path);

    }



That is the basic C function.  Now for the S function. The shorthand curve notation is a bit confusing.
http://stackoverflow.com/questions/5287559/calculating-control-points-for-a-shorthand-smooth-svg-path-bezier-curve

From the SVG spec
CommandNameParametersDescription
C(absolute)
c (relative)
curveto(x1 y1 x2 y2 x y)+Draws a cubic Bézier curve from the current point to (x,y) using (x1,y1) as the control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve. C (uppercase) indicates that absolute coordinates will follow; c (lowercase) indicates that relative coordinates will follow. Multiple sets of coordinates may be specified to draw a polybézier. At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybézier.
S(absolute)
s (relative)
shorthand/smooth curveto(x2 y2 x y)+Draws a cubic Bézier curve from the current point to (x,y). The first control point is assumed to be the reflection of the second control point on the previous command relative to the current point. (If there is no previous command or if the previous command was not an C, c, S or s, assume the first control point is coincident with the current point.) (x2,y2) is the second control point (i.e., the control point at the end of the curve). S (uppercase) indicates that absolute coordinates will follow; s (lowercase) indicates that relative coordinates will follow. Multiple sets of coordinates may be specified to draw a polybézier. At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybézier.

I am only doing a cubic curve, and there are quadratic and elliptical types.  Need to see if I need to implement the others or if I can get by with just implementing the Bezier cubic.


2 comments:

  1. Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a Java developer learn from Java Training in Chennai. or learn thru Java Online Training in India . Nowadays Java has tons of job opportunities on various vertical industry.

    ReplyDelete