1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
//! Hexagonal tools lib in rust.
//!
//! > Inspired by this [`RedBlobGames` article](https://www.redblobgames.com/grids/hexagons/implementation.html)
//! > and [Sander Evers](https://sanderevers.github.io/) work
//!
//! This lib allows you to:
//!
//! * Manipulate hexagon coordinates
//! * Generate hexagonal maps with custom layouts and orientation
//! * Generate hexagon meshes (planes or columns)
//!
//! I made the choice to use *Axial Coordinates* for performance and utility
//! reasons, but the [`Hex`] type has conversion utilities with *cubic*,
//! *doubled* and *offset* coordinates.
//!
//! > See the [hexagonal coordinate systems](https://www.redblobgames.com/grids/hexagons/#coordinates)
//!
//! ## Installation
//!
//! Run `cargo add hexx` in your project or add the following line to your
//! `Cargo.toml`:
//!
//! * `hexx = "0.15"`
//!
//! ### Cargo features
//!
//! `hexx` supports serialization and deserialization of most types using [serde](https://github.com/serde-rs/serde),
//! through the `serde` feature gate. To enable it add the following line to
//! your `Cargo.toml`:
//!
//! * `hexx = { version = "0.15", features = ["serde"] }`
//!
//! By default `Hex` uses rust classic memory layout, if you want to use `hexx`
//! through the FFI or have `Hex` be stored without any memory padding, the
//! `packed` feature will make `Hex` `repr(C)`. To enable this behaviour add the
//! following line to your `Cargo.toml`:
//!
//! * `hexx = { version = "0.15", features = ["packed"] }`
//!
//! `hexx` supports [Bevy Reflection](https://docs.rs/bevy_reflect/latest/bevy_reflect) through the
//! `bevy_reflect` feature. To enable it add the following line to your
//! `Cargo.toml`:
//!
//! * `hexx = { version = "0.15", features = ["bevy_reflect"] }`
//!
//! ## Features
//!
//! `hexx` provides the [`Hex`] coordinates with:
//!
//! * Distances
//! * Neighbors and directions
//! * Lines
//! * Ranges
//! * Rings
//! * Edges
//! * Wedges
//! * Spirals
//! * Rotation
//! * Symmetry
//! * Vector operations
//! * Conversions to other coordinate systems:
//!     * Cubic coordinates
//!     * Offset coordinates
//!     * Doubled coordinates
//!     * Hexmod coordinates
//! * Multiple hex resolution
//!
//! ## Basic usage
//!
//!```rust
//! use hexx::*;
//!
//! // Declare points in hexagonal spaces
//! let point_a = hex(10, -5); // Equivalent of `Hex::new(10, -5)`
//! let point_b = hex(-8, 15);
//! // Find distance between them
//! let dist = point_a.unsigned_distance_to(point_b);
//! // Compute a line between points
//! let line: Vec<Hex> = point_a.line_to(point_b).collect();
//! // Compute a ring from `point_a` containing `point_b`
//! let ring: Vec<Hex> = point_a.ring(dist).collect();
//! // Rotate `point_b` around `point_a` by 2 times 60 degrees clockwise
//! let rotated = point_b.rotate_cw_around(point_a, 2);
//! // Find the direction between the two points
//! let dir_a = point_a.main_direction_to(point_b);
//! let dir_b = point_b.main_direction_to(point_a);
//! assert!(dir_a == -dir_b);
//! // Compute a wedge from `point_a` to `point_b`
//! let wedge = point_a.wedge_to(point_b);
//! // Get the average value of the wedge
//! let avg = wedge.average();
//! ```
//!
//! ## Layout usage
//!
//! [`HexLayout`] is the bridge between your world/screen/pixel coordinate
//! system and the hexagonal coordinates system.
//!
//!```rust
//! use hexx::*;
//!
//! // Define your layout
//! let layout = HexLayout {
//!     hex_size: Vec2::new(1.0, 1.0),
//!     orientation: HexOrientation::Flat,
//!     ..Default::default()
//! };
//! // Get the hex coordinate at the world position `world_pos`.
//! let world_pos = Vec2::new(53.52, 189.28);
//! let point = layout.world_pos_to_hex(world_pos);
//! // Get the world position of `point`
//! let point = hex(123, 45);
//! let world_pos = layout.hex_to_world_pos(point);
//! ```
//!
//! ## Wrapping
//!
//! [`HexBounds`] defines a bounding hexagon around a center coordinate.
//! It can be used for boundary and interesection checks but also for wrapping
//! coordinates.
//! Coordinate wrapping transform a point outside of the bounds to a point
//! inside. This allows for seamless or repeating [wraparound](https://www.redblobgames.com/grids/hexagons/#wraparound) maps.
//!
//! ```rust
//! use hexx::*;
//!
//! let center = hex(23, -45);
//! let radius = 5;
//! let bounds = HexBounds::new(center, radius);
//! let outside_coord = hex(12345, 98765);
//! assert!(!bounds.is_in_bounds(outside_coord));
//! let wrapped_coord = bounds.wrap(outside_coord);
//! assert!(bounds.is_in_bounds(wrapped_coord));
//! ```
//!
//! ## Resolutions and chunks
//!
//! [`Hex`] support multi-resolution coordinates.
//! In practice this means that you may convert a coordinate to a different
//! resolution:
//!
//! * To a lower resolution, meaning retrieving a *parent* coordinate
//! * to a higher resolution, meaning retrieving the center *child* coordinate
//!
//! Resolutions are abstract, the only useful information is the resolution
//! **radius**.
//!
//! For example, if you use a big grid, with a radius of a 100, you might want
//! to split that grid evenly in larger hexagons containing a 10 radius of
//! coordinates and maybe do operations locally inside of these chunks.
//!
//! So instead of using a big range directly:
//!
//! ```rust
//! use hexx::*;
//!
//! const MAP_RADIUS: u32 = 100;
//!
//! // Our big grid with hundreds of hexagons
//! let big_grid = Hex::ZERO.range(MAP_RADIUS);
//! ```
//!
//! You may define a smaller grid you will then divide to a higher resolution
//!
//! ```rust
//! use hexx::*;
//!
//! const CHUNK_RADIUS: u32 = 10;
//! const MAP_RADIUS: u32 = 20;
//!
//! let chunks = Hex::ZERO.range(MAP_RADIUS);
//! for chunk in chunks {
//!     // We can retrieve the center of that chunk by increasing the resolution
//!     let center = chunk.to_higher_res(CHUNK_RADIUS);
//!     // And retrieve the other coordinates in the chunk
//!     let children = center.range(CHUNK_RADIUS);
//!     // We can retrieve the chunk coordinates from any coordinate..
//!     for coord in children {
//!         // .. by reducing the resolution
//!         assert_eq!(coord.to_lower_res(CHUNK_RADIUS), chunk);
//!     }
//! }
//! ```
//!
//! An other usage could be to draw an infinite hex grid, with different
//! resolutions displayed, dynamically changing according to user zoom level.
//!
//! ## Usage in [Bevy](https://bevyengine.org/)
//!
//! If you want to generate 3D hexagonal mesh and use it in
//! [bevy](bevyengine.org) you may do it this way:
//!
//!```rust
//! use bevy::{
//!     prelude::Mesh,
//!     render::{
//!         mesh::Indices, render_asset::RenderAssetUsages, render_resource::PrimitiveTopology,
//!     },
//! };
//! use hexx::MeshInfo;
//!
//! pub fn hexagonal_plane(mesh_info: MeshInfo) -> Mesh {
//!     Mesh::new(
//!         PrimitiveTopology::TriangleList,
//!         // Means you won't edit the mesh afterwards, check bevy docs for more information
//!         RenderAssetUsages::RENDER_WORLD,
//!     )
//!     .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices)
//!     .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals)
//!     .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs)
//!     .with_inserted_indices(Indices::U16(mesh_info.indices))
//! }
//! ```
//!
//! The [`MeshInfo`] can be produced from [`PlaneMeshBuilder`] or
//! [`ColumnMeshBuilder`]
#![forbid(unsafe_code)]
#![warn(clippy::nursery, clippy::pedantic, clippy::cargo, missing_docs)]
#![allow(clippy::module_name_repetitions, clippy::multiple_crate_versions)]
/// Non exhaustive collection of classic algorithms.
#[cfg(feature = "algorithms")]
pub mod algorithms;
/// Hexagonal range bounds module
pub mod bounds;
/// Hexagonal coordinates conversion module
pub mod conversions;
/// Hexagonal directions module
pub mod direction;
/// Hexagonal coordinates module
pub mod hex;
/// Hexagonal layout module
pub mod layout;
#[cfg(feature = "mesh")]
/// Mesh generation utils module
pub mod mesh;
/// Hexagon oritentation module
pub mod orientation;
/// Map shapes generation functions
pub mod shapes;

#[doc(inline)]
pub use bounds::HexBounds;
#[doc(inline)]
pub use conversions::*;
#[doc(inline)]
pub use direction::*;
#[doc(hidden)]
pub use glam::{IVec2, IVec3, Quat, Vec2, Vec3};
#[doc(inline)]
pub use hex::{hex, Hex, HexIterExt};
#[doc(inline)]
pub use layout::HexLayout;
#[cfg(feature = "mesh")]
pub use mesh::*;
#[doc(inline)]
pub use orientation::HexOrientation;