Java Classes - Point Line Polynomial

exercises
lab
java
oop
class-design

Practical exercises for week 3, building up a small geometry class hierarchy (PointLinePolynomial) to practice java-encapsulation and java-mutability (note that movePoint/flipPoint/scale-style methods return a new object rather than mutating this).

On the HTML site, fill in each blank with your answer (as a quoted string, e.g. "5.0"), then click Run Code to check it. In the PDF, the Working callout is shown as a static answer key instead (interactive checking needs a browser).

Question 1 — Points

Write a Point class representing an x,y-coordinate on a Cartesian plane, with:

  • Point(float x, float y) and a default Point() (both 0).
  • getX()/getY().
  • Point movePoint(float deltaX, float deltaY) — returns a new Point at (getX() + deltaX, getY() + deltaY), without modifying this.
  • static double distance(Point p, Point q) — Euclidean distance between two points.

If p1 = new Point() and p2 = p1.movePoint(4, 5), what does p2 print (assuming a toString of "(" + x + ", " + y + ")")?

public class Point {
    private float x;
    private float y;

    public Point() {
        this(0, 0);
    }

    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public float getX() { return this.x; }
    public float getY() { return this.y; }

    public Point movePoint(float deltaX, float deltaY) {
        return new Point(this.x + deltaX, this.y + deltaY);
    }

    public static double distance(Point p, Point q) {
        double x = p.x - q.x;
        double y = p.y - q.y;
        return Math.sqrt(x * x + y * y);
    }

    @Override
    public String toString() {
        return "(" + x + ", " + y + ")";
    }
}

movePoint deliberately returns a new Point rather than mutating thisp1 is left unchanged at (0.0, 0.0).

Question 2 — Lines

Write a Line class storing a start Point, an end Point, and the (precomputed) double length between them, with:

  • Line(Point start, Point end) and a default Line() (both ends at the origin, length 0).
  • getStart()/getEnd()/getLength().
  • void moveStart(float deltaX, float deltaY) / void moveEnd(float deltaX, float deltaY)mutate the line’s start/end in place and recompute the length.

For a Line from (0, 0) to (3, 4), what is getLength()?

public class Line {
    private Point start;
    private Point end;
    private double length;

    public Line() {
        this.start = new Point();
        this.end = new Point();
        this.length = 0;
    }

    public Line(Point start, Point end) {
        this.start = start;
        this.end = end;
        this.length = Point.distance(start, end);
    }

    public Point getStart() { return start; }
    public Point getEnd() { return end; }
    public double getLength() { return length; }

    public void moveStart(float deltaX, float deltaY) {
        start = start.movePoint(deltaX, deltaY);
        length = Point.distance(start, end);
    }

    public void moveEnd(float deltaX, float deltaY) {
        end = end.movePoint(deltaX, deltaY);
        length = Point.distance(start, end);
    }

    @Override
    public String toString() {
        return start.toString() + " " + end.toString() + " " + this.getLength();
    }
}

(0,0) to (3,4) is a 3-4-5 right triangle, so the length is exactly 5.0 — unlike Point, moveStart/moveEnd mutate the Line in place (a deliberately different, mutable design from Point’s immutable movePoint).

Question 3 — Testing and toString

Unless overridden, printing an object prints its class name and memory location, e.g. Point@30f39991. Overriding toString() (as used above) replaces this with something readable — always worth adding when testing a class by eye.

Writing a quick main to sanity-check as you go (rather than writing a large class fully before ever running it) catches mistakes early:

Point p1 = new Point();
Point p2 = p1.movePoint(4, 5);
System.out.println(p1); // (0.0, 0.0)
System.out.println(p2); // (4.0, 5.0)

Question 4 — Additional methods

Add to Point:

  • Line createLine(Point end) — a Line from this to end.
  • Point flipPoint() — negates both coordinates, e.g. (-1, 2) becomes (1, -2).

Add to Line:

  • Point middle() — the midpoint of the start and end.
  • Line flipLine() — a Line with both endpoints flipped.

What does new Point(-1, 2).flipPoint() print?

public Line createLine(Point end) {
    return new Line(this, end);
}

public Point flipPoint() {
    return new Point(x * -1, y * -1);
}

public Point middle() {
    return new Point((start.getX() + end.getX()) / 2, (start.getY() + end.getY()) / 2);
}

public Line flipLine() {
    return new Line(start.flipPoint(), end.flipPoint());
}

Question 5 — Polynomials (bonus)

A polynomial function of the restricted form \(f(x) = a + bx + cx^2\) can be represented by its coefficients. Write a Polynomial class with constructors Polynomial(), Polynomial(float a), Polynomial(float a, float b), Polynomial(float a, float b, float c), plus:

  • float valueAt(float x) — evaluates the polynomial at x.
  • Polynomial add(Polynomial other) — adds two polynomials coefficient-wise, returning a new Polynomial.

For \(f(x) = 1 + 2x\), what is \(f(3)\)?

public class Polynomial {
    private final float[] coefficients;

    public Polynomial() { coefficients = new float[]{0}; }
    public Polynomial(float a) { coefficients = new float[]{a}; }
    public Polynomial(float a, float b) { coefficients = new float[]{a, b}; }
    public Polynomial(float a, float b, float c) { coefficients = new float[]{a, b, c}; }
    public Polynomial(float[] coefficients) { this.coefficients = coefficients; }

    private static float index(float[] coefficients, int index) {
        // Coefficients beyond the polynomial's degree are implicitly 0.
        if (index >= coefficients.length) {
            return 0;
        }
        return coefficients[index];
    }

    public Polynomial add(Polynomial other) {
        int max = Math.max(coefficients.length, other.coefficients.length);
        float[] newCoefficients = new float[max];
        for (int i = 0; i < max; i++) {
            newCoefficients[i] = index(coefficients, i) + index(other.coefficients, i);
        }
        return new Polynomial(newCoefficients);
    }

    public float valueAt(float x) {
        float v = 0;
        float xpower = 1;
        for (int i = 0; i < coefficients.length; i++) {
            v += coefficients[i] * xpower; // xpower == x^i
            xpower *= x;
        }
        return v;
    }
}

\(f(3) = 1 + 2 \times 3 = 7\).

Challenge — representing the unrestricted polynomial \(f(x) = a_0 + a_1x + \dots + a_nx^n\) for any \(n \geq 0\) (rather than fixing the degree at 2) just needs the internal representation generalised to a float[] coefficients array of arbitrary length, as already used by add’s newCoefficients array and the extra Polynomial(float[]) constructor above — valueAt and add already work unchanged for any length.