#math #geometry #vector #2d

vector2math

Traits for doing 2D vector geometry operations using standard types

29 releases (12 breaking)

0.13.0 Mar 30, 2021
0.11.2 Feb 23, 2021
0.11.1 Oct 15, 2020
0.7.0 Jul 10, 2020
0.4.0 Mar 28, 2019

#564 in Math

Download history 29/week @ 2022-08-09 10/week @ 2022-08-16 67/week @ 2022-08-23 9/week @ 2022-08-30 48/week @ 2022-09-06 18/week @ 2022-09-13 24/week @ 2022-09-20 57/week @ 2022-09-27 33/week @ 2022-10-04 15/week @ 2022-10-11 5/week @ 2022-10-18 19/week @ 2022-10-25 12/week @ 2022-11-01 29/week @ 2022-11-08 88/week @ 2022-11-15 56/week @ 2022-11-22

188 downloads per month
Used in fit_text

MIT license

54KB
1K SLoC

Description

This library provides traits for doing 2D vector geometry operations using either Rust's built-in types or custom types.

For examples and usage details, check out the API Documentation


lib.rs:

This crate provides traits for doing 2D vector geometry operations using standard types

Scalars

Simple vector math is implemented for vectors with the following scalar types:

  • u8-u128
  • usize
  • i8-i128
  • isize
  • f32
  • f64
  • Any type that implements [Scalar]

f32 and f64 implement [FloatingScalar], which gives some additional operations only applicable to floating-point numbers.

Each scalar type has an associated module that has type definitions for standard geometric types using that scalar.

For example, instead of writing

# use vector2math::*;
let square = <[f32; 4]>::square([0.0; 2], 1.0);

You can instead write

# use vector2math::*;
let square = f32::Rect::square([0.0; 2], 1.0);

Vectors

Vectors can be of the following forms:

  • [T; 2]
  • (T, T)
  • Any type that implements [Vector2]

Many 2D Vector operations are supported.

use vector2math::*;

let a = [2, 6];
let b = [4, -1];
assert_eq!(2, a.x());
assert_eq!(-1, b.y());
assert_eq!([-2, -6], a.neg());
assert_eq!([6, 5], a.add(b));
assert_eq!([-2, 7], a.sub(b));
assert_eq!([12, -3], b.mul(3));
assert_eq!([8, -6], b.mul2(a));
assert_eq!([1, 3], a.div(2));
assert_eq!([0, -6], a.div2(b));
assert_eq!(2, a.dot(b));

Vectors that implement [FloatingVector2] have additional operations:

use vector2math::*;

assert_eq!(5.0, [3.0, 4.0].mag());
assert_eq!(10.0, [-1.0, -2.0].dist([5.0, 6.0]));
let rotation_calculation = [1.0, 0.0].rotate_about(f64::TAU / 8.0, [0.0; 2]);
let rotation_solution = [2f64.powf(0.5) / 2.0; 2];
assert!(rotation_calculation.sub(rotation_solution).mag() < std::f64::EPSILON);

Rectangles

Many types can be used to define axis-aligned rectangles:

  • [[T; 2]; 2]
  • [(T, T); 2]
  • ((T, T), (T, T))
  • ([T; 2], [T; 2])
  • [T; 4]
  • (T, T, T, T)
  • Any type that implements [Pair] where the associated [Pair::Item] type implements [Vector2].
use vector2math::*;

let rect = [1i32, 2, 4, 6];
assert_eq!([1, 2], rect.top_left());
assert_eq!([4, 6], rect.size());
assert_eq!([3, 5], rect.center());
assert_eq!(20, rect.perimeter());
assert_eq!(24, rect.area());
assert!(rect.contains([3, 5]));
let corners = rect.corners();
assert_eq!(corners[0], [1, 2]);
assert_eq!(corners[1], [5, 2]);
assert_eq!(corners[2], [5, 8]);
assert_eq!(corners[3], [1, 8]);

Circles

A few types can be used to define circles:

  • ([T; 2], T)
  • ((T, T), T)
  • Any pair of types where the first implements [FloatingVector2] and the second is the vector's [Vector2::Scalar] type.
use vector2math::*;
use std::f64;

let circle = ([2.0, 3.0], 4.0);
assert!((circle.circumference() - 25.132_741_228_718_345).abs() < f64::EPSILON);
assert!((circle.area() - 50.265_482_457_436_69).abs() < f64::EPSILON);
assert!(circle.contains([0.0, 1.0]));
assert!(!circle.contains([5.0, 6.0]));

Mapping

Vector, rectangle, and circle types can be easily mapped to different types:

use vector2math::*;

let arrayf32: [f32; 2] = [1.0, 2.0];
let arrayf64: [f64; 2] = arrayf32.map_into();
let pairf64: (f64, f64) = arrayf64.map_into();
let arrayi16: [i16; 2] = pairf64.map_with(|f| f as i16);
assert_eq!(arrayf32, arrayi16.map_into::<f32::Vec2>());

let weird_rect = [(0.0, 1.0), (2.0, 5.0)];
let normal_rectf32: [f32; 4] = weird_rect.map_into();
let normal_rectf64: [f64; 4] = normal_rectf32.map_into();
let normal_rectu8: [u8; 4] = normal_rectf32.map_with(|f| f as u8);
assert_eq!([0, 1, 2, 5], normal_rectu8);

let pair_circlef32 = ((0.0, 1.0), 2.0);
let array_circlef32 = ([0.0, 1.0], 2.0);
assert_eq!(((0.0, 1.0), 2.0), array_circlef32.map_into::<((f64, f64), f64)>());

Transforms

The [Transform] trait is used to define 2D vector transforms. This crate implements [Transform] for all types that implement Pair where the Pair's Item implments [Trio] where the [Trio]'s [Trio::Item] implements [FloatingScalar]. This type range includes everything from [[f32; 3]; 2] to (f64, f64, f64, f64, f64, f64). [Transform]s can be chained and applied to vectors.

use vector2math::*;

let dis = [1.0; 2];
let rot = f32::TAU / 4.0;
let sc = [2.0; 2];

let transform = f32::Trans::identity().translate(dis).rotate(rot).scale(sc);

let v = [3.0, 5.0];
let v1 = v.transform(transform);
let v2 = v.add(dis).rotate(rot).mul2(sc);

assert_eq!(v1, v2);

Implementing traits

Implementing these traits for your own types is simple. Just make sure that your type is Copy.

use vector2math::*;

#[derive(Clone, Copy)]
struct MyVector {
x: f64,
y: f64,
}

impl Vector2 for MyVector {
type Scalar = f64;
fn new(x: f64, y: f64) -> Self {
MyVector { x, y }
}
fn x(&self) -> f64 {
self.x
}
fn y(&self) -> f64 {
self.y
}
}

#[derive(Clone, Copy)]
struct MyRectangle {
top_left: MyVector,
size: MyVector,
}

impl Rectangle for MyRectangle {
type Vector = MyVector;
fn new(top_left: MyVector, size: MyVector) -> Self {
MyRectangle { top_left, size }
}
fn top_left(self) -> MyVector {
self.top_left
}
fn size(self) -> MyVector {
self.size
}
}

let rect: MyRectangle = [1, 2, 3, 4].map_into();
assert_eq!(12.0, rect.area());
assert_eq!(6.0, rect.bottom());

Dependencies