SwitchGame/source/Tool/Math.h

282 lines
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
};