We have our vectors ready. Now, points are entirely analogous, insofar they are value objects:

final class Pt { public final double x; public final double y; public Pt(double x, double y) { this.x = x; this.y = y; } public static final Pt ORIGIN = new Pt(0, 0); public boolean equals(Object o) { if (o == null || !(o instanceof Pt)) return false; else if (this == o) return true; final Pt that = (Pt) o; return this.x == that.x && this.y == that.y; } public int hashCode() { return (int) ((Double.doubleToLongBits(x) >> 32) & 0xffffffffL) ^ (int) ((Double.doubleToLongBits(y) >> 32) & 0xffffffffL); } public String toString() { return String.format("(%g , %g)", x, y); }

There is a distinguished point, the origin.

It is important to understand the need to duplicate code that is essentially the same as in `Vec`

; in other words, it is not appropriate to refactor common code in classes `Vec`

and `Pt`

, for two reasons:

- First, a vector is not a point, nor vice-versa. There is not even a meaningful common supertype between them. The whole point of using the typed algebra is to manipulate formulas with the added security afforded by the typing rules
- Second, even if a private base class could abstract some code, the bulk of the code needed to correctly implement a base type is in
`equals`

. This method needs to cast to the static class of the object in order for the comparison to be meaningful (else it would be comparing a derived class to the base class), so the duplicate`equals`

are essential anyway

The Algebra has two "constructors" linking points and vectors: the point constructor and the vector constructor. Both operate on points, so naturally they are members of the `Pt`

class. Also, as Axiom 1 states, both operations are some kind of additive inverses one of the other:

public Pt at(Vec v) { return new Pt(x + v.i, y + v.j); } public Vec to(Pt p) { return new Vec(p.x - x, p.y - y); }

A natural operation on points is to find the distance between them. It is, quite simply, `p.to(q).norm()`

. However for convenience I include it directly in `Pt`

:

public double dist(Pt p) { return to(p).norm(); }

Linear interpolation, or lerp mixes two points to give a third:

public Pt lerp(Pt p, double k) { return at(to(p).scale(k)); }

In particular, the midpoint between two given points is:

public Pt mid(Pt p) { return lerp(p, 0.5); }

The set of all linear interpolants is obviously a line. The simplest way to determine one is however to give a point through which it passes and the direction it takes:

public Line towards(Vec v) { return new Line(this, v); } public Line through(Pt p) { return new Line(this, to(p)); } }

I will show next how to use lines.

## No comments:

Post a Comment