std/linear/vector2
std/linear/src/vector2.trb
Vector2, the two-component vector, and the three layers of members its scalar decides.
There is one type and not two. Vector2 is the Float vector, Vector2<Int> is the pixel or tile vector, and
Vector2<Fixed> is the deterministic one; what each of them can do follows from the scalar's bound. Arithmetic,
dot, lengthSquared and the grid operations need only Numeric; a sign and a Manhattan length need Signed;
length, normalized, angle and rotated need Real, and a grid vector therefore never gets a square root by
accident.
type Vector2
type Vector2<Scalar: Numeric = Float> with Add, Subtract, Multiply<Scalar>, Divide<Scalar>
A point, a direction or a size in the plane, over whatever scalar the program counts in.
Nothing here knows which way is up. y is the second component and that is all it is: a program that draws with
y growing downwards and one that draws with y growing upwards use the same vectors, and only the program's own
rotated calls look different to a viewer.
Examples
const step = Vector2 3.0, 4.0
const tile = Vector2 3, 4
print "{step.length()} {tile.dot(tile)} {step.add(step)}"
Pitfalls
Vector2(1, 2)is aVector2<Int>andVector2(1.0, 2.0)is aVector2<Float>: the literals decide, and the two do not mix. Cross the boundary on purpose withVector2.toFloatandVector2.rounded.- Overflow panics, here as everywhere.
lengthSquaredon aVector2<Int>squares both components, so a pair of coordinates above three billion leaves the range of anIntalthough the vector itself is ordinary. - The constants (
Vector2.zero,Vector2.one,Vector2.unitX,Vector2.unitY) exist for every scalar and take it from the expected type:const tile: Vector2<Int> = Vector2.zerois the grid's zero. With nothing expected, the bareVector2.zerois theFloatone, the declared default.
Related
Vector3- the same members with a third component.Angle- whatVector2.angleanswers and whatVector2.rotatedtakes.
field x
x: Scalar
The first component.
field y
y: Scalar
The second component.
fn filled
static fn filled(value: Scalar): Vector2<Scalar>
Both components set to the same value: the generic way to write a constant vector, where a literal cannot be written at all.
print Vector2.filled 2.0
const zero
static zero: Vector2<Scalar> = Vector2 Scalar.zero, Scalar.zero
Both components zero, over whichever scalar is asked for: Vector2<Int>.zero, Vector2<Fixed>.zero.
const one
static one: Vector2<Scalar> = Vector2 Scalar.one, Scalar.one
Both components one.
const unitX
static unitX: Vector2<Scalar> = Vector2 Scalar.one, Scalar.zero
The first basis vector.
const unitY
static unitY: Vector2<Scalar> = Vector2 Scalar.zero, Scalar.one
The second basis vector.
fn add
fn add(other: Vector2<Scalar>): Vector2<Scalar>
The sum, component by component.
fn subtract
fn subtract(other: Vector2<Scalar>): Vector2<Scalar>
The difference, component by component.
fn multiply
fn multiply(other: Scalar): Vector2<Scalar>
Every component multiplied by the scalar.
fn divide
fn divide(other: Scalar): Vector2<Scalar>
Every component divided by the scalar. Panics on a division by zero.
fn dot
fn dot(other: Vector2<Scalar>): Scalar
The dot product: length * other.length * cosine(angle between them), without a square root and without an angle.
Zero exactly where the two are perpendicular, positive where they point the same way.
fn lengthSquared
fn lengthSquared(): Scalar
The square of the length. This is the comparison to reach for: sorting by distance, a radius test and a
"did it move at all" test all work on it, and none of them needs the root that Vector2.length would take.
fn cross
fn cross(other: Vector2<Scalar>): Scalar
The one number a cross product has in the plane: x * other.y - y * other.x. It is the signed area of the
parallelogram the two span, so its sign says which side of self the other vector is on, and it is zero exactly
where the two are parallel.
fn scaled
fn scaled(by: Vector2<Scalar>): Vector2<Scalar>
Component by component, which is what scaling a size by a size means.
fn divided
fn divided(by: Vector2<Scalar>): Vector2<Scalar>
Component by component. Panics where a component of by is zero.
fn min
fn min(other: Vector2<Scalar>): Vector2<Scalar>
The smaller of each pair of components: the corner of the box that holds both.
fn max
fn max(other: Vector2<Scalar>): Vector2<Scalar>
The larger of each pair of components.
fn clamped
fn clamped(low: Vector2<Scalar>, high: Vector2<Scalar>): Vector2<Scalar>
Every component pulled into the box the two corners span.
fn withX
fn withX(value: Scalar): Vector2<Scalar>
The same vector with another first component.
fn withY
fn withY(value: Scalar): Vector2<Scalar>
The same vector with another second component.
fn isZero
fn isZero(): Bool
Whether both components are zero.
fn largestComponent
fn largestComponent(): Scalar
The larger of the two components.
fn smallestComponent
fn smallestComponent(): Scalar
The smaller of the two components.
fn sum
fn sum(): Scalar
Both components added together: the area of a box this size is Vector2.scaled instead.
extend Vector2<Scalar> with Negate
extend<Scalar: Signed> Vector2<Scalar> with Negate
A vector of a signed scalar can be turned around, and that is what a direction needs.
fn negate
fn negate(): Vector2<Scalar>
Every component with its sign flipped.
extend Vector2<Scalar>
extend<Scalar: Signed> Vector2<Scalar>
What a sign buys: a distance that needs no root, and the quarter turn that needs no trigonometry.
fn absolute
fn absolute(): Vector2<Scalar>
Every component without its sign.
fn manhattanLength
fn manhattanLength(): Scalar
The distance along the axes, |x| + |y|: the number of steps on a four-neighbour grid, and the cheapest distance
there is.
print Vector2(3, -4).manhattanLength()
fn manhattanDistanceTo
fn manhattanDistanceTo(other: Vector2<Scalar>): Scalar
The Vector2.manhattanLength of the step from here to there.
fn perpendicular
fn perpendicular(): Vector2<Scalar>
A quarter turn from the first axis towards the second, (-y, x). Exact for every scalar, integers included, which
is why a right angle in this library is this and not a rotation by Angle.quarterTurn.
extend Vector2<Scalar>
extend<Scalar: Real> Vector2<Scalar>
What a root and an angle buy: lengths, directions and interpolation.
fn length
fn length(): Scalar
The euclidean length. Vector2.lengthSquared is the one to compare with.
fn distanceTo
fn distanceTo(other: Vector2<Scalar>): Scalar
The distance from here to there.
fn distanceSquaredTo
fn distanceSquaredTo(other: Vector2<Scalar>): Scalar
The square of the distance from here to there, without the root.
fn normalized
fn normalized(): Vector2<Scalar>
The same direction with length one. A vector that is already zero answers itself, because there is no direction to keep and a division by zero would be a worse answer than the honest one.
print Vector2(3.0, 4.0).normalized()
fn withLength
fn withLength(value: Scalar): Vector2<Scalar>
The same direction with the length given. A zero vector stays zero.
fn angle
fn angle(): Angle<Scalar>
The direction, measured from the first axis towards the second. A zero vector answers no rotation.
fn angleTo
fn angleTo(other: Vector2<Scalar>): Angle<Scalar>
The rotation that takes this direction onto the other one, in (-pi, pi].
fn rotated
fn rotated(by: Angle<Scalar>): Vector2<Scalar>
Turned by the angle, from the first axis towards the second. Whether a viewer sees that as clockwise depends on which way the program draws its second axis, and this library does not decide that.
print Vector2(1.0, 0.0).rotated(by: Angle.degrees(90.0)).isCloseTo(Vector2(0.0, 1.0), tolerance: 0.0001)
fn rotatedAround
fn rotatedAround(center: Vector2<Scalar>, by: Angle<Scalar>): Vector2<Scalar>
Turned around the given point instead of around the origin.
fn interpolated
fn interpolated(toward: Vector2<Scalar>, by: Scalar): Vector2<Scalar>
The point factor of the way from here to there: 0 is here, 1 is there, and a factor outside [0, 1] carries
on past either end.
fn projectedOnto
fn projectedOnto(other: Vector2<Scalar>): Vector2<Scalar>
The part of this vector that lies along the other one. Panics where the other one is zero.
fn reflected
fn reflected(normal: Vector2<Scalar>): Vector2<Scalar>
Mirrored in the line through the origin whose normal is given. The normal is expected to have length one.
fn isCloseTo
fn isCloseTo(other: Vector2<Scalar>, tolerance: Scalar): Bool
Whether every component is within tolerance of the other vector's.
extend Vector2<Float>
extend Vector2<Float>
The float vector: the three ways down to a grid.
fn rounded
fn rounded(): Vector2<Int>
Every component rounded to the nearest whole number, halves away from zero.
print Vector2(1.5, -1.5).rounded()
Panics
When a component is not a number or its rounding does not fit an Int, as wholeOf says.
fn floored
fn floored(): Vector2<Int>
Every component rounded towards negative infinity: which cell of a grid the point is in.
Panics
When a component is not a number or its rounding does not fit an Int, as wholeOf says.
fn ceiling
fn ceiling(): Vector2<Int>
Every component rounded towards positive infinity.
Panics
When a component is not a number or its rounding does not fit an Int, as wholeOf says.
extend Vector2<Int>
extend Vector2<Int>
The grid vector: the two ways up to a scalar that has fractions.