spacebox/src/math.cpp

138 lines
4.2 KiB
C++

/* +=======================================================+
____/ \____ /: Open source game framework licensed to freely use, :
\ / / : copy, and modify - created for dank.game :
+==\ ^__^ /==+ : :
: ~/ \~ : : Download at https://open.shampoo.ooo/shampoo/spacebox :
: ~~~~~~~~~~~~ : +=======================================================+
: SPACE ~~~~~ : /
: ~~~~~~~ BOX :/
+=============*/
#include "math.hpp"
glm::vec2 sb::math::angle_to_vector(float angle, float magnitude)
{
return {glm::sin(angle) * magnitude, glm::cos(angle) * magnitude};
}
float sb::math::angle_between(glm::vec2 start, glm::vec2 end)
{
return glm::atan(end.x - start.x, end.y - start.y);
}
float sb::math::angle_difference(float start, float end)
{
return glm::atan(glm::sin(end - start), glm::cos(end - start));
}
float sb::math::angle_ratio(float start, float end)
{
return angle_difference(start, end) / glm::pi<float>();
}
glm::vec2 sb::math::point_on_circle(const glm::vec2& center, float angle, float radius)
{
return center + angle_to_vector(angle, radius);
}
void sb::math::points_on_circle(
std::vector<glm::vec2>& points, int count, float radius, const glm::vec2& center, float offset)
{
float step = glm::two_pi<float>() / count;
for (int ii = 0; ii < count; ii++)
{
points.push_back(point_on_circle(center, radius, ii * step + offset));
}
}
std::vector<glm::vec2> sb::math::points_on_circle(int count, float radius, const glm::vec2& center, float offset)
{
std::vector<glm::vec2> points;
points.reserve(count);
points_on_circle(points, count, radius, center, offset);
return points;
}
std::vector<glm::vec2> sb::math::bezier(const std::vector<glm::vec2>& control, int resolution)
{
std::vector<glm::vec2> points;
points.reserve(resolution);
float b0x = control[0][0];
float b0y = control[0][1];
float b1x = control[1][0];
float b1y = control[1][1];
float b2x = control[2][0];
float b2y = control[2][1];
float b3x = control[3][0];
float b3y = control[3][1];
float ax = -b0x + 3.0f * b1x + -3.0f * b2x + b3x;
float ay = -b0y + 3.0f * b1y + -3.0f * b2y + b3y;
float bx = 3.0f * b0x + -6.0f * b1x + 3.0f * b2x;
float by = 3.0f * b0y + -6.0f * b1y + 3.0f * b2y;
float cx = -3.0f * b0x + 3.0f * b1x;
float cy = -3.0f * b0y + 3.0f * b1y;
float dx = b0x;
float dy = b0y;
float steps = resolution - 1;
float h = 1.0f / steps;
float pointX = dx;
float pointY = dy;
float firstFDX = ax * std::pow(h, 3.0f) + bx * std::pow(h, 2.0f) + cx * h;
float firstFDY = ay * std::pow(h, 3.0f) + by * std::pow(h, 2.0f) + cy * h;
float secondFDX = 6 * ax * std::pow(h, 3.0f) + 2 * bx * std::pow(h, 2.0f);
float secondFDY = 6 * ay * std::pow(h, 3.0f) + 2 * by * std::pow(h, 2.0f);
float thirdFDX = 6 * ax * std::pow(h, 3.0f);
float thirdFDY = 6 * ay * std::pow(h, 3.0f);
points.push_back({pointX, pointY});
for (int ii = 0; ii < steps; ii++)
{
pointX += firstFDX;
pointY += firstFDY;
firstFDX += secondFDX;
firstFDY += secondFDY;
secondFDX += thirdFDX;
secondFDY += thirdFDY;
points.push_back({pointX, pointY});
}
return points;
}
std::string sb::math::random::id(std::size_t length, std::optional<int> seed)
{
/* Mersenne Twister engine */
std::mt19937 generator;
/* Use the submitted seed, or get a random seed if no seed is given. */
if (seed.has_value())
{
generator.seed(seed.value());
}
else
{
std::random_device device;
generator.seed(device());
}
/* List of possible characters in the ID string */
std::string pool { "23456789abcdefghijklmnopqrstuvwxyz" };
/* Limit the possible choices to the indices of the string, so a random character will be chosen each call. */
std::uniform_int_distribution<> distribution(0, pool.size() - 1);
/* Generate an ID string */
std::string id;
for (std::size_t index { 0 }; index < length; index++)
{
id += pool[distribution(generator)];
}
return id;
}