extern crate nalgebra as na;
use std::char;
use super::svg::node::element;
use super::svg::node::element::path::Data;
use draw::consts::*;
use game;
use game::Orientation;
use tile;
pub fn scale(map: &game::Map) -> f64 {
map.scale * PPCM
}
fn draw_hex(center: na::Vector2<f64>,
info: &game::Map) -> element::Path {
let basis = get_basis(&info.orientation);
let points = [
na::Vector3::new(-1.0, 0.0, 0.0),
na::Vector3::new( 0.0, 0.0, 1.0),
na::Vector3::new( 0.0, 1.0, 0.0),
na::Vector3::new( 1.0, 0.0, 0.0),
na::Vector3::new( 0.0, 0.0, -1.0),
na::Vector3::new( 0.0, -1.0, 0.0),
];
let data = Data::new()
.move_to(point_to_tuple(scale(&info) * (basis * points[0] + center)))
.line_to(point_to_tuple(scale(&info) * (basis * points[1] + center)))
.line_to(point_to_tuple(scale(&info) * (basis * points[2] + center)))
.line_to(point_to_tuple(scale(&info) * (basis * points[3] + center)))
.line_to(point_to_tuple(scale(&info) * (basis * points[4] + center)))
.line_to(point_to_tuple(scale(&info) * (basis * points[5] + center)))
.close();
element::Path::new()
.set("d", data)
}
pub fn draw_hex_edge(center: na::Vector2<f64>,
info: &game::Map) -> element::Path {
draw_hex(center, info)
.set("fill", "none")
.set("stroke", "black")
.set("stroke-width", LINE_WIDTH * scale(&info))
}
pub fn draw_hex_background(center: na::Vector2<f64>,
info: &game::Map,
color: tile::colors::Color) -> element::Path {
draw_hex(center, info)
.set("fill", color.value())
.set("stroke", "none")
}
pub fn draw_path_helper(path: &tile::Path,
center: &na::Vector2<f64>,
info: &game::Map,
rotation: &f64) -> element::Path {
let basis = get_basis(&info.orientation);
let rot = rotate(rotation);
let (start_x, start_y) = point_to_tuple(
scale(&info) * (rot * basis * path.start() + center));
let (end_x, end_y) = point_to_tuple(
scale(&info) * (rot * basis * path.end() + center));
let control1 = match &path.start_control {
&None => path.radius() * C * rot * basis * path.start() + center,
&Some(ref point) => rot * basis * point.as_vector() + center,
};
let control2 = match &path.end_control {
&None => path.radius() * C * rot * basis * path.end() + center,
&Some(ref point) => rot * basis * point.as_vector() + center,
};
let (x1, y1) = point_to_tuple(scale(&info) * control1);
let (x2, y2) = point_to_tuple(scale(&info) * control2);
let data = Data::new()
.move_to((start_x, start_y))
.cubic_curve_to((x1, y1, x2, y2, end_x, end_y));
element::Path::new()
.set("d", data.clone())
.set("fill", "none")
}
pub fn draw_city_circle(pos: &na::Vector2<f64>,
info: &game::Map) -> element::Circle {
draw_circle(pos, TOKEN_SIZE * scale(&info), "white", "black",
LINE_WIDTH * scale(&info))
}
pub fn city_circle_pos(city: &tile::City,
circle: u32,
center: &na::Vector2<f64>,
info: &game::Map,
rotation: &f64) -> na::Vector2<f64> {
let basis = get_basis(&info.orientation);
let rot = rotate(rotation);
let pos = rot * basis * city.position() + center;
let pos = match city.circles {
1 => pos,
2 => match circle {
0 => pos - rot * na::Vector2::new(TOKEN_SIZE, 0.0),
1 => pos + rot * na::Vector2::new(TOKEN_SIZE, 0.0),
n => panic!("Illegal circle id {} for city of size 2", n),
},
3 => match circle {
0 => pos + na::Vector2::new(0.0, -2.0 * TOKEN_SIZE/3.0_f64.sqrt()),
1 => pos + na::Vector2::new(-TOKEN_SIZE,
TOKEN_SIZE / 3.0_f64.sqrt()),
2 => pos + na::Vector2::new(TOKEN_SIZE, TOKEN_SIZE/3.0_f64.sqrt()),
n => panic!("Illegal circle id {} for city of size 3", n),
},
4 => match circle {
0 => pos + na::Vector2::new(-TOKEN_SIZE, -TOKEN_SIZE),
1 => pos + na::Vector2::new(-TOKEN_SIZE, TOKEN_SIZE),
2 => pos + na::Vector2::new( TOKEN_SIZE, -TOKEN_SIZE),
3 => pos + na::Vector2::new( TOKEN_SIZE, TOKEN_SIZE),
n => panic!("Illegal circle id {} for city of size 3", n),
}
n => panic!("Cities of {} not supported!", n),
};
pos * scale(&info)
}
pub fn draw_circle(pos: &na::Vector2<f64>, radius: f64, fill: &str,
stroke_color: &str, stroke_width: f64) -> element::Circle {
element::Circle::new()
.set("cx", pos.x)
.set("cy", pos.y)
.set("r", radius)
.set("fill", fill)
.set("stroke", stroke_color)
.set("stroke-width", stroke_width)
}
pub fn get_basis(orientation: &Orientation) -> na::Matrix2x3<f64> {
match orientation {
&Orientation::Horizontal => na::Matrix2x3::from_columns(&[
na::Vector2::new( 1.0, 0.0),
na::Vector2::new( 0.5, -0.5 * 3.0_f64.sqrt()),
na::Vector2::new(-0.5, -0.5 * 3.0_f64.sqrt())
]),
&Orientation::Vertical => na::Matrix2x3::from_columns(&[
na::Vector2::new(0.5 * 3.0_f64.sqrt(), -0.5),
na::Vector2::new(0.0, -1.0),
na::Vector2::new(-0.5 * 3.0_f64.sqrt(), -0.5),
]),
}
}
pub fn rotate(theta: &f64) -> na::Matrix2<f64> {
na::Matrix2::new(theta.cos(), -theta.sin(), theta.sin(), theta.cos())
}
pub fn point_to_tuple(p: na::Vector2<f64>) -> (f64, f64) {
(p.x, p.y)
}
pub fn number_to_letter(n: u32) -> String {
match n {
n if n < 26 =>
char::from_digit(n + 10, 36).unwrap().to_string().to_uppercase(),
n => number_to_letter(n / 26 - 1) + &number_to_letter(n % 26),
}
}