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;