I have this funny program for playing around with 2D vectors:Vector2D.java:package net.coderodde.robohand;import java.awt.geom.Point2D;import java.util.List;import java.util.ArrayList;import java.util.Objects;/** * This class implements a vector. The tail of another vector can be attached to * the head of this vector. *  * @author Rodion rodde Efremov * @version 1.6 (Apr 17, 2016) */public class Vector2D {    /**     * The <tt>x</tt>-coordinate of the tail of this vector.     */    private float locationX;    /**     * The <tt>y</tt>-coordinate of the tail of this vector.     */    private float locationY;    /**     * The length of this vector.     */    private float length;    /**     * The angle of this vector in radians.     */    private float angle;    /**     * The list of all the child vectors of this vector. Child vectors' tails     * are attached to the head of this vector.     */    private final List<Vector2D> childVectors = new ArrayList<>();    /**     * Constructs a vector with given length and angle.     *      * @param length the length of a new vector.     * @param angle  the angle in radians of a new vector.     */    public Vector2D(float length, float angle) {        this.length = length;        this.angle = angle;    }    /**     * Connects {@code vector} as a child to this vector.     *      * @param vector the child vector to add.     */    public void addChildVector(Vector2D vector) {        Objects.requireNonNull(vector, The input vector is null.);        childVectors.add(vector);        Point2D.Float headLocation = getHeadLocation();        vector.setLocation(headLocation.x, headLocation.y);    }    /**     * Removes a child vector if it is connected to the tail of this vector.     *      * @param vector the vector to remove from the child list.     */    public void removeChildVector(Vector2D vector) {        Objects.requireNonNull(vector, The input vector is null.);        childVectors.remove(vector);    }    /**     * Gets the location of the tail of this vector.     *      * @return the tail location.     */    public Point2D.Float getLocation() {        return new Point2D.Float(locationX, locationY);    }    /**     * Sets the location of this vector. If this vector has child vectors, they     * are moved as well.     *      * @param locationX the <tt>x</tt>-coordinate of the new location.     * @param locationY the <tt>y</tt>-coordinate of the new location.     */    public void setLocation(float locationX, float locationY) {        this.locationX = locationX;        this.locationY = locationY;        Point2D.Float point = getHeadLocation();        for (Vector2D childVector : childVectors) {            childVector.setLocation(point.x, point.y);        }    }    /**     * Returns the length of this vector.     *      * @return the length of this vector.      */    public float getLength() {        return length;    }    /**     * Sets the new length of this vector. If this vector has child vectors,      * they are moved as well.     *      * @param length the new length.     */    public void setLength(float length) {        this.length = length;        Point2D.Float point = getHeadLocation();        for (Vector2D childVector : childVectors) {            childVector.setLocation(point.x, point.y);        }    }    /**     * Gets the angle of this vector.     *      * @return the angle of this vector.     */    public float getAngle() {        return angle;    }    /**     * Sets the angle of this vector. If this vector has child vectors, it      * updates their location and angles as well.     *      * @param angle the angle in radians.     */    public void setAngle(float angle) {        float angleDelta = angle - this.angle;        this.angle = angle;        Point2D.Float headLocation = getHeadLocation();        for (Vector2D childVector : childVectors) {            childVector.setLocation(headLocation.x, headLocation.y);            childVector.setAngle(childVector.getAngle() + angleDelta);        }    }    /**     * Returns the location of the head of this vector.     *      * @return the location of the head of this vector.     */    public Point2D.Float getHeadLocation() {        Point2D.Float point = new Point2D.Float();        float x = locationX + length * (float) Math.cos(angle);        float y = locationY + length * (float) Math.sin(angle);        point.x = x;        point.y = y;        return point;    }}VectorCanvas.java:package net.coderodde.robohand;import java.awt.Canvas;import java.awt.Color;import java.awt.Graphics;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.awt.geom.Point2D;import java.util.ArrayList;import java.util.List;/** * This class implements the canvas that draws vectors. *  * @author Rodion rodde Efremov * @version 1.6 (Apr 17, 2016) */public class VectorCanvas extends Canvas {    /**     * Minimum number of vectors allowed.     */    private static final int MINIMUM_VECTORS = 1;    /**     * When resizing a vector, its length may be increased or decreased by      * {@code LENGTH_DELTA} pixels per request.     */    private static final float LENGTH_DELTA = 5.0f;    /**     * When changing the angle of a vector, the angle increases or decreases by     * {@code ANGLE_DELTA} radians per request. This is roughly 5 degrees.     */    private static final float ANGLE_DELTA = ((float) Math.PI) / 36;    /**     * The color used to draw non-selected vectors.     */    private static final Color VECTOR_COLOR = Color.RED;    /**     * The color of the current vector.      */    private static final Color CURRENT_VECTOR_COLOR = Color.WHITE;    /**     * The list of vectors in this canvas.     */    private final List<Vector2D> vectorList = new ArrayList<>();    /**     * The index of the selected vector.     */    private int selectedVectorIndex;    /**     * Constructs this canvas with given vectors.     *      * @param vectorList the vectors to operate on. May form a tree. A cycle      * will eventually lead to stack overflow.     */    public VectorCanvas(List<Vector2D> vectorList) {        if (vectorList.size() < 1) {            throw new IllegalArgumentException(                    This canvas requires at least  + MINIMUM_VECTORS +  vector.);        }        this.vectorList.addAll(vectorList);        addKeyListener(new MyCanvasKeyListener());    }    /**     * Chooses a preceding vector in the list as selected. If the current      * selected vector is first in the list, does nothing.     */    public void decSelectedVectorIndex() {        if (selectedVectorIndex > 0) {            selectedVectorIndex--;        }        repaint();    }    /**     * Chooses a succeeding vector in the list as selected. If the current      * selected vector is last in the list, does nothing.     */    public void incSelectedVectorIndex() {        if (selectedVectorIndex < vectorList.size() - 1) {            selectedVectorIndex++;        }        repaint();    }    /**     * Makes selected vector a little bit longer.     */    public void enlargeCurrentSelectedVector() {        setSelectedVectorLength(LENGTH_DELTA);    }    /**     * Makes selected vector a little bit shorter. The length of the vector will     * never become negative.     */    public void shrinkCurrentSelectedVector() {        setSelectedVectorLength(-LENGTH_DELTA);    }    /**     * Rotates the selected vector at its tail. If the selected vector has     * child vectors, their angle and location is modified as well such that     * they preserve their geometry with respect to the selected vector.     *      * @param angleDelta the amount of rotation in radians.     */    public void rotateSelectedVector(float angleDelta) {        float newAngle = vectorList.get(selectedVectorIndex)                                   .getAngle() + angleDelta;        vectorList.get(selectedVectorIndex).setAngle(newAngle);        repaint();    }    @Override    public void update(Graphics g) {        vectorList.get(0).setLocation(getWidth() / 2, getHeight() / 2);        // Fill everything with the background color.        g.setColor(getBackground());        g.fillRect(0, 0, getWidth(), getHeight());        // Draw the vectors.        g.setColor(VECTOR_COLOR);        for (Vector2D vector : vectorList) {            draw(g, vector);        }        g.setColor(CURRENT_VECTOR_COLOR);        draw(g, vectorList.get(selectedVectorIndex));    }    @Override    public void paint(Graphics g) {        update(g);    }    private void draw(Graphics g, Vector2D vector) {        Point2D.Float tail = vector.getLocation();        Point2D.Float head = vector.getHeadLocation();        g.drawLine((int) tail.x,                    (int) tail.y,                    (int) head.x,                    (int) head.y);    }    private void setSelectedVectorLength(float delta) {        Vector2D vector = vectorList.get(selectedVectorIndex);        vector.setLength(Math.max(0.0f, vector.getLength() + delta));        repaint();    }    private final class MyCanvasKeyListener implements KeyListener {        @Override        public void keyTyped(KeyEvent e) {            switch (e.getKeyChar()) {                case 'a':                case 'A':                    decSelectedVectorIndex();                    break;                case 'd':                case 'D':                    incSelectedVectorIndex();                    break;                case 'w':                case 'W':                    enlargeCurrentSelectedVector();                    break;                case 's':                case 'S':                    shrinkCurrentSelectedVector();                    break;                case 'q':                case 'Q':                    rotateSelectedVector(-ANGLE_DELTA);                    break;                case 'e':                case 'E':                    rotateSelectedVector(ANGLE_DELTA);                    break;            }        }        @Override        public void keyPressed(KeyEvent e) {}        @Override        public void keyReleased(KeyEvent e) {}    }}RobohandApp.java:package net.coderodde.robohand;import java.awt.BorderLayout;import java.awt.Canvas;import java.awt.Color;import java.awt.Dimension;import java.awt.Toolkit;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.SwingUtilities;/** * This class implements the GUI for dealing with a robohand. *  * @author Rodion rodde Efremov * @version 1.6 (Apr 17, 2016) */public class RobohandApp extends JFrame {    /**     * The width of this frame in pixels.     */    private static final int FRAME_WIDTH  = 800;    /**     * The height of this frame in pixels.     */    private static final int FRAME_HEIGHT = 600;    private final JPanel panel = new JPanel();    private Canvas myCanvas;    public RobohandApp() {        super(Robohand 1.6);        constructCanvas();        this.getContentPane().setLayout(new BorderLayout());        this.getContentPane().add(panel, BorderLayout.CENTER);        panel.setLayout(new BorderLayout());        panel.add(myCanvas, BorderLayout.CENTER);        myCanvas.setBackground(Color.BLACK);        setPreferredSize(new Dimension(FRAME_WIDTH, FRAME_HEIGHT));        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        pack();        setResizable(false);        centerOut();        setVisible(true);    }    private void constructCanvas() {        List<Vector2D> vectorList = new ArrayList<>();        float length = 30.0f;        float angle  = 0.0f;        Vector2D[] vectors = new Vector2D[] {            new Vector2D(length, angle),            new Vector2D(length, angle),            new Vector2D(length, angle),            new Vector2D(length, angle),            new Vector2D(length, angle),            new Vector2D(length, angle),            new Vector2D(length, angle),            new Vector2D(length, angle),        };        vectors[0].addChildVector(vectors[1]);        vectors[0].addChildVector(vectors[2]);        vectors[1].addChildVector(vectors[3]);        vectors[1].addChildVector(vectors[4]);        vectors[2].addChildVector(vectors[5]);        vectors[2].addChildVector(vectors[6]);        vectors[6].addChildVector(vectors[7]);        vectorList.addAll(Arrays.asList(vectors));        myCanvas = new VectorCanvas(vectorList);    }    private void centerOut() {        final int currentWidth  = getWidth();        final int currentHeight = getHeight();        final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();        setLocation((screen.width - currentWidth) / 2,                    (screen.height - currentHeight) / 2);    }    public static void main(final String[] args) {        SwingUtilities.invokeLater(() -> {            RobohandApp app = new RobohandApp();        });    }}It looks like this:In order to manipulate it, click for focus the frame, and use keys wasdqe. This time, it would be nice to hear about my API design.
Controlling a robot arm in a Java GUI program
java;gui