use na;
use grid::{GridCoord, GridPoint3, Dir};
use grid::cell_shape::NEIGHBOR_OFFSETS;
use super::triangles::*;
type Pos2 = na::Point2<GridCoord>;
type PosMat2 = na::Matrix2<GridCoord>;
pub fn local_to_world(
pos: GridPoint3,
dir: Dir,
resolution: [GridCoord; 2],
tri: &Triangle,
) -> (GridPoint3, Dir) {
let x_dir = tri.x_dir;
let y_dir = (x_dir + 2) % 12;
let x_edge_index = (x_dir / 2) as usize;
let y_edge_index = (y_dir / 2) as usize;
let transform_to_world = PosMat2::new(
NEIGHBOR_OFFSETS[x_edge_index].0,
NEIGHBOR_OFFSETS[y_edge_index].0,
NEIGHBOR_OFFSETS[x_edge_index].1,
NEIGHBOR_OFFSETS[y_edge_index].1,
);
let pos2 = Pos2::new(pos.x, pos.y);
let mut new_pos2: Pos2 = transform_to_world * pos2;
let new_dir = Dir::new((dir.index + x_dir) % 12);
let apex = Pos2::new(tri.apex[0], tri.apex[1]) * resolution[0];
new_pos2 += apex.coords;
let mut new_pos = pos;
new_pos.x = new_pos2.x;
new_pos.y = new_pos2.y;
(new_pos, new_dir)
}
pub fn world_to_local(
pos: GridPoint3,
dir: Dir,
resolution: [GridCoord; 2],
tri: &Triangle,
) -> (GridPoint3, Dir) {
let apex = Pos2::new(tri.apex[0], tri.apex[1]) * resolution[0];
let pos2 = Pos2::new(pos.x, pos.y);
let pos_from_tri_apex = Pos2::from_coordinates(pos2 - apex);
let x_dir = tri.x_dir;
let y_dir = (x_dir + 2) % 12;
let x_edge_index = (x_dir / 2) as usize;
let y_edge_index = (y_dir / 2) as usize;
let transform_to_local = PosMat2::new(
NEIGHBOR_OFFSETS[y_edge_index].1,
-NEIGHBOR_OFFSETS[y_edge_index].0,
-NEIGHBOR_OFFSETS[x_edge_index].1,
NEIGHBOR_OFFSETS[x_edge_index].0,
);
let new_pos2: Pos2 = transform_to_local * pos_from_tri_apex;
let mut new_pos = pos;
new_pos.x = new_pos2.x;
new_pos.y = new_pos2.y;
let new_dir = Dir::new((dir.index + 12 - x_dir) % 12);
(new_pos, new_dir)
}
#[cfg(test)]
mod tests {
use super::*;
use grid::{GridPoint3, Dir};
const RESOLUTION: [i64; 2] = [32, 64];
#[test]
fn world_to_tri_0_facing_x_is_noop() {
let pos = GridPoint3::default();
let dir = Dir::default();
let tri = &TRIANGLES[0];
let (new_pos, new_dir) = world_to_local(pos, dir, RESOLUTION, tri);
assert_eq!(pos, new_pos);
assert_eq!(dir, new_dir);
}
#[test]
fn world_to_tri_0_facing_north_is_noop() {
let pos = GridPoint3::default().with_x(1).with_y(1);
let dir = Dir::new(7);
let tri = &TRIANGLES[0];
let (new_pos, new_dir) = world_to_local(pos, dir, RESOLUTION, tri);
assert_eq!(pos, new_pos);
assert_eq!(dir, new_dir);
}
#[test]
fn world_to_tri_4() {
let pos = GridPoint3::default().with_x(2).with_y(
RESOLUTION[1] / 2 - 1,
);
let dir = Dir::new(8);
let tri = &TRIANGLES[4];
let (new_pos, new_dir) = world_to_local(pos, dir, RESOLUTION, tri);
assert_eq!(GridPoint3::default().with_x(1).with_y(1), new_pos);
assert_eq!(Dir::new(10), new_dir);
}
#[test]
fn tri_4_to_world() {
let pos = GridPoint3::default().with_x(1).with_y(1);
let dir = Dir::new(10);
let tri = &TRIANGLES[4];
let (new_pos, new_dir) = local_to_world(pos, dir, RESOLUTION, tri);
assert_eq!(
GridPoint3::default().with_x(2).with_y(
RESOLUTION[1] / 2 - 1,
),
new_pos
);
assert_eq!(Dir::new(8), new_dir);
}
}