Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Yujia Zhou E22214017 AHU Software Engineering
- // Noitce: This program require compile environment newer than C++20
- // (Including C++ 20) as some of it's newly added features used in
- // this program
- #include <iostream>
- #include <algorithm>
- #include <cmath>
- using std::cout, std::endl;
- using std::max, std::min;
- using LL = long long;
- using db = double;
- // const values
- const double G = 9.8;
- const double PI = 3.1415926535;
- const double ANG_RAD_CONV_FACTOR = PI / 180;
- struct TestCaseData;
- // function declarations
- double angToRad(double ang);
- double RadToAng(double rad);
- void preprocessData(TestCaseData &data);
- double frac(double n, double d);
- double pointDistance(double x1, double y1, double x2, double y2);
- double frac(double n, double d)
- {
- return n / d;
- }
- double angToRad(double ang)
- {
- return (ang * ANG_RAD_CONV_FACTOR);
- }
- double RadToAng(double rad)
- {
- return (rad / ANG_RAD_CONV_FACTOR);
- }
- double pointDistance(double x1, double y1, double x2, double y2)
- {
- double xd = x1 - x2;
- double yd = y1 - y2;
- return sqrt(xd * xd + yd * yd);
- }
- double solveQuadratic(double a, double b, double c)
- {
- double discriminant = b * b - 4 * a * c;
- double root;
- if (discriminant < 0)
- {
- return -1;
- }
- double root1 = (-b + sqrt(discriminant)) / (2 * a);
- double root2 = (-b - sqrt(discriminant)) / (2 * a);
- if (root1 < 0 && root2 < 0)
- {
- return -1;
- }
- if (root1 < 0 || root2 < 0)
- {
- return max(root1, root2);
- }
- if (sqrt(root1) > sqrt(root2))
- {
- return root2;
- }
- else
- {
- return root1;
- }
- }
- // Data of a testcase
- //
- // Notice:
- // All degree data inside TestCaseData is about the moving items.
- struct TestCaseData
- {
- // original data
- double v;
- double w;
- double ang;
- double x0;
- double y0;
- // pre-processed data
- double rad;
- double wx;
- double wy;
- };
- /// @brief Pre-process the TestCaseData instance
- /// @param data The data need to be pre-processed
- void preprocessData(TestCaseData &data)
- {
- data.rad = angToRad(data.ang);
- data.wx = data.w * cos(data.rad);
- data.wy = data.w * sin(data.rad);
- }
- struct TestCaseRuntime
- {
- TestCaseData caseData;
- double xi;
- double yi;
- double xip; // stands for xi previous
- double yip;
- double ti;
- double rad;
- bool iterated;
- bool canSolve;
- bool solved;
- };
- TestCaseRuntime createTestCaseRuntime(const TestCaseData &data)
- {
- TestCaseRuntime rt{
- .caseData{data},
- .xi{data.x0},
- .yi{data.y0},
- .xip{data.x0},
- .yip{data.y0},
- .ti{0},
- .rad{0},
- .iterated{false},
- .canSolve{true},
- .solved{false}};
- return rt;
- }
- // Iterate the runtime data
- //
- // If return false, means iteration terminated
- // (maybe found solution or can NOT be solved)
- bool iterateRuntime(TestCaseRuntime &rt)
- {
- // cout << "[DEBUG] Iterating..." << endl;
- // calculate t
- const static double a = frac(1, 4) * G * G;
- double b = rt.yi * G - rt.caseData.v * rt.caseData.v;
- double c = rt.xi * rt.xi + rt.yi * rt.yi;
- double t2 = solveQuadratic(a, b, c);
- double t = sqrt(t2);
- // debug
- if (t2 < 0 && t2 != -1)
- {
- cout << "[DEBUG][ERROR] solveQuadratic return negative value";
- exit(0);
- }
- // no solution
- if (t2 == -1 || t2 < 0)
- {
- rt.canSolve = false;
- rt.solved = false;
- return false;
- }
- // update t
- rt.ti = t;
- // update point
- rt.xip = rt.xi;
- rt.yip = rt.yi;
- // calc new xi, yi
- rt.xi = rt.caseData.x0 + rt.caseData.wx * t;
- rt.yi = rt.caseData.y0 + rt.caseData.wy * t;
- // calculate delta
- double delta = pointDistance(rt.xi, rt.yi, rt.xip, rt.yip);
- // debug
- if (delta < 0)
- {
- cout << "[DEBUG][ERROR] pointDistance return negative value";
- exit(0);
- }
- // cout << "[DEBUG] Distance: " << delta << endl;
- // meet terminate condition
- if (delta < 1e-4)
- {
- rt.solved = true;
- rt.canSolve = true;
- rt.rad = acos(rt.xi / (rt.caseData.v * rt.ti));
- return false;
- }
- if (delta > 9999999)
- {
- cout << "[DEBUG][NOTICE] Iteration result diverge, force terminated"
- << endl;
- rt.solved = false;
- rt.canSolve = true;
- return false;
- }
- return true;
- }
- void solveCase(TestCaseData caseData)
- {
- preprocessData(caseData);
- auto runtime = createTestCaseRuntime(caseData);
- LL itCount = 0;
- while (iterateRuntime(runtime))
- {
- }
- cout << "-------------------------" << endl;
- cout << " Case solved: " << (runtime.solved == 1 ? "Yes" : "No") << endl;
- if (runtime.solved)
- {
- cout << " Result: " << endl
- << " ti: " << runtime.ti << endl
- << " xi: " << runtime.xi << endl
- << " yi: " << runtime.yi << endl;
- cout << "Luanch angle: " << runtime.rad << " Rad." << endl
- << " " << RadToAng(runtime.rad) << " Ang." << endl;
- }
- else if (runtime.canSolve)
- {
- cout << " Reason: Result Diverged." << endl;
- }
- else
- {
- cout << " Reason: No real root for equation, "
- << " which means it's impossible for projectile to hit target. " << endl;
- }
- cout << "-------------------------" << endl;
- }
- void showCredential()
- {
- cout << "周裕佳 E22214017" << endl;
- }
- int main()
- {
- showCredential();
- TestCaseData case1{
- .v{100},
- .w{20},
- .ang{150},
- .x0{600},
- .y0{200},
- };
- TestCaseData case2{
- .v{100},
- .w{120},
- .ang{30},
- .x0{500},
- .y0{100},
- };
- TestCaseData case3{
- .v{120},
- .w{30},
- .ang{-60},
- .x0{500},
- .y0{-100},
- };
- solveCase(case1);
- solveCase(case2);
- solveCase(case3);
- return 0;
- }
- // Output:
- /**
- 周裕佳 E22214017
- -------------------------
- Case solved: Yes
- Result:
- ti: 6.99227
- xi: 478.89
- yi: 269.923
- Luanch angle: 0.816351 Rad.
- 46.7735 Ang.
- -------------------------
- -------------------------
- Case solved: No
- Reason: No real root for equation, which means it's impossible for projectile to hit target.
- -------------------------
- -------------------------
- Case solved: Yes
- Result:
- ti: 4.86242
- xi: 572.936
- yi: -226.329
- Luanch angle: 0.19049 Rad.
- 10.9142 Ang.
- -------------------------
- */
- // Answer has been examinated, for more info check out: https://www.geogebra.org/calculator/zvrrge3r
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement