diff --git a/include/fggl/grid/hexagon.hpp b/include/fggl/grid/hexagon.hpp new file mode 100644 index 0000000000000000000000000000000000000000..be211071d673c4230351b45cee928c08eca17050 --- /dev/null +++ b/include/fggl/grid/hexagon.hpp @@ -0,0 +1,143 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 27/11/22. +// + +#ifndef FGGL_GRID_HEX_HPP +#define FGGL_GRID_HEX_HPP + +#include <array> +#include <vector> +#include <cmath> + +#include <fggl/math/fmath.hpp> + +/** + * Hexagonal Grid Implementation. + * Based largely off Amit's incredible grid documentation. + */ +namespace fggl::grid { + + enum class HexDirPointy { + RIGHT = 0, TOP_RIGHT = 1, TOP_LEFT = 2, LEFT = 3, BOTTOM_LEFT = 4, BOTTOM_RIGHT = 5 + }; + + enum class HexDirFlat { + BOTTOM_RIGHT = 0, TOP_RIGHT = 1, TOP = 2, TOP_LEFT = 3, BOTTOM_LEFT = 4, BOTTOM = 5 + }; + + constexpr std::array< std::array<int, 2>, 6> HEX_DIRECTIONS {{ + {1, 0}, {1, -1}, {0, 1}, + {-1, 0}, {-1, 1}, {0, 1} + }}; + + constexpr std::array< std::array<int, 2>, 6> HEX_DIAGONALS {{ + {2, -1}, {+1, -2}, {-1, -1}, + {-2, 1}, {-1, 2}, {1, 1} + }}; + + template<typename T> + struct HexPointT { + + constexpr HexPointT(T q, T r) : m_pos({q, r}) {} + constexpr explicit HexPointT(const std::array<int, 2>& pos) : m_pos(pos[0], pos[1]) {} + + inline T q() const { + return m_pos[0]; + } + + inline T r() const { + return m_pos[1]; + } + + inline T s() const { + return -m_pos[0]-m_pos[1]; + } + + inline HexPointT neighbour(HexDirPointy dir) { + return this + HexPointT<T>(HEX_DIRECTIONS[(int)dir]); + } + + inline HexPointT neighbour(HexDirFlat dir) { + return this + HexPointT<T>(HEX_DIAGONALS[(int)dir]); + } + + HexPointT operator+(const HexPointT<T>& other) const { + return { m_pos[0] + other.m_pos[0], m_pos[1] + other.m_pos[1] }; + } + + HexPointT operator-(const HexPointT<T>& other) const { + return { m_pos[0] - other.m_pos[0], m_pos[1] - other.m_pos[1] }; + } + + T distance(const HexPointT& other) const { + auto vec = *this - other; + return ( + ::abs(vec.q()) + + ::abs(vec.q() - vec.r()) + + ::abs(vec.r()) / 2 + ); + } + + std::vector<HexPointT<T>> hexesInRange(int range) const { + std::vector<HexPointT<T>> results; + for ( auto q = -range; q <= range; ++q ) { + auto stopCount = std::min(range, -q+range); + for ( auto r = std::max(-range, -q-range); r <= stopCount; ++r ) { + results.push_back( this + HexPointT<T>(q, r) ); + } + } + return results; + } + + private: + std::array<T, 2> m_pos; + }; + + using FloatHex = HexPointT<float>; + using IntHex = HexPointT<int>; + + template<typename T> + constexpr FloatHex hexLerp(const HexPointT<T>& start, const HexPointT<T>& end, float t) { + return { + math::lerp(start.q(), end.q(), t), + math::lerp(start.r(), end.r(), t) + }; + } + + constexpr IntHex round(const FloatHex& hex) { + // see https://observablehq.com/@jrus/hexround for original JS implementation + float xGrid = std::round( hex.r() ); + float yGrid = std::round( hex.q() ); + float x = hex.q() - xGrid; + float y = hex.r() - yGrid; + auto dx = std::round(x + 0.5F*y) * (x*x >= y*y); + auto dy = std::round(y + 0.5F*x) * (x*x < y*y); + return { (int)(xGrid + dx), (int)(yGrid + dy) }; + } + + std::vector<IntHex> lineTo(const IntHex& start, const IntHex& end) { + int distance = start.distance(end); + std::vector<IntHex> line; + for (auto i=0; i < distance; ++i) { + line.push_back( round(hexLerp(start, end, 1.0F/distance * i)) ); + } + return line; + } + +} // namespace fggl::grid + +#endif //FGGL_GRID_HEX_HPP diff --git a/include/fggl/math/fmath.hpp b/include/fggl/math/fmath.hpp index 8deee12ab1d0368bfe46d711af86456e400dcd35..f6683b62c072e05641d05ee87ac0d6b604de8a0d 100644 --- a/include/fggl/math/fmath.hpp +++ b/include/fggl/math/fmath.hpp @@ -84,6 +84,14 @@ namespace fggl::math { return valueOrMin > max ? max : valueOrMin; } + constexpr float lerpImprecise(float start, float end, float t) { + return start + t * (end - start); + } + + constexpr float lerp(float start, float end, float t) { + return (1 - t) * start + t * end; + } + } // namespace fggl::math