this repo has no description
1//! By convention, root.zig is the root source file when making a library.
2const std = @import("std");
3
4const PI: comptime_float = std.math.pi;
5const sqrt_3: comptime_float = std.math.sqrt(3.0);
6
7pub const Point = struct { x: f32, y: f32 };
8
9// Axial coordinates: q + r + s = 0 constraint
10// s = -q-r
11pub const Axial = struct {
12 q: i32,
13 r: i32,
14 s: i32,
15
16 pub fn init(q: i32, r: i32) Axial {
17 return .{ .q = q, .r = r, .s = -q - r };
18 }
19
20 pub fn add(self: Axial, other: Axial) Axial {
21 return .{ .q = self.q + other.q, .r = self.r + other.r, .s = self.s + other.s };
22 }
23
24 pub fn sub(self: Axial, other: Axial) Axial {
25 return .{ .q = self.q - other.q, .r = self.r - other.r, .s = self.s - other.s };
26 }
27
28 pub fn neighbor(self: Axial, dir: Direction) Axial {
29 return self.add(direction_vectors[@intFromEnum(dir)]);
30 }
31
32 pub fn toPixel(self: Axial, size: f32) Point {
33 const q: f32 = @floatFromInt(self.q);
34 const r: f32 = @floatFromInt(self.r);
35 return .{
36 .x = size * (1.5 * q),
37 .y = size * (sqrt_3 * (r + q / 2.0)),
38 };
39 }
40
41 // flat-top odd-q
42 pub fn toOffset(self: Axial) Offset {
43 const col = self.q;
44 const row = self.r + @divFloor(self.q - (self.q & 1), 2);
45 return .{ .col = col, .row = row };
46 }
47};
48
49pub const Offset = struct {
50 col: i32,
51 row: i32,
52
53 // flat-top odd-q
54 pub fn toAxial(self: Offset) Axial {
55 const q = self.col;
56 const r = self.row - @divFloor(self.col - (self.col & 1), 2);
57 return Axial.init(q, r);
58 }
59};
60
61const direction_vectors = [6]Axial{
62 .{ .q = 0, .r = -1, .s = 1 }, // top_left
63 .{ .q = 1, .r = -1, .s = 0 }, // top
64 .{ .q = 1, .r = 0, .s = -1 }, // top_right
65 .{ .q = 0, .r = 1, .s = -1 }, // bottom_right
66 .{ .q = -1, .r = 1, .s = 0 }, // bottom
67 .{ .q = -1, .r = 0, .s = 1 }, // bottom_left
68};
69
70pub const HexCell = struct { inner_radius: f32, outer_radius: f32, height: f32, width: f32, center: Point, cubic: Axial };
71pub const Cell = HexCell;
72
73pub const HexDirections = enum { top_left, top, top_right, bottom_right, bottom, bottom_left };
74pub const Direction = HexDirections;
75
76fn calculate_outer_radius(inner_radius: f32) f32 {
77 return 2.0 * inner_radius / sqrt_3;
78}
79fn calculate_inner_radius(outer_radius: f32) f32 {
80 return outer_radius / 2.0 * sqrt_3;
81}
82
83pub fn calculate_hex_corners(center: Point, size: f32, _i: usize) Point {
84 const i: f32 = @floatFromInt(_i);
85 const angle_deg = 60.0 * i;
86 const angle_rad = std.math.degreesToRadians(angle_deg);
87
88 const x_offset: f32 = size * std.math.cos(angle_rad);
89 const y_offset: f32 = size * std.math.sin(angle_rad);
90
91 return Point{ .x = center.x + x_offset, .y = center.y + y_offset };
92}
93
94pub fn new_hex(outer_radius: f32, cubic: Axial) HexCell {
95 const size = outer_radius;
96 const inner = calculate_inner_radius(size);
97 const center = cubic.toPixel(size);
98 return HexCell{ .inner_radius = inner, .outer_radius = size, .height = sqrt_3 * size, .width = 2 * size, .center = center, .cubic = cubic };
99}
100
101pub fn new_hex_at(outer_radius: f32, center: Point) HexCell {
102 const size = outer_radius;
103 const inner = calculate_inner_radius(size);
104 return HexCell{ .inner_radius = inner, .outer_radius = size, .height = sqrt_3 * size, .width = 2 * size, .center = center, .cubic = Axial.init(0, 0) };
105}
106
107pub fn add_hex(base: HexCell, direction: HexDirections) HexCell {
108 const new_cubic = base.cubic.neighbor(direction);
109 return new_hex(base.outer_radius, new_cubic);
110}