The evenness function can be used to determine which of a given set of numbers in the same range is most evenly distributed across that range. It is related to variance and standard deviation but I don't know of a standard function that measures this exact property. Add setter for table property in Boards class. This allows for use with more than one remote table, using the same object. If the scores field is included in the response from the leaderboard database and is empty, clear the scores in the leaderboard object. This fixes situations where needing to know whether the leaderboard contains results for a range of scores query. Fix order of arguments to read_range function in leaderboards HTTP API.
170 lines
4.9 KiB
C++
170 lines
4.9 KiB
C++
/* +===================================================+
|
|
____/ \____ /: DANK.GAME software library for the development of :
|
|
\ / / : video games and multimedia projects :
|
|
+==\ ^__^ /==+ : :
|
|
: ~/ \~ : : https://dank.game https://open.shampoo.ooo :
|
|
: ~~~~~~~~~~~~ : +===================================================+
|
|
: DANK ~~~~~ : /
|
|
: ~~~~~ WARE :/
|
|
+=============*/
|
|
|
|
#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;
|
|
}
|
|
|
|
float sb::math::loop(float time, float length)
|
|
{
|
|
if (length <= 0.0f) return 0.0f;
|
|
return glm::mod(time, length) / length;
|
|
}
|
|
|
|
float sb::math::ping_pong(float time, float length)
|
|
{
|
|
if (length <= 0.0f) return 0.0f;
|
|
return glm::abs(length - glm::mod(time + length, 2.0f * length)) / length;
|
|
}
|
|
|
|
int sb::math::random::integer(int start, int end, std::optional<std::mt19937*> generator)
|
|
{
|
|
if (start > end) {
|
|
throw std::invalid_argument("The upper bound cannot be less than the lower bound");
|
|
}
|
|
|
|
/* A random unsigned integer */
|
|
std::uint32_t rand;
|
|
|
|
/* Create a Mersenne Twister engine, seeded randomly, if no generator was provided. */
|
|
if (!generator.has_value()) {
|
|
std::mt19937 twister;
|
|
twister.seed(std::random_device()());
|
|
rand = twister();
|
|
}
|
|
else {
|
|
rand = (*(generator.value()))();
|
|
}
|
|
|
|
/* Return a random integer between the given bounds */
|
|
return start + rand % (end + 1 - start);
|
|
}
|
|
|
|
std::string sb::math::random::id(std::size_t length, std::optional<std::uint32_t> 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" };
|
|
|
|
/* Generate an ID string */
|
|
std::string id;
|
|
for (std::size_t index { 0 }; index < length; index++)
|
|
{
|
|
id += pool[random::integer(0, pool.size() - 1, &generator)];
|
|
}
|
|
return id;
|
|
}
|