use super::*;
pub fn transform_point(t: Transform, p: Vec2) -> Vec2 {
let x = (t.q.c * p.x - t.q.s * p.y) + t.p.x;
let y = (t.q.s * p.x + t.q.c * p.y) + t.p.y;
Vec2 { x, y }
}
pub fn inv_transform_point(t: Transform, p: Vec2) -> Vec2 {
let vx = p.x - t.p.x;
let vy = p.y - t.p.y;
Vec2 {
x: t.q.c * vx + t.q.s * vy,
y: -t.q.s * vx + t.q.c * vy,
}
}
pub fn mul_transforms(a: Transform, b: Transform) -> Transform {
Transform {
q: mul_rot(a.q, b.q),
p: add(rotate_vector(a.q, b.p), a.p),
}
}
pub fn inv_mul_transforms(a: Transform, b: Transform) -> Transform {
Transform {
q: inv_mul_rot(a.q, b.q),
p: inv_rotate_vector(a.q, sub(b.p, a.p)),
}
}
pub fn to_pos(v: Vec2) -> Pos {
Pos {
x: v.x as _,
y: v.y as _,
}
}
pub fn to_vec2(p: Pos) -> Vec2 {
Vec2 {
x: p.x as f32,
y: p.y as f32,
}
}
#[cfg(feature = "double-precision")]
pub fn round_down_float(x: f64) -> f32 {
let f = x as f32;
if f as f64 > x {
next_after_f32(f, f32::MIN)
} else {
f
}
}
#[cfg(feature = "double-precision")]
pub fn round_up_float(x: f64) -> f32 {
let f = x as f32;
if (f as f64) < x {
next_after_f32(f, f32::MAX)
} else {
f
}
}
#[cfg(not(feature = "double-precision"))]
pub fn round_down_float(x: f64) -> f32 {
x as f32
}
#[cfg(not(feature = "double-precision"))]
pub fn round_up_float(x: f64) -> f32 {
x as f32
}
#[cfg(feature = "double-precision")]
fn next_after_f32(from: f32, to: f32) -> f32 {
if from.is_nan() || to.is_nan() {
return f32::NAN;
}
if from == to {
return to;
}
if from == 0.0 {
return if to > 0.0 {
f32::from_bits(1)
} else {
-f32::from_bits(1)
};
}
let bits = from.to_bits();
let next = if (from < to) == (from > 0.0) {
bits + 1
} else {
bits - 1
};
f32::from_bits(next)
}
pub fn sub_pos(a: Pos, b: Pos) -> Vec2 {
Vec2 {
x: (a.x - b.x) as f32,
y: (a.y - b.y) as f32,
}
}
pub fn offset_pos(p: Pos, d: Vec2) -> Pos {
Pos {
x: p.x + d.x as PosScalar,
y: p.y + d.y as PosScalar,
}
}
pub fn lerp_position(a: Pos, b: Pos, t: f32) -> Pos {
Pos {
x: (1.0 - t) as PosScalar * a.x + t as PosScalar * b.x,
y: (1.0 - t) as PosScalar * a.y + t as PosScalar * b.y,
}
}
#[cfg(feature = "double-precision")]
type PosScalar = f64;
#[cfg(not(feature = "double-precision"))]
type PosScalar = f32;
pub fn transform_world_point(t: WorldTransform, p: Vec2) -> Pos {
let rx = t.q.c * p.x - t.q.s * p.y;
let ry = t.q.s * p.x + t.q.c * p.y;
Pos {
x: t.p.x + rx as PosScalar,
y: t.p.y + ry as PosScalar,
}
}
pub fn inv_transform_world_point(t: WorldTransform, p: Pos) -> Vec2 {
let vx = (p.x - t.p.x) as f32;
let vy = (p.y - t.p.y) as f32;
Vec2 {
x: t.q.c * vx + t.q.s * vy,
y: -t.q.s * vx + t.q.c * vy,
}
}
pub fn inv_mul_world_transforms(a: WorldTransform, b: WorldTransform) -> Transform {
let d = Vec2 {
x: (b.p.x - a.p.x) as f32,
y: (b.p.y - a.p.y) as f32,
};
Transform {
q: inv_mul_rot(a.q, b.q),
p: inv_rotate_vector(a.q, d),
}
}
pub fn offset_world_transform(a: WorldTransform, b: Transform) -> WorldTransform {
WorldTransform {
q: mul_rot(a.q, b.q),
p: offset_pos(a.p, rotate_vector(a.q, b.p)),
}
}
pub fn to_relative_transform(t: WorldTransform, base: Pos) -> Transform {
Transform {
q: t.q,
p: Vec2 {
x: (t.p.x - base.x) as f32,
y: (t.p.y - base.y) as f32,
},
}
}
pub fn make_world_transform(t: Transform) -> WorldTransform {
WorldTransform {
p: to_pos(t.p),
q: t.q,
}
}
pub fn mul_mv(a: Mat22, v: Vec2) -> Vec2 {
Vec2 {
x: a.cx.x * v.x + a.cy.x * v.y,
y: a.cx.y * v.x + a.cy.y * v.y,
}
}
pub fn get_inverse_22(a: Mat22) -> Mat22 {
let (m11, m12, m21, m22) = (a.cx.x, a.cy.x, a.cx.y, a.cy.y);
let mut det = m11 * m22 - m12 * m21;
if det != 0.0 {
det = 1.0 / det;
}
Mat22 {
cx: Vec2 {
x: det * m22,
y: -det * m21,
},
cy: Vec2 {
x: -det * m12,
y: det * m11,
},
}
}
pub fn solve_22(a: Mat22, b: Vec2) -> Vec2 {
let (a11, a12, a21, a22) = (a.cx.x, a.cy.x, a.cx.y, a.cy.y);
let mut det = a11 * a22 - a12 * a21;
if det != 0.0 {
det = 1.0 / det;
}
Vec2 {
x: det * (a22 * b.x - a12 * b.y),
y: det * (a11 * b.y - a21 * b.x),
}
}