From 2f31a9495a3e94de71e431d99b8f1c32c2c8c08c Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Mon, 20 Apr 2020 16:00:47 +0300 Subject: [PATCH] Allow circles to be transformed to area points. --- module/Base/Circle.cpp | 28 ++++++++++++++++++++++++++++ module/Base/Circle.hpp | 5 +++++ module/Misc/Areas.cpp | 24 ++++++++++++++++++++++++ module/Misc/Areas.hpp | 14 ++++++++++++++ sqrat/sqrat/sqratArray.h | 20 ++++++++++++++++++++ 5 files changed, 91 insertions(+) diff --git a/module/Base/Circle.cpp b/module/Base/Circle.cpp index 7491078d..b23203d3 100644 --- a/module/Base/Circle.cpp +++ b/module/Base/Circle.cpp @@ -467,6 +467,33 @@ Circle Circle::Abs() const return {pos.Abs(), std::fabs(rad)}; } +// ------------------------------------------------------------------------------------------------ +Array Circle::ToPointsArray(SQInteger num_segments) const +{ + // Allocate an array with the same amount of elements as the number of segments + Array arr(SqVM(), num_segments); + // Iterate the specified segments array + arr.AppendFromCounted([this](HSQUIRRELVM vm, SQInteger i, SQInteger num_segments) -> bool { + if (i >= num_segments) return false; + // Get the current angle +#ifdef SQUSEDOUBLE + SQFloat theta = 2.0d * SQMOD_PI64 * static_cast< SQFloat >(i) / static_cast< SQFloat >(num_segments); +#else + SQFloat theta = 2.0f * SQMOD_PI * static_cast< SQFloat >(i) / static_cast< SQFloat >(num_segments); +#endif // SQUSEDOUBLE + // Calculate the x component + SQFloat x = (rad * std::cos(theta)) + pos.x; + // Calculate the y component + SQFloat y = (rad * std::sin(theta)) + pos.y; + // Push the Vector2 instance on the stack + Var< Vector2 >::push(vm, Vector2{x, y}); + // Insert the element on the stack into the array + return true; + }, num_segments); + // Return the resulted array + return arr; +} + // ------------------------------------------------------------------------------------------------ const Circle & Circle::Get(StackStrF & str) { @@ -539,6 +566,7 @@ void Register_Circle(HSQUIRRELVM vm) .Func(_SC("SetPositionEx"), &Circle::SetPositionEx) .FmtFunc(_SC("SetStr"), &Circle::SetStr) .Func(_SC("Clear"), &Circle::Clear) + .Func(_SC("ToPointsArray"), &Circle::ToPointsArray) // Member Overloads .Overload< void (Circle::*)(void) >(_SC("Generate"), &Circle::Generate) .Overload< void (Circle::*)(Val, Val, bool) >(_SC("Generate"), &Circle::Generate) diff --git a/module/Base/Circle.hpp b/module/Base/Circle.hpp index 52e6f442..51a841cc 100644 --- a/module/Base/Circle.hpp +++ b/module/Base/Circle.hpp @@ -411,6 +411,11 @@ struct Circle */ Circle Abs() const; + /* -------------------------------------------------------------------------------------------- + * Transform this into an array of Vector2 points that form a circle. + */ + Array ToPointsArray(SQInteger num_segments) const; + /* -------------------------------------------------------------------------------------------- * Extract the values for components of the Circle type from a string. */ diff --git a/module/Misc/Areas.cpp b/module/Misc/Areas.cpp index f47a7702..fded97db 100644 --- a/module/Misc/Areas.cpp +++ b/module/Misc/Areas.cpp @@ -48,6 +48,28 @@ void Area::AddArray(const Sqrat::Array & a) }); } #pragma clang diagnostic pop +// ------------------------------------------------------------------------------------------------ +void Area::AddCircleEx(SQFloat cx, SQFloat cy, SQFloat cr, SQInteger num_segments) +{ + for(SQInteger i = 0; i < num_segments; ++i) + { + CheckLock(); + // Get the current angle +#ifdef SQUSEDOUBLE + SQFloat theta = 2.0d * SQMOD_PI64 * static_cast< SQFloat >(i) / static_cast< SQFloat >(num_segments); +#else + SQFloat theta = 2.0f * SQMOD_PI * static_cast< SQFloat >(i) / static_cast< SQFloat >(num_segments); +#endif // SQUSEDOUBLE + // Calculate the x component + SQFloat x = (cr * std::cos(theta)) + cx; + // Calculate the y component + SQFloat y = (cr * std::sin(theta)) + cy; + // Insert the point into the list + mPoints.emplace_back(x, y); + // Update the bounding box + Expand(x, y); + } +} // ------------------------------------------------------------------------------------------------ bool Area::Manage() @@ -456,6 +478,8 @@ void Register_Areas(HSQUIRRELVM vm) .Func(_SC("AddEx"), &Area::AddPointEx) .Func(_SC("AddVirtual"), &Area::AddVirtualPoint) .Func(_SC("AddVirtualEx"), &Area::AddVirtualPointEx) + .Func(_SC("AddCircle"), &Area::AddCircle) + .Func(_SC("AddCircleEx"), &Area::AddCircleEx) .Func(_SC("AddFake"), &Area::AddVirtualPoint) .Func(_SC("AddFakeEx"), &Area::AddVirtualPointEx) .Func(_SC("AddArray"), &Area::AddArray) diff --git a/module/Misc/Areas.hpp b/module/Misc/Areas.hpp index 1c2f2677..c9e7fffb 100644 --- a/module/Misc/Areas.hpp +++ b/module/Misc/Areas.hpp @@ -2,6 +2,7 @@ // ------------------------------------------------------------------------------------------------ #include "Base/Shared.hpp" +#include "Base/Circle.hpp" #include "Base/Vector2.hpp" #include "Base/Vector4.hpp" #include "Base/Vector2i.hpp" @@ -402,6 +403,19 @@ struct Area */ void AddArray(const Sqrat::Array & a); + /* -------------------------------------------------------------------------------------------- + * Add a 2D circle to the point list. + */ + void AddCircle(const Circle & c, SQInteger num_segments) + { + AddCircleEx(c.pos.x, c.pos.y, c.rad, num_segments); + } + + /* -------------------------------------------------------------------------------------------- + * Add a 2D circle to the point list. + */ + void AddCircleEx(SQFloat cx, SQFloat cy, SQFloat cr, SQInteger num_segments); + /* -------------------------------------------------------------------------------------------- * Test if a point is inside the bounding box and then the area. */ diff --git a/sqrat/sqrat/sqratArray.h b/sqrat/sqrat/sqratArray.h index 1d765454..79541ca1 100644 --- a/sqrat/sqrat/sqratArray.h +++ b/sqrat/sqrat/sqratArray.h @@ -548,6 +548,26 @@ public: return *this; } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Appends values to the end of the Array + /// + /// \param func Functor that is continuously called to push values on the stack + /// + /// \tparam F Type of functor (usually doesnt need to be defined explicitly) + /// + /// \return The Array itself so the call can be chained + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + ArrayBase& AppendFromCounted(F&& func, A &&... a) { + sq_pushobject(vm, GetObj()); + for (SQInteger i = 0; func(vm, i, std::forward< A >(a)...); ++i) + { + sq_arrayappend(vm, -2); + } + sq_pop(vm,1); // pop array + return *this; + } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////