SwitchGame/source/Tool/Math.h

282 lines
10 KiB
C
Raw Permalink Normal View History

2025-09-18 15:21:43 +08:00
#pragma once
#include <vector>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <stdexcept>
class Math
{
private:
/* data */
public:
Math(/* args */) = default;
~Math() = default;
public:
static void InitRandomSeed()
{
static bool seeded = false;
if (!seeded)
{
srand(static_cast<unsigned int>(time(nullptr)));
seeded = true;
}
}
// 1. 获取X轴方向0目标在左侧1目标在右侧
static int getDirectionToTargetX(float objX, float x)
{
return (objX > x) ? 0 : 1;
}
// 2. 生成[Min, Max]范围内的随机整数(左闭右闭)
static int Rand(int Min, int Max)
{
InitRandomSeed(); // 确保随机数种子已初始化
if (Min > Max)
{
throw std::invalid_argument("Rand: Min must be less than or equal to Max");
}
// 计算随机数范围:(Max - Min + 1)个可能值
int range = Max - Min + 1;
// rand()返回[0, RAND_MAX],通过取模和偏移实现范围映射
return Min + (rand() % range);
}
// 3. 从数组中随机获取一个元素(支持任意可索引容器)
template <typename T>
static T GetRandomElementFromArray(const std::vector<T> &arr)
{
if (arr.empty())
{
throw std::invalid_argument("GetRandomElementFromArray: Array is empty");
}
int randomIndex = Rand(0, static_cast<int>(arr.size()) - 1);
return arr[randomIndex];
}
// 5. 根据方向计算偏移后的X坐标
static float GetDistancePos(float startX, int direction, float offsetX)
{
return (direction == 0) ? (startX - offsetX) : (startX + offsetX);
}
// 6. 通过两点坐标计算旋转角度(预留实现,需根据具体需求补充)
static float getRorateAngleByCurrentPos(float x1, float y1, float z1, float x2, float y2, float z2)
{
// 示例实现计算X-Z平面内的角度可根据需求调整为3D角度
float dx = x2 - x1;
float dz = z2 - z1;
// atan2(dz, dx)返回与X轴正方向的夹角弧度范围[-π, π]
return std::atan2(dz, dx);
}
// 8. 标准抛物线计算y = a(x - c/2)² + b开口向下
static float sq_Parabola(float x, float b, float c)
{
if (c == 0)
{
throw std::invalid_argument("sq_Parabola: c cannot be zero");
}
// 计算抛物线系数a确保顶点在x=c/2y=b
float a = (-4.0f * b) / (c * c);
return a * (x - c / 2.0f) * (x - c / 2.0f) + b;
}
// 9. 计算2D平面两点距离Y轴权重0.29,用于透视校正)
static float Get2D_Distance(float x1, float y1, float x2, float y2)
{
float offsetX = x1 - x2;
float offsetY = (y1 - y2) * 0.29f;
// 勾股定理计算距离
return std::sqrt(offsetX * offsetX + offsetY * offsetY);
}
// 10. 判断角度是否在[startA, endA]形成的锐角范围内(角度单位:度)
static bool CheckAngleIsInArea(float judge, float startA, float endA)
{
// 步骤1将角度标准化到[0, 360)范围
auto normalizeAngle = [](float angle)
{
angle = std::fmod(angle, 360.0f);
return (angle < 0) ? (angle + 360.0f) : angle;
};
startA = normalizeAngle(startA);
endA = normalizeAngle(endA);
judge = normalizeAngle(judge);
// 特殊情况范围跨0度如startA=350°endA=10°
if (startA > 270.0f && startA < 360.0f && endA > 0.0f && endA < 90.0f)
{
return (judge >= startA && judge <= 360.0f) || (judge >= 0.0f && judge <= endA);
}
// 普通情况范围不跨0度
else
{
// 处理startA > endA的正常范围如startA=30°endA=60°
if (startA > endA)
{
std::swap(startA, endA);
}
return (judge >= startA && judge <= endA);
}
}
// 11. 弧度转角度
static float toDegree(float radian)
{
return radian * 57.2957795f; // 180/π ≈ 57.2957795
}
// 12. 角度转弧度
static float toRadian(float degree)
{
return degree * 0.0174532925f; // π/180 ≈ 0.0174532925
}
// 13. 判断点是否在立方体内(立方体由对角点定义)
static bool pointIsInCubeArea(float px, float py, float pz,
float startX, float startY, float startZ,
float endX, float endY, float endZ)
{
// 计算立方体中心点和半边长
float cubeCenterX = (startX + endX) / 2.0f;
float cubeXLen = std::fabs(startX - endX) / 2.0f;
float cubeCenterY = (startY + endY) / 2.0f;
float cubeYLen = std::fabs(startY - endY) / 2.0f;
float cubeCenterZ = (startZ + endZ) / 2.0f;
float cubeZLen = std::fabs(startZ - endZ) / 2.0f;
// 点到各轴中心点的距离 ≤ 半边长 → 在立方体内
return (std::fabs(px - cubeCenterX) <= cubeXLen + 1e-6f) &&
(std::fabs(py - cubeCenterY) <= cubeYLen + 1e-6f) &&
(std::fabs(pz - cubeCenterZ) <= cubeZLen + 1e-6f);
}
// 14. 立方体与立方体碰撞检测(基于顶点和中心点判断)
static bool CubeAndCubeCollection(float c1StartX, float c1StartY, float c1StartZ,
float c1EndX, float c1EndY, float c1EndZ,
float c2StartX, float c2StartY, float c2StartZ,
float c2EndX, float c2EndY, float c2EndZ)
{
// 优化说明原Squirrel代码判断过多冗余点此处保留核心顶点+中心点判断
const std::vector<std::tuple<float, float, float>> c1Points = {
// 立方体1的8个顶点
{c1StartX, c1StartY, c1StartZ},
{c1EndX, c1StartY, c1StartZ},
{c1StartX, c1EndY, c1StartZ},
{c1EndX, c1EndY, c1StartZ},
{c1StartX, c1StartY, c1EndZ},
{c1EndX, c1StartY, c1EndZ},
{c1StartX, c1EndY, c1EndZ},
{c1EndX, c1EndY, c1EndZ},
// 立方体1的中心点
{(c1StartX + c1EndX) / 2, (c1StartY + c1EndY) / 2, (c1StartZ + c1EndZ) / 2}};
const std::vector<std::tuple<float, float, float>> c2Points = {
// 立方体2的8个顶点
{c2StartX, c2StartY, c2StartZ},
{c2EndX, c2StartY, c2StartZ},
{c2StartX, c2EndY, c2StartZ},
{c2EndX, c2EndY, c2StartZ},
{c2StartX, c2StartY, c2EndZ},
{c2EndX, c2StartY, c2EndZ},
{c2StartX, c2EndY, c2EndZ},
{c2EndX, c2EndY, c2EndZ},
// 立方体2的中心点
{(c2StartX + c2EndX) / 2, (c2StartY + c2EndY) / 2, (c2StartZ + c2EndZ) / 2}};
// 检查立方体1的点是否在立方体2内
for (const auto &[x, y, z] : c1Points)
{
if (pointIsInCubeArea(x, y, z, c2StartX, c2StartY, c2StartZ, c2EndX, c2EndY, c2EndZ))
{
return true;
}
}
// 检查立方体2的点是否在立方体1内
for (const auto &[x, y, z] : c2Points)
{
if (pointIsInCubeArea(x, y, z, c1StartX, c1StartY, c1StartZ, c1EndX, c1EndY, c1EndZ))
{
return true;
}
}
return false;
}
// 15. 计算三角形面积(叉乘法,避免开方,效率更高)
static float get3PointArea(float x1, float y1, float x2, float y2, float x3, float y3)
{
// 面积公式0.5 * |x1(y2-y3) + x2(y3-y1) + x3(y1-y2)|
return 0.5f * std::fabs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
}
// 16. 计算四边形面积(拆分为两个三角形面积之和)
static float get4PointArea(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
{
// 四边形拆分为:(x1,y1)-(x2,y2)-(x3,y3) 和 (x2,y2)-(x3,y3)-(x4,y4)
float area1 = get3PointArea(x1, y1, x2, y2, x3, y3);
float area2 = get3PointArea(x2, y2, x3, y3, x4, y4);
return area1 + area2;
}
// 17. 判断点是否在四边形内(面积比较法,要求四边形顶点按顺序排列)
static bool pointIsIn4PointArea(float px, float py,
float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4)
{
const float eps = 10.0f; // 容差原Squirrel代码定义为10.0
float totalArea = get4PointArea(x1, y1, x2, y2, x3, y3, x4, y4);
// 点与四边形各边组成的4个三角形面积之和
float sumArea = get3PointArea(x1, y1, x2, y2, px, py) +
get3PointArea(x2, y2, x3, y3, px, py) +
get3PointArea(x3, y3, x4, y4, px, py) +
get3PointArea(x4, y4, x1, y1, px, py);
// 面积差在容差范围内 → 点在四边形内
return std::fabs(totalArea - sumArea) < eps;
}
// 18. 判断点是否在矩形内(矩形由坐标数组定义,格式:[x, y, width, height]
static bool PointIsInSquare(float x1, float y1, const std::vector<float> &SquareArr)
{
if (SquareArr.size() != 4)
{
throw std::invalid_argument("PointIsInSquare: SquareArr must have 4 elements (x, y, width, height)");
}
float sqX = SquareArr[0];
float sqY = SquareArr[1];
float sqWidth = SquareArr[2];
float sqHeight = SquareArr[3];
// 点的X在[sqX, sqX+width]Y在[sqY, sqY+height] → 在矩形内
return (x1 >= sqX - 1e-6f) && (x1 <= sqX + sqWidth + 1e-6f) &&
(y1 >= sqY - 1e-6f) && (y1 <= sqY + sqHeight + 1e-6f);
}
static float getUniformVelocity(float sv, float ev, float currentRate, float maxRate)
{
// 避免除零错误
if (maxRate <= 0.0f)
{
throw std::invalid_argument("maxRate must be greater than 0");
}
// 计算当前进度比例0.0到1.0之间)
float rate = currentRate / maxRate;
// 限制比例在[0, 1]范围内,避免超出边界
rate = std::clamp(rate, 0.0f, 1.0f);
// 计算变化量并返回当前值
float varyValue = ev - sv;
return sv + varyValue * rate;
}
};