mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-14 15:33:26 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e1990942b |
@@ -5,7 +5,7 @@ project(omath VERSION 3.0.2 LANGUAGES CXX)
|
|||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
|
||||||
option(OMATH_BUILD_TESTS "Build unit tests" OFF)
|
option(OMATH_BUILD_TESTS "Build unit tests" ${PROJECT_IS_TOP_LEVEL})
|
||||||
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
|
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
|
||||||
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
|
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
|
||||||
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
|
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 8/3/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "omath/engines/source_engine/formulas.hpp"
|
||||||
|
#include "omath/projectile_prediction/projectile.hpp"
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace omath::projectile_prediction::traits
|
||||||
|
{
|
||||||
|
class SourceEngineTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
constexpr static Vector3<float> predict_projectile_position(const Projectile& projectile, const float pitch,
|
||||||
|
const float yaw, const float time,
|
||||||
|
const float gravity) noexcept
|
||||||
|
{
|
||||||
|
auto current_pos = projectile.m_origin
|
||||||
|
+ source_engine::forward_vector({source_engine::PitchAngle::from_degrees(-pitch),
|
||||||
|
source_engine::YawAngle::from_degrees(yaw),
|
||||||
|
source_engine::RollAngle::from_degrees(0)})
|
||||||
|
* projectile.m_launch_speed * time;
|
||||||
|
current_pos.z -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f;
|
||||||
|
|
||||||
|
return current_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_projectile_reached_target(const Vector3<float>& target_position,
|
||||||
|
const Projectile& projectile, const float pitch,
|
||||||
|
const float time, const float gravity,
|
||||||
|
const float tolerance) noexcept
|
||||||
|
{
|
||||||
|
const auto yaw = projectile.m_origin.view_angle_to(target_position).y;
|
||||||
|
const auto projectile_position = predict_projectile_position(projectile, pitch, yaw, time, gravity);
|
||||||
|
|
||||||
|
return projectile_position.distance_to(target_position) <= tolerance;
|
||||||
|
}
|
||||||
|
[[nodiscard]]
|
||||||
|
static float calc_vector_2d_distance(const Vector3<float>& delta)
|
||||||
|
{
|
||||||
|
return std::sqrt(delta.x * delta.x + delta.y * delta.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr static float get_vector_height_coordinate(const Vector3<float>& vec)
|
||||||
|
{
|
||||||
|
return vec.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static Vector3<float> calc_viewpoint_from_angles(const Projectile& projectile,
|
||||||
|
Vector3<float> predicted_target_position,
|
||||||
|
const std::optional<float> projectile_pitch)
|
||||||
|
{
|
||||||
|
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
|
||||||
|
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
|
||||||
|
|
||||||
|
return {predicted_target_position.x, predicted_target_position.y, projectile.m_origin.z + height};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace omath::projectile_prediction::traits
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "engine_traits/source_engine_trait.hpp"
|
||||||
#include "omath/projectile_prediction/proj_pred_engine.hpp"
|
#include "omath/projectile_prediction/proj_pred_engine.hpp"
|
||||||
#include "omath/projectile_prediction/projectile.hpp"
|
#include "omath/projectile_prediction/projectile.hpp"
|
||||||
#include "omath/projectile_prediction/target.hpp"
|
#include "omath/projectile_prediction/target.hpp"
|
||||||
@@ -13,15 +14,40 @@
|
|||||||
namespace omath::projectile_prediction
|
namespace omath::projectile_prediction
|
||||||
{
|
{
|
||||||
// ReSharper disable once CppClassCanBeFinal
|
// ReSharper disable once CppClassCanBeFinal
|
||||||
|
template<class EngineTrait = traits::SourceEngineTrait>
|
||||||
class ProjPredEngineLegacy : public ProjPredEngineInterface
|
class ProjPredEngineLegacy : public ProjPredEngineInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ProjPredEngineLegacy(float gravity_constant, float simulation_time_step, float maximum_simulation_time,
|
explicit ProjPredEngineLegacy(const float gravity_constant, const float simulation_time_step,
|
||||||
float distance_tolerance);
|
const float maximum_simulation_time, const float distance_tolerance)
|
||||||
|
: m_gravity_constant(gravity_constant), m_simulation_time_step(simulation_time_step),
|
||||||
|
m_maximum_simulation_time(maximum_simulation_time), m_distance_tolerance(distance_tolerance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::optional<Vector3<float>> maybe_calculate_aim_point(const Projectile& projectile,
|
std::optional<Vector3<float>> maybe_calculate_aim_point(const Projectile& projectile,
|
||||||
const Target& target) const override;
|
const Target& target) const override
|
||||||
|
{
|
||||||
|
for (float time = 0.f; time < m_maximum_simulation_time; time += m_simulation_time_step)
|
||||||
|
{
|
||||||
|
const auto predicted_target_position = target.predict_position(time, m_gravity_constant);
|
||||||
|
|
||||||
|
const auto projectile_pitch =
|
||||||
|
maybe_calculate_projectile_launch_pitch_angle(projectile, predicted_target_position);
|
||||||
|
|
||||||
|
if (!projectile_pitch.has_value()) [[unlikely]]
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!EngineTrait::is_projectile_reached_target(predicted_target_position, projectile,
|
||||||
|
projectile_pitch.value(), time, m_gravity_constant,
|
||||||
|
m_distance_tolerance))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return EngineTrait::calc_viewpoint_from_angles(projectile, predicted_target_position, projectile_pitch);
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const float m_gravity_constant;
|
const float m_gravity_constant;
|
||||||
@@ -44,30 +70,27 @@ namespace omath::projectile_prediction
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::optional<float>
|
std::optional<float>
|
||||||
maybe_calculate_projectile_launch_pitch_angle(const Projectile& projectile,
|
maybe_calculate_projectile_launch_pitch_angle(const Projectile& projectile,
|
||||||
const Vector3<float>& target_position) const noexcept;
|
const Vector3<float>& target_position) const noexcept
|
||||||
|
{
|
||||||
|
const auto bullet_gravity = m_gravity_constant * projectile.m_gravity_scale;
|
||||||
|
const auto delta = target_position - projectile.m_origin;
|
||||||
|
|
||||||
[[nodiscard]]
|
const auto distance2d = EngineTrait::calc_vector_2d_distance(delta);
|
||||||
bool is_projectile_reached_target(const Vector3<float>& target_position, const Projectile& projectile,
|
const auto distance2d_sqr = distance2d * distance2d;
|
||||||
float pitch, float time) const noexcept;
|
const auto launch_speed_sqr = projectile.m_launch_speed * projectile.m_launch_speed;
|
||||||
|
|
||||||
protected:
|
float root = launch_speed_sqr * launch_speed_sqr
|
||||||
// NOTE: Override this if you need to use engine with different coordinate system
|
- bullet_gravity
|
||||||
// Like where Z is not height coordinate
|
* (bullet_gravity * distance2d_sqr
|
||||||
// ===============================================================================================
|
+ 2.0f * EngineTrait::get_vector_height_coordinate(delta) * launch_speed_sqr);
|
||||||
[[nodiscard]]
|
|
||||||
virtual float calc_vector_2d_distance(const Vector3<float>& delta) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
if (root < 0.0f) [[unlikely]]
|
||||||
virtual float get_vector_height_coordinate(const Vector3<float>& vec) const;
|
return std::nullopt;
|
||||||
|
|
||||||
[[nodiscard]]
|
root = std::sqrt(root);
|
||||||
virtual Vector3<float> calc_viewpoint_from_angles(const Projectile& projectile,
|
const float angle = std::atan((launch_speed_sqr - root) / (bullet_gravity * distance2d));
|
||||||
Vector3<float> predicted_target_position,
|
|
||||||
std::optional<float> projectile_pitch) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
return angles::radians_to_degrees(angle);
|
||||||
virtual Vector3<float> predict_projectile_position(const Projectile& projectile, float pitch, float yaw,
|
}
|
||||||
float time, float gravity) const;
|
|
||||||
// ===============================================================================================
|
|
||||||
};
|
};
|
||||||
} // namespace omath::projectile_prediction
|
} // namespace omath::projectile_prediction
|
||||||
|
|||||||
@@ -4,97 +4,5 @@
|
|||||||
|
|
||||||
namespace omath::projectile_prediction
|
namespace omath::projectile_prediction
|
||||||
{
|
{
|
||||||
ProjPredEngineLegacy::ProjPredEngineLegacy(const float gravity_constant, const float simulation_time_step,
|
|
||||||
const float maximum_simulation_time, const float distance_tolerance)
|
|
||||||
: m_gravity_constant(gravity_constant), m_simulation_time_step(simulation_time_step),
|
|
||||||
m_maximum_simulation_time(maximum_simulation_time), m_distance_tolerance(distance_tolerance)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Vector3<float>> ProjPredEngineLegacy::maybe_calculate_aim_point(const Projectile& projectile,
|
|
||||||
const Target& target) const
|
|
||||||
{
|
|
||||||
for (float time = 0.f; time < m_maximum_simulation_time; time += m_simulation_time_step)
|
|
||||||
{
|
|
||||||
const auto predicted_target_position = target.predict_position(time, m_gravity_constant);
|
|
||||||
|
|
||||||
const auto projectile_pitch =
|
|
||||||
maybe_calculate_projectile_launch_pitch_angle(projectile, predicted_target_position);
|
|
||||||
|
|
||||||
if (!projectile_pitch.has_value()) [[unlikely]]
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!is_projectile_reached_target(predicted_target_position, projectile, projectile_pitch.value(), time))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return calc_viewpoint_from_angles(projectile, predicted_target_position, projectile_pitch);
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<float> ProjPredEngineLegacy::maybe_calculate_projectile_launch_pitch_angle(
|
|
||||||
const Projectile& projectile, const Vector3<float>& target_position) const noexcept
|
|
||||||
{
|
|
||||||
const auto bullet_gravity = m_gravity_constant * projectile.m_gravity_scale;
|
|
||||||
const auto delta = target_position - projectile.m_origin;
|
|
||||||
|
|
||||||
const auto distance2d = calc_vector_2d_distance(delta);
|
|
||||||
const auto distance2d_sqr = distance2d * distance2d;
|
|
||||||
const auto launch_speed_sqr = projectile.m_launch_speed * projectile.m_launch_speed;
|
|
||||||
|
|
||||||
float root = launch_speed_sqr * launch_speed_sqr
|
|
||||||
- bullet_gravity
|
|
||||||
* (bullet_gravity * distance2d_sqr
|
|
||||||
+ 2.0f * get_vector_height_coordinate(delta) * launch_speed_sqr);
|
|
||||||
|
|
||||||
if (root < 0.0f) [[unlikely]]
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
root = std::sqrt(root);
|
|
||||||
const float angle = std::atan((launch_speed_sqr - root) / (bullet_gravity * distance2d));
|
|
||||||
|
|
||||||
return angles::radians_to_degrees(angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProjPredEngineLegacy::is_projectile_reached_target(const Vector3<float>& target_position,
|
|
||||||
const Projectile& projectile, const float pitch,
|
|
||||||
const float time) const noexcept
|
|
||||||
{
|
|
||||||
const auto yaw = projectile.m_origin.view_angle_to(target_position).y;
|
|
||||||
const auto projectile_position = predict_projectile_position(projectile, pitch, yaw, time, m_gravity_constant);
|
|
||||||
|
|
||||||
return projectile_position.distance_to(target_position) <= m_distance_tolerance;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ProjPredEngineLegacy::calc_vector_2d_distance(const Vector3<float>& delta) const
|
|
||||||
{
|
|
||||||
return std::sqrt(delta.x * delta.x + delta.y * delta.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
float ProjPredEngineLegacy::get_vector_height_coordinate(const Vector3<float>& vec) const
|
|
||||||
{
|
|
||||||
return vec.z;
|
|
||||||
}
|
|
||||||
Vector3<float> ProjPredEngineLegacy::calc_viewpoint_from_angles(const Projectile& projectile,
|
|
||||||
const Vector3<float> predicted_target_position,
|
|
||||||
const std::optional<float> projectile_pitch) const
|
|
||||||
{
|
|
||||||
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
|
|
||||||
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
|
|
||||||
|
|
||||||
return {predicted_target_position.x, predicted_target_position.y, projectile.m_origin.z + height};
|
|
||||||
}
|
|
||||||
Vector3<float> ProjPredEngineLegacy::predict_projectile_position(const Projectile& projectile, const float pitch,
|
|
||||||
const float yaw, const float time,
|
|
||||||
const float gravity) const
|
|
||||||
{
|
|
||||||
auto current_pos = projectile.m_origin
|
|
||||||
+ source_engine::forward_vector({source_engine::PitchAngle::from_degrees(-pitch),
|
|
||||||
source_engine::YawAngle::from_degrees(yaw),
|
|
||||||
source_engine::RollAngle::from_degrees(0)})
|
|
||||||
* projectile.m_launch_speed * time;
|
|
||||||
current_pos.z -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f;
|
|
||||||
|
|
||||||
return current_pos;
|
|
||||||
}
|
|
||||||
} // namespace omath::projectile_prediction
|
} // namespace omath::projectile_prediction
|
||||||
|
|||||||
Reference in New Issue
Block a user