282 lines
10 KiB
C++
282 lines
10 KiB
C++
#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/2,y=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;
|
||
}
|
||
}; |