From 5361d498c33deeb1e1ad44aed24a53a4f9e97618 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 2 Jul 2023 17:27:38 +0200 Subject: [PATCH] WARNING: REDESIGN: `Vector2Angle()`<-->`Vector2LineAngle()` #2887 --- examples/others/raymath_vector_angle.c | 106 +++++++++++++++++++++++ examples/others/raymath_vector_angle.png | Bin 0 -> 16339 bytes src/raymath.h | 27 +++--- 3 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 examples/others/raymath_vector_angle.c create mode 100644 examples/others/raymath_vector_angle.png diff --git a/examples/others/raymath_vector_angle.c b/examples/others/raymath_vector_angle.c new file mode 100644 index 000000000..86cd91a93 --- /dev/null +++ b/examples/others/raymath_vector_angle.c @@ -0,0 +1,106 @@ +/******************************************************************************************* +* +* raylib [shapes] example - Vector Angle +* +* Example originally created with raylib 1.0, last time updated with raylib 4.2 +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2023 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [math] example - vector angle"); + + Vector2 v0 = { screenWidth/2, screenHeight/2 }; + Vector2 v1 = { 100.0f, 80.0f }; + Vector2 v2 = { 0 }; // Updated with mouse position + + float angle = 0.0f; // Angle in degrees + int angleMode = 0; // 0-Vector2Angle(), 1-Vector2LineAngle() + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + if (IsKeyPressed(KEY_SPACE)) angleMode = !angleMode; + + if (angleMode == 0) + { + // Calculate angle between two vectors, considering a common origin (v0) + v1 = Vector2Add(v0, (Vector2){ 100.0f, 80.0f }); + v2 = GetMousePosition(); + angle = Vector2Angle(Vector2Normalize(Vector2Subtract(v1, v0)), Vector2Normalize(Vector2Subtract(v2, v0)))*RAD2DEG; + } + else if (angleMode == 1) + { + // Calculate angle defined by a two vectors line, in reference to horizontal line + v1 = (Vector2){ screenWidth/2, screenHeight/2 }; + v2 = GetMousePosition(); + angle = Vector2LineAngle(v1, v2)*RAD2DEG; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + if (angleMode == 0) DrawText("v0", v0.x, v0.y, 10, DARKGRAY); + DrawText("v1", v1.x, v1.y, 10, DARKGRAY); + DrawText("v2", v2.x, v2.y, 10, DARKGRAY); + + if (angleMode == 0) + { + DrawText("MODE: Angle between V1 and V2", 10, 10, 20, BLACK); + + DrawLineEx(v0, v1, 2.0f, BLACK); + DrawLineEx(v0, v2, 2.0f, RED); + + // TODO: Properly draw circle sector + DrawCircleSector(v0, 40.0f, Vector2LineAngle(v0, v1)*RAD2DEG, angle, 32, Fade(GREEN, 0.6f)); + } + else if (angleMode == 1) + { + DrawText("MODE: Angle formed by line V1 to V2", 10, 10, 20, BLACK); + + DrawLine(0, screenHeight/2, screenWidth, screenHeight/2, LIGHTGRAY); + DrawLineEx(v1, v2, 2.0f, RED); + + DrawCircleSector(v1, 40.0f, 90.0f, 180 - angle - 90, 32, Fade(GREEN, 0.6f)); + } + + DrawText("Press SPACE to change MODE", 460, 10, 20, DARKGRAY); + DrawText(TextFormat("ANGLE: %2.2f", angle), 10, 40, 20, LIME); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/others/raymath_vector_angle.png b/examples/others/raymath_vector_angle.png new file mode 100644 index 0000000000000000000000000000000000000000..29995e002f283e5bd9a1960085dc25da31d5e9eb GIT binary patch literal 16339 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 literal 0 HcmV?d00001 diff --git a/src/raymath.h b/src/raymath.h index 47728ff69..6a929cf6e 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -314,8 +314,19 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) // NOTE: Angle is calculated from origin point (0, 0) RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) { - float result = atan2f(v2.y - v1.y, v2.x - v1.x); + float result = 0.0f; + + float dot = v1.x*v2.x + v1.y*v2.y; // Dot product + float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp + if (dotClamp > 1.0f) dotClamp = 1.0f; + result = acosf(dotClamp); + + // Alternative implementation, more costly + //float v1Length = sqrtf((v1.x*v1.x) + (v1.y*v1.y)); + //float v2Length = sqrtf((v2.x*v2.x) + (v2.y*v2.y)); + //float result = -acosf((v1.x*v2.x + v1.y*v2.y)/(v1Length*v2Length)); + return result; } @@ -325,18 +336,8 @@ RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) RMAPI float Vector2LineAngle(Vector2 start, Vector2 end) { float result = 0.0f; - - float dot = start.x*end.x + start.y*end.y; // Dot product - - float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp - if (dotClamp > 1.0f) dotClamp = 1.0f; - - result = acosf(dotClamp); - - // Alternative implementation, more costly - //float v1Length = sqrtf((start.x*start.x) + (start.y*start.y)); - //float v2Length = sqrtf((end.x*end.x) + (end.y*end.y)); - //float result = -acosf((start.x*end.x + start.y*end.y)/(v1Length*v2Length)); + + result = atan2f(end.y - start.y, end.x - start.x); return result; }