From 6d11eb504838946a7498f23c97ab589c5bba15ae Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Wed, 10 Jan 2024 17:49:24 -0600 Subject: [PATCH] Update to geom2d 2.0 util --- Adventures in Lestoria/Ability.h | 2 +- .../AdventuresInLestoria.cpp | 5 +- Adventures in Lestoria/AdventuresInLestoria.h | 4 +- Adventures in Lestoria/Attributable.h | 1 - Adventures in Lestoria/AttributableStat.h | 2 +- Adventures in Lestoria/Bullet.h | 1 - Adventures in Lestoria/BulletTypes.h | 1 - Adventures in Lestoria/Class.h | 1 - Adventures in Lestoria/ConnectionPoint.h | 1 + Adventures in Lestoria/DamageNumber.h | 2 +- Adventures in Lestoria/Effect.h | 2 - Adventures in Lestoria/Emitter.cpp | 1 + Adventures in Lestoria/Emitter.h | 2 +- Adventures in Lestoria/EnvironmentalAudio.h | 3 +- .../InventoryConsumableWindow.cpp | 1 - Adventures in Lestoria/Item.h | 1 - Adventures in Lestoria/ItemDrop.h | 1 - Adventures in Lestoria/Key.h | 3 +- Adventures in Lestoria/Menu.cpp | 2 +- Adventures in Lestoria/Merchant.h | 1 - Adventures in Lestoria/Monster.h | 1 - Adventures in Lestoria/MonsterData.cpp | 1 - Adventures in Lestoria/Pathfinding.h | 4 +- Adventures in Lestoria/Ranger.cpp | 1 - Adventures in Lestoria/TMXParser.h | 2 +- Adventures in Lestoria/TSXParser.h | 2 - Adventures in Lestoria/Thief.cpp | 1 - Adventures in Lestoria/TitleScreen.h | 1 + Adventures in Lestoria/Trapper.cpp | 1 - Adventures in Lestoria/Version.h | 2 +- Adventures in Lestoria/Warrior.cpp | 1 - Adventures in Lestoria/Witch.cpp | 1 - Adventures in Lestoria/Wizard.cpp | 1 - Adventures in Lestoria/config.h | 1 - Adventures in Lestoria/olcPGEX_TTF.h | 1 + Adventures in Lestoria/olcPGEX_ViewPort.h | 1 - Adventures in Lestoria/olcPixelGameEngine.h | 5 +- Adventures in Lestoria/olcUTIL_Animate2D.h | 2 +- Adventures in Lestoria/olcUTIL_Camera2D.h | 4 +- Adventures in Lestoria/olcUTIL_DataFile.h | 3 +- Adventures in Lestoria/olcUTIL_Geometry2D.h | 2009 ++++++++++++++--- Adventures in Lestoria/pixelGameEngine.cpp | 1 + Adventures in Lestoria/util.h | 1 + 43 files changed, 1703 insertions(+), 381 deletions(-) diff --git a/Adventures in Lestoria/Ability.h b/Adventures in Lestoria/Ability.h index aba06e65..254d1063 100644 --- a/Adventures in Lestoria/Ability.h +++ b/Adventures in Lestoria/Ability.h @@ -36,8 +36,8 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "Key.h" +#include "olcPixelGameEngine.h" class Player; diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index edc0e14a..5174c93f 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -35,9 +35,9 @@ Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ #pragma endregion +#include "olcUTIL_Camera2D.h" #include "olcPGEX_TransformedView.h" #include "AdventuresInLestoria.h" -#include "olcUTIL_Camera2D.h" #include "DamageNumber.h" #include "Bullet.h" #include "Ability.h" @@ -1461,7 +1461,7 @@ void AiL::RenderCooldowns(){ for(Ability&a:cooldowns){ if(a.name!="???"){ DrawCooldown(iconPos,a); - iconPos+={32,0}; + iconPos+=vf2d{32,0}; } } @@ -2201,7 +2201,6 @@ bool AiL::OnUserDestroy(){ for(auto&[key,value]:GameState::states){ delete value; } - delete[]pathfinder.nodes; Menu::CleanupAllMenus(); for(auto&[key,value]:MonsterData::imgs){ delete value; diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h index b6f785bf..137917dd 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.h +++ b/Adventures in Lestoria/AdventuresInLestoria.h @@ -36,13 +36,12 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" +#include "olcUTIL_Camera2D.h" #include "Animation.h" #include "olcUTIL_Animate2D.h" #include "Monster.h" #include "olcPGEX_TransformedView.h" #include "Player.h" -#include "olcUTIL_Camera2D.h" #include "Bullet.h" #include "Effect.h" #include "Map.h" @@ -55,6 +54,7 @@ All rights reserved. #endif #include "Audio.h" #include "olcPGEX_SplashScreen.h" +#include "olcPixelGameEngine.h" class AiL : public olc::PixelGameEngine { diff --git a/Adventures in Lestoria/Attributable.h b/Adventures in Lestoria/Attributable.h index 44ab542e..8e989892 100644 --- a/Adventures in Lestoria/Attributable.h +++ b/Adventures in Lestoria/Attributable.h @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "MonsterAttribute.h" #include "DEFINES.h" #include diff --git a/Adventures in Lestoria/AttributableStat.h b/Adventures in Lestoria/AttributableStat.h index 9a304f35..81fa31bf 100644 --- a/Adventures in Lestoria/AttributableStat.h +++ b/Adventures in Lestoria/AttributableStat.h @@ -36,9 +36,9 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "safemap.h" #include +#include using namespace std::string_view_literals; diff --git a/Adventures in Lestoria/Bullet.h b/Adventures in Lestoria/Bullet.h index 492cef8c..49e7ba6b 100644 --- a/Adventures in Lestoria/Bullet.h +++ b/Adventures in Lestoria/Bullet.h @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "Animation.h" #include "olcUTIL_Animate2D.h" #include "Monster.h" diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h index 0b455b6a..00a11075 100644 --- a/Adventures in Lestoria/BulletTypes.h +++ b/Adventures in Lestoria/BulletTypes.h @@ -37,7 +37,6 @@ All rights reserved. #pragma endregion #pragma once #include "Bullet.h" -#include "olcPixelGameEngine.h" struct EnergyBolt:public Bullet{ float lastParticleSpawn=0; diff --git a/Adventures in Lestoria/Class.h b/Adventures in Lestoria/Class.h index 6a5c4087..dc32949c 100644 --- a/Adventures in Lestoria/Class.h +++ b/Adventures in Lestoria/Class.h @@ -38,7 +38,6 @@ All rights reserved. #pragma once #include "Ability.h" #include "Animation.h" -#include "olcPixelGameEngine.h" #undef GetClassInfo diff --git a/Adventures in Lestoria/ConnectionPoint.h b/Adventures in Lestoria/ConnectionPoint.h index c668b497..52fb6766 100644 --- a/Adventures in Lestoria/ConnectionPoint.h +++ b/Adventures in Lestoria/ConnectionPoint.h @@ -37,6 +37,7 @@ All rights reserved. #pragma endregion #pragma once #include "olcUTIL_Geometry2D.h" +#include struct ConnectionPoint{ friend class State_OverworldMap; diff --git a/Adventures in Lestoria/DamageNumber.h b/Adventures in Lestoria/DamageNumber.h index 098cad90..d2ac15f4 100644 --- a/Adventures in Lestoria/DamageNumber.h +++ b/Adventures in Lestoria/DamageNumber.h @@ -36,7 +36,7 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" +#include "olcUTIL_Geometry2D.h" enum DamageNumberType{ HEALTH_LOSS, diff --git a/Adventures in Lestoria/Effect.h b/Adventures in Lestoria/Effect.h index baee10a3..6b9097b9 100644 --- a/Adventures in Lestoria/Effect.h +++ b/Adventures in Lestoria/Effect.h @@ -36,9 +36,7 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "Animation.h" -#include "olcUTIL_Animate2D.h" struct Effect{ friend class AiL; diff --git a/Adventures in Lestoria/Emitter.cpp b/Adventures in Lestoria/Emitter.cpp index 87cf0fd0..a8e6b8db 100644 --- a/Adventures in Lestoria/Emitter.cpp +++ b/Adventures in Lestoria/Emitter.cpp @@ -36,6 +36,7 @@ All rights reserved. */ #pragma endregion #include "Emitter.h" +#include std::vector>EMITTER_LIST; diff --git a/Adventures in Lestoria/Emitter.h b/Adventures in Lestoria/Emitter.h index 3f097476..a39af125 100644 --- a/Adventures in Lestoria/Emitter.h +++ b/Adventures in Lestoria/Emitter.h @@ -36,7 +36,7 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" +#include "olcUTIL_Geometry2D.h" struct Emitter{ friend class AiL; diff --git a/Adventures in Lestoria/EnvironmentalAudio.h b/Adventures in Lestoria/EnvironmentalAudio.h index f98d0e65..d3abb9fc 100644 --- a/Adventures in Lestoria/EnvironmentalAudio.h +++ b/Adventures in Lestoria/EnvironmentalAudio.h @@ -36,7 +36,8 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" +#include "olcUTIL_Geometry2D.h" +#include using EnvironmentalAudioSoundName=std::string; using FileName=std::string; diff --git a/Adventures in Lestoria/InventoryConsumableWindow.cpp b/Adventures in Lestoria/InventoryConsumableWindow.cpp index 88750bc0..c047d5a2 100644 --- a/Adventures in Lestoria/InventoryConsumableWindow.cpp +++ b/Adventures in Lestoria/InventoryConsumableWindow.cpp @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #include "AdventuresInLestoria.h" -#include "olcPixelGameEngine.h" #include "safemap.h" #include "Item.h" #include "MenuItemButton.h" diff --git a/Adventures in Lestoria/Item.h b/Adventures in Lestoria/Item.h index 38868199..ada7d557 100644 --- a/Adventures in Lestoria/Item.h +++ b/Adventures in Lestoria/Item.h @@ -39,7 +39,6 @@ All rights reserved. #include #include #include -#include "olcPixelGameEngine.h" #include "olcUTIL_DataFile.h" #include "AttributableStat.h" #include "BitwiseEnum.h" diff --git a/Adventures in Lestoria/ItemDrop.h b/Adventures in Lestoria/ItemDrop.h index 391be907..407eaa41 100644 --- a/Adventures in Lestoria/ItemDrop.h +++ b/Adventures in Lestoria/ItemDrop.h @@ -35,7 +35,6 @@ Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ #pragma endregion -#include "olcPixelGameEngine.h" #include "Item.h" #include "util.h" #include "AdventuresInLestoria.h" diff --git a/Adventures in Lestoria/Key.h b/Adventures in Lestoria/Key.h index ffec02c6..fc84848d 100644 --- a/Adventures in Lestoria/Key.h +++ b/Adventures in Lestoria/Key.h @@ -36,8 +36,9 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include +#include +#include //Future-proof game controller support. enum InputType{ diff --git a/Adventures in Lestoria/Menu.cpp b/Adventures in Lestoria/Menu.cpp index 5e237d48..ff588133 100644 --- a/Adventures in Lestoria/Menu.cpp +++ b/Adventures in Lestoria/Menu.cpp @@ -81,7 +81,7 @@ INCLUDE_WINDOW_SIZE using A=Attribute; Menu::Menu(vf2d pos,vf2d size) - :pos(pos==CENTERED?WINDOW_SIZE/2-size/2:vi2d{pos}),size(size){ + :pos(pos==CENTERED?vi2d{WINDOW_SIZE/2-size/2}:vi2d{pos}),size(size){ this->window=ViewPort::rectViewPort({-24,-24},this->size+vi2d{48,48},this->pos); } diff --git a/Adventures in Lestoria/Merchant.h b/Adventures in Lestoria/Merchant.h index 3ac903a9..c87effd8 100644 --- a/Adventures in Lestoria/Merchant.h +++ b/Adventures in Lestoria/Merchant.h @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "FunctionPriming.h" class Item; diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h index 452a7f9a..54b94f6a 100644 --- a/Adventures in Lestoria/Monster.h +++ b/Adventures in Lestoria/Monster.h @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "Animation.h" #include "State.h" #include "Buff.h" diff --git a/Adventures in Lestoria/MonsterData.cpp b/Adventures in Lestoria/MonsterData.cpp index bb501b43..3dde9ff6 100644 --- a/Adventures in Lestoria/MonsterData.cpp +++ b/Adventures in Lestoria/MonsterData.cpp @@ -35,7 +35,6 @@ Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ #pragma endregion -#include "olcPixelGameEngine.h" #include "Monster.h" #include "Animation.h" #include "config.h" diff --git a/Adventures in Lestoria/Pathfinding.h b/Adventures in Lestoria/Pathfinding.h index e44b2ff5..70872dfd 100644 --- a/Adventures in Lestoria/Pathfinding.h +++ b/Adventures in Lestoria/Pathfinding.h @@ -36,8 +36,10 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" +#include "olcUTIL_Geometry2D.h" #include +#include +#include struct Pathfinding{ struct sNode diff --git a/Adventures in Lestoria/Ranger.cpp b/Adventures in Lestoria/Ranger.cpp index 1ac0e61a..838f7484 100644 --- a/Adventures in Lestoria/Ranger.cpp +++ b/Adventures in Lestoria/Ranger.cpp @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #include "Class.h" -#include "olcPixelGameEngine.h" #include "DEFINES.h" #include "Player.h" #include "Effect.h" diff --git a/Adventures in Lestoria/TMXParser.h b/Adventures in Lestoria/TMXParser.h index 423f82dd..792cb915 100644 --- a/Adventures in Lestoria/TMXParser.h +++ b/Adventures in Lestoria/TMXParser.h @@ -36,8 +36,8 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "olcUTIL_Geometry2D.h" +#include "olcPixelGameEngine.h" #include #include #include "EnvironmentalAudio.h" diff --git a/Adventures in Lestoria/TSXParser.h b/Adventures in Lestoria/TSXParser.h index 6137a8ae..5a718b3b 100644 --- a/Adventures in Lestoria/TSXParser.h +++ b/Adventures in Lestoria/TSXParser.h @@ -36,11 +36,9 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include #include "TMXParser.h" #include "Map.h" -#include "olcUTIL_Geometry2D.h" #include "olcUTIL_DataFile.h" #include "Error.h" diff --git a/Adventures in Lestoria/Thief.cpp b/Adventures in Lestoria/Thief.cpp index 6a09c7a0..9379227f 100644 --- a/Adventures in Lestoria/Thief.cpp +++ b/Adventures in Lestoria/Thief.cpp @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #include "Class.h" -#include "olcPixelGameEngine.h" #include "DEFINES.h" #include "Player.h" #include "Effect.h" diff --git a/Adventures in Lestoria/TitleScreen.h b/Adventures in Lestoria/TitleScreen.h index 0ed8ef20..74cf15a9 100644 --- a/Adventures in Lestoria/TitleScreen.h +++ b/Adventures in Lestoria/TitleScreen.h @@ -37,6 +37,7 @@ All rights reserved. #pragma endregion #pragma once +#include "olcUTIL_Geometry2D.h" #include "olcPixelGameEngine.h" class TitleScreen{ diff --git a/Adventures in Lestoria/Trapper.cpp b/Adventures in Lestoria/Trapper.cpp index e2d3af6a..a4a02913 100644 --- a/Adventures in Lestoria/Trapper.cpp +++ b/Adventures in Lestoria/Trapper.cpp @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #include "Class.h" -#include "olcPixelGameEngine.h" #include "DEFINES.h" #include "Player.h" #include "Effect.h" diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 93f91c7f..27dbf03e 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 5583 +#define VERSION_BUILD 5618 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/Warrior.cpp b/Adventures in Lestoria/Warrior.cpp index 3295f64e..49702f55 100644 --- a/Adventures in Lestoria/Warrior.cpp +++ b/Adventures in Lestoria/Warrior.cpp @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #include "Class.h" -#include "olcPixelGameEngine.h" #include "DEFINES.h" #include "Player.h" #include "Effect.h" diff --git a/Adventures in Lestoria/Witch.cpp b/Adventures in Lestoria/Witch.cpp index f77afadc..d2da6561 100644 --- a/Adventures in Lestoria/Witch.cpp +++ b/Adventures in Lestoria/Witch.cpp @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #include "Class.h" -#include "olcPixelGameEngine.h" #include "DEFINES.h" #include "Player.h" #include "Effect.h" diff --git a/Adventures in Lestoria/Wizard.cpp b/Adventures in Lestoria/Wizard.cpp index 6bded088..ce98750a 100644 --- a/Adventures in Lestoria/Wizard.cpp +++ b/Adventures in Lestoria/Wizard.cpp @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #include "Class.h" -#include "olcPixelGameEngine.h" #include "DEFINES.h" #include "Player.h" #include "Effect.h" diff --git a/Adventures in Lestoria/config.h b/Adventures in Lestoria/config.h index 4665069a..9e713b9b 100644 --- a/Adventures in Lestoria/config.h +++ b/Adventures in Lestoria/config.h @@ -36,7 +36,6 @@ All rights reserved. */ #pragma endregion #pragma once -#include "olcPixelGameEngine.h" #include "olcUTIL_DataFile.h" using namespace olc; diff --git a/Adventures in Lestoria/olcPGEX_TTF.h b/Adventures in Lestoria/olcPGEX_TTF.h index 3f92b302..fe64d16d 100644 --- a/Adventures in Lestoria/olcPGEX_TTF.h +++ b/Adventures in Lestoria/olcPGEX_TTF.h @@ -38,6 +38,7 @@ All rights reserved. #ifndef OLC_PGEX_TTF_H #define OLC_PGEX_TTF_H +#include "olcUTIL_Geometry2D.h" #include "olcPixelGameEngine.h" #ifdef WIN32 diff --git a/Adventures in Lestoria/olcPGEX_ViewPort.h b/Adventures in Lestoria/olcPGEX_ViewPort.h index 65f99d60..b6bf24bb 100644 --- a/Adventures in Lestoria/olcPGEX_ViewPort.h +++ b/Adventures in Lestoria/olcPGEX_ViewPort.h @@ -1,6 +1,5 @@ #pragma once -#include "olcPixelGameEngine.h" #include "olcPGEX_TTF.h" #include "olcUTIL_Geometry2D.h" diff --git a/Adventures in Lestoria/olcPixelGameEngine.h b/Adventures in Lestoria/olcPixelGameEngine.h index 6d171855..39465712 100644 --- a/Adventures in Lestoria/olcPixelGameEngine.h +++ b/Adventures in Lestoria/olcPixelGameEngine.h @@ -401,6 +401,7 @@ return 0; #include #include #include "Error.h" +#include "olcUTIL_Geometry2D.h" #pragma endregion #define PGE_VER 223 @@ -669,7 +670,7 @@ namespace olc }; - +#define OLC_IGNORE_VEC2D // O------------------------------------------------------------------------------O // | olc::vX2d - A generic 2D vector type | @@ -7547,4 +7548,4 @@ using namespace olc; #define PI 3.14159f -using Color=PixelGameEngine; \ No newline at end of file +using Color=olc::PixelGameEngine; \ No newline at end of file diff --git a/Adventures in Lestoria/olcUTIL_Animate2D.h b/Adventures in Lestoria/olcUTIL_Animate2D.h index f8aea55d..a4438eb7 100644 --- a/Adventures in Lestoria/olcUTIL_Animate2D.h +++ b/Adventures in Lestoria/olcUTIL_Animate2D.h @@ -54,8 +54,8 @@ David Barr, aka javidx9, �OneLoneCoder 2019, 2020, 2021, 2022 #pragma once -#include "olcPixelGameEngine.h" #include "olcUTIL_Geometry2D.h" +#include "olcPixelGameEngine.h" namespace olc::utils::Animate2D { diff --git a/Adventures in Lestoria/olcUTIL_Camera2D.h b/Adventures in Lestoria/olcUTIL_Camera2D.h index 6333b78b..ac8080bd 100644 --- a/Adventures in Lestoria/olcUTIL_Camera2D.h +++ b/Adventures in Lestoria/olcUTIL_Camera2D.h @@ -51,10 +51,8 @@ Author David Barr, aka javidx9, �OneLoneCoder 2019, 2020, 2021, 2022 */ - #pragma once - -#include "olcPixelGameEngine.h" +#include "olcUTIL_Geometry2D.h" namespace olc::utils { diff --git a/Adventures in Lestoria/olcUTIL_DataFile.h b/Adventures in Lestoria/olcUTIL_DataFile.h index 3fa67a41..c15988f7 100644 --- a/Adventures in Lestoria/olcUTIL_DataFile.h +++ b/Adventures in Lestoria/olcUTIL_DataFile.h @@ -53,7 +53,7 @@ David Barr, aka javidx9, �OneLoneCoder 2019, 2020, 2021, 2022 */ #pragma once - +#include "olcPixelGameEngine.h" #include #include #include @@ -63,7 +63,6 @@ David Barr, aka javidx9, �OneLoneCoder 2019, 2020, 2021, 2022 #include #include #include "Error.h" -#include "olcPixelGameEngine.h" using namespace std::literals; diff --git a/Adventures in Lestoria/olcUTIL_Geometry2D.h b/Adventures in Lestoria/olcUTIL_Geometry2D.h index b81b769d..6a3130b9 100644 --- a/Adventures in Lestoria/olcUTIL_Geometry2D.h +++ b/Adventures in Lestoria/olcUTIL_Geometry2D.h @@ -1,64 +1,508 @@ /* -OneLoneCoder - Geometry 2D v1.01 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A collection of 2D Geometric primitives and functions to work with -and between them. - - -License (OLC-3) -~~~~~~~~~~~~~~~ - -Copyright 2018 - 2024 OneLoneCoder.com - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions or derivations of source code must retain the above -copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions or derivative works in binary form must reproduce -the above copyright notice. This list of conditions and the following -disclaimer must be reproduced in the documentation and/or other -materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived -from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Links -~~~~~ -YouTube: https://www.youtube.com/javidx9 -Discord: https://discord.gg/WhwHUMV -Twitter: https://www.twitter.com/javidx9 -Twitch: https://www.twitch.tv/javidx9 -GitHub: https://www.github.com/onelonecoder -Homepage: https://www.onelonecoder.com - -Author -~~~~~~ -David Barr, aka javidx9, �OneLoneCoder 2019, 2020, 2021, 2022 - -Changes: -v1.01: +Made constants inline -+Header guards (lol... sigh...) + OneLoneCoder - Geometry 2D v2.0 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + A collection of 2D Geometric primitives and functions to work with + and between them. + + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2024 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions or derivations of source code must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce + the above copyright notice. This list of conditions and the following + disclaimer must be reproduced in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + + Authors + ~~~~~~~ + David Barr, aka javidx9, (c) OneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024 + + With significant contributions from: + + Piratux, Gusgo99, Gorbit99, MaGetzUb, Dandistine, Moros1138 + cstdint, sigonasr, bixxy, Qwerasd, starfreakclone, fux + + Changes: + v1.01: +Made constants inline + +Header guards (lol... sigh...) + v2.0: +Major file contribution and restructuring */ +/* + What Is This? + ~~~~~~~~~~~~~ + + I've worked with 2D stuff for decades and I'm tired of reapeatedly researching, deriving + and implementing geometric analysis routines, so wanted a "one-stop-shop" to collate all + these mathematics. You don't even need olc::PixelGameEngine, this file will run as a + standalone 2D vector/geometry utility. + + As well as a robust 2D Vector implementation, this file offers definitions of the following + shapes: + + point - A 2D (x,y) vector from (0,0) + line - A line segment defined by a start and end point + circle - A circle defined by a middle point and a radius + rectangle - An axis aligned quad defined by a top left point, and a size + triangle - A triangle defined by 3 points + ray - A special case "line" with an origin and a direction + + Functions have been provided that yield useful analyses for almost every combination + of shapes. The function groups all have the same names, and are differentiated via + argument type: + + point closest(a, b) + Returns closest point on Shape A to Shape B + + bool overlaps(a, b) + Returns true if any part of Shape A overlaps any part of Shape B, including boundaries + + bool contains(a, b) + Returns true if Shape A wholly contains Shape B within and including it's boundary + + vector intersects(a, b) + Returns a vector of points where Shape A boundary intersects with Shape B boundary + + optional project(a, b, ray) + Projects Shape A along a ray, until and if it contacts shape B. If it never contacts + then nothing is returned. If it does contact the closest position Shape A can be to + Shape B is returned without the shapes overlapping + + rect envelope_r(a) / bounding_box(a) + Returns the minimum area rectangle that fully encompasses Shape A + + rect envelope_c(a) / bounding_circle(a) + Returns the minimum area circle that fully encompasses Shape A + + ray reflect(ray, a) + Returns a ray that is a reflection of supplied incident ray against Shape A + + optional collision(ray, a) + Returns the point and normal where a ray collides with Shape A + +*/ + +/* + Quick Navigation + ~~~~~~~~~~~~~~~~ + + To jump to an implementation quickly, use your editor to search in the following way: + + f(a, b) + + where: + + f = overlaps, intersects, contains, closest, envelope_r, envelope_b, reflects, collision + a = p, l, r, c, t, q, pol (point, line, rect, circ, triangle, ray, polygon) + + example: + + "contains(r,c)" - takes you to implementation for contains(rect, circ) + - Does the rectangle contain the circle? +*/ + +/* + Function Matrix - Function(A, B) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + A B>| POINT | LINE | RECT | CIRCLE | TRIANGLE | RAY | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + POINT | contains | contains | contains | contains | contains | | + | closest | closest | closest | closest | closest | closest | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + LINE | contains | contains | contains | contains | contains | | + | closest | | | closest | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + RECT | contains | contains | contains | contains | contains | | + | closest | | | | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + CIRCLE | contains | contains | contains | contains | contains | | + | closest | closest | | | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | project | project | | project | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + TRIANGLE | contains | contains | contains | contains | contains | | + | closest | | | | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + RAY | | | | | | | + | | | | | | | + | | collision | collision | collision | collision | collision* | + | | intersects | intersects | intersects | intersects | intersects | + | | reflect | reflect | reflect | reflect | reflect* | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + + * Exists but always fails +*/ + #pragma once -#include "olcPixelGameEngine.h" +#include +#include +#include +#include +#include +#include +#include + +#ifndef OLC_V2D_TYPE +#define OLC_V2D_TYPE +namespace olc +{ + /* + A complete 2D geometric vector structure, with a variety + of useful utility functions and operator overloads + */ + template + struct v_2d + { + static_assert(std::is_arithmetic::value, "olc::v_2d must be numeric"); + + // x-axis component + T x = 0; + // y-axis component + T y = 0; + + // Default constructor + inline constexpr v_2d() = default; + + // Specific constructor + inline constexpr v_2d(T _x, T _y) : x(_x), y(_y) + {} + + // Copy constructor + inline constexpr v_2d(const v_2d& v) = default; + + // Assignment operator + inline constexpr v_2d& operator=(const v_2d& v) = default; + + + // Returns rectangular area of vector + inline constexpr auto area() const + { + return x * y; + } + + // Returns magnitude of vector + inline auto mag() const + { + return std::sqrt(x * x + y * y); + } + + // Returns magnitude squared of vector (useful for fast comparisons) + inline constexpr T mag2() const + { + return x * x + y * y; + } + + // Returns normalised version of vector + inline v_2d norm() const + { + auto r = 1 / mag(); + return v_2d(x * r, y * r); + } + + // Returns vector at 90 degrees to this one + inline constexpr v_2d perp() const + { + return v_2d(-y, x); + } + + // Rounds both components down + inline constexpr v_2d floor() const + { + return v_2d(std::floor(x), std::floor(y)); + } + + // Rounds both components up + inline constexpr v_2d ceil() const + { + return v_2d(std::ceil(x), std::ceil(y)); + } + + // Returns 'element-wise' max of this and another vector + inline constexpr v_2d max(const v_2d& v) const + { + return v_2d(std::max(x, v.x), std::max(y, v.y)); + } + + // Returns 'element-wise' min of this and another vector + inline constexpr v_2d min(const v_2d& v) const + { + return v_2d(std::min(x, v.x), std::min(y, v.y)); + } + + // Calculates scalar dot product between this and another vector + inline constexpr auto dot(const v_2d& rhs) const + { + return this->x * rhs.x + this->y * rhs.y; + } + + // Calculates 'scalar' cross product between this and another vector (useful for winding orders) + inline constexpr auto cross(const v_2d& rhs) const + { + return this->x * rhs.y - this->y * rhs.x; + } + + // Treat this as polar coordinate (R, Theta), return cartesian equivalent (X, Y) + inline constexpr v_2d cart() const + { + return v_2d(std::cos(y) * x, std::sin(y) * x); + } + + // Treat this as cartesian coordinate (X, Y), return polar equivalent (R, Theta) + inline constexpr v_2d polar() const + { + return v_2d(mag(), std::atan2(y, x)); + } + + // Clamp the components of this vector in between the 'element-wise' minimum and maximum of 2 other vectors + inline constexpr v_2d clamp(const v_2d& v1, const v_2d& v2) const + { + return this->max(v1).min(v2); + } + + // Linearly interpolate between this vector, and another vector, given normalised parameter 't' + inline constexpr v_2d lerp(const v_2d& v1, const double t) const + { + return (T(1.0 - t)) + (v1 * T(t)); + } + + // Compare if this vector is numerically equal to another + inline constexpr bool operator == (const v_2d& rhs) const + { + return (this->x == rhs.x && this->y == rhs.y); + } + + // Compare if this vector is not numerically equal to another + inline constexpr bool operator != (const v_2d& rhs) const + { + return (this->x != rhs.x || this->y != rhs.y); + } + + // Return this vector as a std::string, of the form "(x,y)" + inline constexpr std::string str() const + { + return std::string("(") + std::to_string(this->x) + "," + std::to_string(this->y) + ")"; + } + + // Assuming this vector is incident, given a normal, return the reflection + inline constexpr v_2d reflect(const v_2d& n) const + { + return (*this) - 2.0 * (this->dot(n) * n); + } + + // Allow 'casting' from other v_2d types + template + inline constexpr operator v_2d() const + { + return { static_cast(this->x), static_cast(this->y) }; + } + }; + + // Multiplication operator overloads between vectors and scalars, and vectors and vectors + template + inline constexpr auto operator * (const TL& lhs, const v_2d& rhs) + { + return v_2d(lhs * rhs.x, lhs * rhs.y); + } + + template + inline constexpr auto operator * (const v_2d& lhs, const TR& rhs) + { + return v_2d(lhs.x * rhs, lhs.y * rhs); + } + + template + inline constexpr auto operator * (const v_2d& lhs, const v_2d& rhs) + { + return v_2d(lhs.x * rhs.x, lhs.y * rhs.y); + } + + template + inline constexpr auto operator *= (v_2d& lhs, const TR& rhs) + { + lhs = lhs * rhs; + return lhs; + } + + // Division operator overloads between vectors and scalars, and vectors and vectors + template + inline constexpr auto operator / (const TL& lhs, const v_2d& rhs) + { + return v_2d(lhs / rhs.x, lhs / rhs.y); + } + + template + inline constexpr auto operator / (const v_2d& lhs, const TR& rhs) + { + return v_2d(lhs.x / rhs, lhs.y / rhs); + } + + template + inline constexpr auto operator / (const v_2d& lhs, const v_2d& rhs) + { + return v_2d(lhs.x / rhs.x, lhs.y / rhs.y); + } + + template + inline constexpr auto operator /= (v_2d& lhs, const TR& rhs) + { + lhs = lhs / rhs; + return lhs; + } + + // Unary Addition operator (pointless but i like the platinum trophies) + template + inline constexpr auto operator + (const v_2d& lhs) + { + return v_2d(+lhs.x, +lhs.y); + } + + // Addition operator overloads between vectors and scalars, and vectors and vectors + template + inline constexpr auto operator + (const TL& lhs, const v_2d& rhs) + { + return v_2d(lhs + rhs.x, lhs + rhs.y); + } + + template + inline constexpr auto operator + (const v_2d& lhs, const TR& rhs) + { + return v_2d(lhs.x + rhs, lhs.y + rhs); + } + + template + inline constexpr auto operator + (const v_2d& lhs, const v_2d& rhs) + { + return v_2d(lhs.x + rhs.x, lhs.y + rhs.y); + } + + template + inline constexpr auto operator += (v_2d& lhs, const TR& rhs) + { + lhs = lhs + rhs; + return lhs; + } + + template + inline constexpr auto operator += (v_2d& lhs, const v_2d& rhs) + { + lhs = lhs + rhs; + return lhs; + } + + // Unary negation operator overoad for inverting a vector + template + inline constexpr auto operator - (const v_2d& lhs) + { + return v_2d(-lhs.x, -lhs.y); + } + + // Subtraction operator overloads between vectors and scalars, and vectors and vectors + template + inline constexpr auto operator - (const TL& lhs, const v_2d& rhs) + { + return v_2d(lhs - rhs.x, lhs - rhs.y); + } + + template + inline constexpr auto operator - (const v_2d& lhs, const TR& rhs) + { + return v_2d(lhs.x - rhs, lhs.y - rhs); + } + + template + inline constexpr auto operator - (const v_2d& lhs, const v_2d& rhs) + { + return v_2d(lhs.x - rhs.x, lhs.y - rhs.y); + } + + template + inline constexpr auto operator -= (v_2d& lhs, const TR& rhs) + { + lhs = lhs - rhs; + return lhs; + } + + // Greater/Less-Than Operator overloads - mathematically useless, but handy for "sorted" container storage + template + inline constexpr bool operator < (const v_2d& lhs, const v_2d& rhs) + { + return (lhs.y < rhs.y) || (lhs.y == rhs.y && lhs.x < rhs.x); + } + + template + inline constexpr bool operator > (const v_2d& lhs, const v_2d& rhs) + { + return (lhs.y > rhs.y) || (lhs.y == rhs.y && lhs.x > rhs.x); + } + + // Allow olc::v_2d to play nicely with std::cout + template + inline constexpr std::ostream& operator << (std::ostream& os, const v_2d& rhs) + { + os << rhs.str(); + return os; + } + + // Convenient types ready-to-go + typedef v_2d vi2d; + typedef v_2d vu2d; + typedef v_2d vf2d; + typedef v_2d vd2d; +} +#else + #include "olcPixelGameEngine.h" +#endif + + namespace olc::utils::geom2d { @@ -68,6 +512,35 @@ namespace olc::utils::geom2d // Floating point error margin inline const double epsilon = 0.001; + namespace internal + { + template + inline std::vector> filter_duplicate_points(const std::vector>& points) { + std::vector> filtered_points; + + for (const auto& point : points) + { + bool is_duplicate = false; + + for (const auto& filtered_point : filtered_points) + { + if (std::abs(point.x - filtered_point.x) < epsilon && std::abs(point.y - filtered_point.y) < epsilon) + { + is_duplicate = true; + break; + } + } + + if (!is_duplicate) + { + filtered_points.push_back(point); + } + } + + return filtered_points; + } + }; + //https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c template constexpr int sgn(T val) { return (T(0) < val) - (val < T(0)); } @@ -76,48 +549,50 @@ namespace olc::utils::geom2d template struct line { - olc::v2d_generic start; - olc::v2d_generic end; + olc::v_2d start; + olc::v_2d end; - inline line(const olc::v2d_generic& s = { T(0), T(0) }, - const olc::v2d_generic& e = { T(0), T(0) }) + inline line(const olc::v_2d& s = { T(0), T(0) }, + const olc::v_2d& e = { T(0), T(0) }) : start(s), end(e) { } + // Get vector pointing from start to end + inline constexpr olc::v_2d vector() const + { + return (end - start); + } // Get length of line inline constexpr T length() { - return (end - start).mag(); + return vector().mag(); } // Get length of line^2 inline constexpr T length2() { - return (end - start).mag2(); + return vector().mag2(); } - inline constexpr olc::v2d_generic vector() const - { - return (end - start); - } + // Given a real distance, get point along line - inline constexpr olc::v2d_generic rpoint(const T& distance) const + inline constexpr olc::v_2d rpoint(const T& distance) const { - return start + (end - start).norm() * distance; + return start + vector().norm() * distance; } // Given a unit distance, get point along line - inline constexpr olc::v2d_generic upoint(const T& distance) const + inline constexpr olc::v_2d upoint(const T& distance) const { - return start + (end - start) * distance; + return start + vector() * distance; } // Return which side of the line does a point lie - inline constexpr int32_t side(const olc::v2d_generic& point) const + inline constexpr int32_t side(const olc::v_2d& point) const { - double d = (end - start).cross(point - start); + double d = vector().cross(point - start); if (d < 0) return -1; else @@ -126,27 +601,52 @@ namespace olc::utils::geom2d else return 0; } + + // Returns line equation "mx + a" coefficients where: + // x: m + // y: a + // NOTE: Returns {inf, inf} if std::abs(end.x - start.x) < epsilon: + inline constexpr olc::vd2d coefficients() const + { + double x1 = start.x; + double x2 = end.x; + double y1 = start.y; + double y2 = end.y; + + // check if line is vertical or close to vertical + if (std::abs(x2 - x1) < epsilon) { + return olc::vd2d{ std::numeric_limits::infinity(), std::numeric_limits::infinity() }; + } + + double m = (y2 - y1) / (x2 - x1); + return olc::vd2d {m, -m * x1 + y1}; + } }; template struct ray { - olc::v2d_generic origin; - olc::v2d_generic direction; + olc::v_2d origin; + olc::v_2d direction; + + inline ray(const olc::v_2d& o = { T(0), T(0) }, + const olc::v_2d& d = { T(0), T(0) }) + : origin(o), direction(d) + { } }; template struct rect { - olc::v2d_generic pos; - olc::v2d_generic size; + olc::v_2d pos; + olc::v_2d size; - inline rect(const olc::v2d_generic& p = { T(0), T(0) }, - const olc::v2d_generic& s = { T(1), T(1) }) + inline rect(const olc::v_2d& p = { T(0), T(0) }, + const olc::v_2d& s = { T(1), T(1) }) : pos(p), size(s) { } - inline olc::v2d_generic middle() const + inline olc::v_2d middle() const { return pos + (size * double(0.5)); } @@ -178,10 +678,11 @@ namespace olc::utils::geom2d // Get a line from an indexed side, starting top, going clockwise inline line side(const size_t i) const { - if (i & (0b11 == 0)) return top(); - if (i & (0b11 == 1)) return right(); - if (i & (0b11 == 2)) return bottom(); - if (i & (0b11 == 3)) return left(); + if ((i & 0b11) == 0) return top(); + if ((i & 0b11) == 1) return right(); + if ((i & 0b11) == 2) return bottom(); + //if ((i & 0b11) == 3) return left(); // Dumb compilers cant fathom this + return left(); } // Get area of rectangle @@ -195,44 +696,21 @@ namespace olc::utils::geom2d { return T(2) * (size.x + size.y); } - }; - - template - struct ellipse - { - olc::v2d_generic pos; - olc::v2d_generic radius; - - inline ellipse(const olc::v2d_generic& p = { T(0), T(0) }, const olc::v2d_generic r = {T(1),T(1)}) - : pos(p), radius(r) - { } - - // Get area of ellipse - inline constexpr T area() const - { - return T(pi) * radius.x * radius.y; - } - - // Get perimeter of an ellipse - inline constexpr T perimeter() const - { - return T(2.0 * pi) * sqrt((radius.x*radius.x+radius.y*radius.y)/(2*1.0)); - } - // Get circumference of ellipse. Which is the same as a permieter of one. - inline constexpr T circumference() const - { - return perimeter(); + // Returns side count: 4 + inline constexpr size_t side_count() const { + return 4; } }; + template struct circle { - olc::v2d_generic pos; + olc::v_2d pos; T radius = T(0); - inline circle(const olc::v2d_generic& p = { T(0), T(0) }, const T r = T(0)) + inline circle(const olc::v_2d& p = { T(0), T(0) }, const T r = T(0)) : pos(p), radius(r) { } @@ -259,12 +737,12 @@ namespace olc::utils::geom2d template struct triangle { - std::array, 3> pos; + std::array, 3> pos; inline triangle( - const olc::v2d_generic& p0 = { T(0), T(0) }, - const olc::v2d_generic& p1 = { T(0), T(0) }, - const olc::v2d_generic& p2 = { T(0), T(0) }) + const olc::v_2d& p0 = { T(0), T(0) }, + const olc::v_2d& p1 = { T(0), T(0) }, + const olc::v_2d& p2 = { T(0), T(0) }) : pos{ p0,p1,p2 } { } @@ -290,57 +768,93 @@ namespace olc::utils::geom2d + line(pos[1], pos[2]).length() + line(pos[2], pos[0]).length(); } + + // Returns side count: 3 + inline constexpr size_t side_count() const { + return 3; + } }; template struct polygon { - std::vector> vPoints; + std::vector> pos; }; // ========================================================================================================================= // Closest(shape, point) =================================================================================================== - // Returns closest point to point + // Closest location on [SHAPE] to Point + + // closest(p,p) + // Returns closest point on point to any shape (aka the original point) :P template - inline olc::v2d_generic closest(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + inline olc::v_2d closest(const olc::v_2d& p, [[maybe_unused]] const T2& anything_who_cares) { - return p1; + return p; } + // closest(l,p) // Returns closest point on line to point template - inline olc::v2d_generic closest(const line& l, const olc::v2d_generic& p) + inline olc::v_2d closest(const line& l, const olc::v_2d& p) { auto d = l.vector(); double u = std::clamp(double(d.dot(p - l.start)) / d.mag2(), 0.0, 1.0); return l.start + u * d; } + // closest(c,p) // Returns closest point on circle to point template - inline olc::v2d_generic closest(const circle& c, const olc::v2d_generic& p) + inline olc::v_2d closest(const circle& c, const olc::v_2d& p) { return c.pos + olc::vd2d(p - c.pos).norm() * c.radius; } + // closest(r,p) // Returns closest point on rectangle to point template - inline olc::v2d_generic closest(const rect& r, const olc::v2d_generic& p) + inline olc::v_2d closest(const rect& r, const olc::v_2d& p) { - // This could be a "constrain" function hmmmm - // TODO: Not quite what i wanted, should restrain to boundary - return olc::v2d_generic{ std::clamp(p.x, r.pos.x, r.pos.x + r.size.x), std::clamp(p.y, r.pos.y, r.pos.y + r.size.y) }; + // Note: this algorithm can be reused for polygon + auto c1 = closest(r.top(), p); + auto c2 = closest(r.bottom(), p); + auto c3 = closest(r.left(), p); + auto c4 = closest(r.right(), p); + + auto d1 = (c1 - p).mag2(); + auto d2 = (c2 - p).mag2(); + auto d3 = (c3 - p).mag2(); + auto d4 = (c4 - p).mag2(); + + auto dmin = d1; + auto cmin = c1; + + if (d2 < dmin) { + dmin = d2; + cmin = c2; + } + if (d3 < dmin) { + dmin = d3; + cmin = c3; + } + if (d4 < dmin) { + dmin = d4; + cmin = c4; + } + return cmin; } + // closest(t,p) // Returns closest point on triangle to point template - inline olc::v2d_generic closest(const triangle& t, const olc::v2d_generic& p) + inline olc::v_2d closest(const triangle& t, const olc::v_2d& p) { - olc::utils::geom2d::line l{t.pos[0], t.pos[1]}; + olc::utils::geom2d::line l{ t.pos[0], t.pos[1] }; auto p0 = closest(l, p); auto d0 = (p0 - p).mag2(); @@ -352,118 +866,233 @@ namespace olc::utils::geom2d auto p2 = closest(l, p); auto d2 = (p2 - p).mag2(); - if((d0 <= d1) && (d0 <= d2)) { + if ((d0 <= d1) && (d0 <= d2)) { return p0; - } else if((d1 <= d0) && (d1 <= d2)) { + } + else if ((d1 <= d0) && (d1 <= d2)) { return p1; - } else { + } + else { return p2; } } + // Closest location on [SHAPE] to Line - - - - - - - - - // ================================================================================================================ - // POINT ========================================================================================================== - - // Checks if point contains point + // closest(l,l) + // Returns closest point on line to line template - inline constexpr bool contains(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + inline olc::v_2d closest(const line& l1, const line& l2) { - return (p1 - p2).mag2() < epsilon; + // TODO: + return {}; } - // Checks if line contains point + // closest(r,l) + // Returns closest point on rectangle to line template - inline constexpr bool contains(const line& l, const olc::v2d_generic& p) + inline olc::v_2d closest(const rect& r, const line& l) { - double d = ((p.x - l.start.x) * (l.end.y - l.start.y) - (p.y - l.start.y) * (l.end.x - l.start.x)); - if (std::abs(d) < epsilon) - { - // point is on line - double u = l.vector().dot(p - l.start) / l.vector().mag2(); - return (u >= double(0.0) && u <= double(1.0)); - } - - return false; + // TODO: + return {}; } - // Checks if rectangle contains point + // closest(c,l) + // Returns closest point on circle to line template - inline constexpr bool contains(const rect& r, const olc::v2d_generic& p) + inline olc::v_2d closest(const circle& c, const line& l) { - return !(p.x < r.pos.x || p.y < r.pos.y || - p.x > (r.pos.x + r.size.x) || p.y > (r.pos.y + r.size.y)); + const auto p1 = closest(l, c.pos); + return c.pos + olc::vd2d(p1 - c.pos).norm() * c.radius; } - // Checks if ellipse contains a point + // closest(t,l) + // Returns closest point on triangle to line template - inline constexpr bool contains(const ellipse& c, const olc::v2d_generic& p) + inline olc::v_2d closest(const triangle& t, const line& l) { - return std::pow(p.x-c.pos.x,2)/(c.radius.x*c.radius.x)+std::pow(p.y-c.pos.y,2)/(c.radius.y*c.radius.y)<1; + // TODO: + return {}; } - // Checks if circle contains a point + + // Closest location on [SHAPE] to Circle + + // closest(l,c) + // Returns closest point on line to circle template - inline constexpr bool contains(const circle& c, const olc::v2d_generic& p) + inline olc::v_2d closest(const line& l, const circle& c) { - return (c.pos - p).mag2() < (c.radius * c.radius); + const auto p1 = closest(c, l); // Closest point on circle to line + return closest(l, p1); } - // Checks if triangle contains a point + // closest(r,c) + // Returns closest point on rectangle to circle template - inline constexpr bool contains(const triangle& t, const olc::v2d_generic& p) + inline olc::v_2d closest(const rect& r, const circle& l) { - // http://jsfiddle.net/PerroAZUL/zdaY8/1/ - T2 A = T2(0.5) * (-t.pos[1].y * t.pos[2].x + t.pos[0].y * (-t.pos[1].x + t.pos[2].x) + t.pos[0].x * (t.pos[1].y - t.pos[2].y) + t.pos[1].x * t.pos[2].y); - T2 sign = A < T2(0) ? T2(-1) : T2(1); - T2 s = (t.pos[0].y * t.pos[2].x - t.pos[0].x * t.pos[2].y + (t.pos[2].y - t.pos[0].y) * p.x + (t.pos[0].x - t.pos[2].x) * p.y) * sign; - T2 v = (t.pos[0].x * t.pos[1].y - t.pos[0].y * t.pos[1].x + (t.pos[0].y - t.pos[1].y) * p.x + (t.pos[1].x - t.pos[0].x) * p.y) * sign; - return s > T2(0) && v > T2(0) && (s + v) < T2(2) * A * sign; + // TODO: + return {}; } + // closest(c,c) + // Returns closest point on circle to circle + template + inline olc::v_2d closest(const circle& c, const circle& l) + { + // TODO: + return {}; + } + + // closest(t,c) + // Returns closest point on triangle to circle + template + inline olc::v_2d closest(const triangle& r, const circle& l) + { + // TODO: + return {}; + } + + + // Closest location on [SHAPE] to Triangle + + // closest(l,t) + // Returns closest point on line to triangle + template + inline olc::v_2d closest(const line& l, const triangle& c) + { + // TODO: + return {}; + } + + // closest(r,t) + // Returns closest point on rectangle to triangle + template + inline olc::v_2d closest(const rect& r, const triangle& l) + { + // TODO: + return {}; + } + + // closest(c,t) + // Returns closest point on circle to triangle + template + inline olc::v_2d closest(const circle& c, const triangle& l) + { + // TODO: + return {}; + } + + // closest(t,t) + // Returns closest point on triangle to triangle + template + inline olc::v_2d closest(const triangle& r, const triangle& l) + { + // TODO: + return {}; + } + + + + + + // ================================================================================================================ + // POINT ========================================================================================================== + + // contains(p,p) + // Checks if point contains point + template + inline constexpr bool contains(const olc::v_2d& p1, const olc::v_2d& p2) + { + return (p1 - p2).mag2() < epsilon; + } + + // contains(l,p) + // Checks if line contains point + template + inline constexpr bool contains(const line& l, const olc::v_2d& p) + { + double d = ((p.x - l.start.x) * (l.end.y - l.start.y) - (p.y - l.start.y) * (l.end.x - l.start.x)); + if (std::abs(d) < epsilon) + { + // point is on line + double u = l.vector().dot(p - l.start) / l.vector().mag2(); + return (u >= double(0.0) && u <= double(1.0)); + } + + return false; + } + + // contains(r,p) + // Checks if rectangle contains point + template + inline constexpr bool contains(const rect& r, const olc::v_2d& p) + { + return !(p.x < r.pos.x || p.y < r.pos.y || + p.x > (r.pos.x + r.size.x) || p.y > (r.pos.y + r.size.y)); + } + + // contains(c,p) + // Checks if circle contains a point + template + inline constexpr bool contains(const circle& c, const olc::v_2d& p) + { + return (c.pos - p).mag2() <= (c.radius * c.radius); + } + + // contains(t,p) + // Checks if triangle contains a point + template + inline constexpr bool contains(const triangle& t, const olc::v_2d& p) + { + // http://jsfiddle.net/PerroAZUL/zdaY8/1/ + T2 A = T2(0.5) * (-t.pos[1].y * t.pos[2].x + t.pos[0].y * (-t.pos[1].x + t.pos[2].x) + t.pos[0].x * (t.pos[1].y - t.pos[2].y) + t.pos[1].x * t.pos[2].y); + T2 sign = A < T2(0) ? T2(-1) : T2(1); + T2 s = (t.pos[0].y * t.pos[2].x - t.pos[0].x * t.pos[2].y + (t.pos[2].y - t.pos[0].y) * p.x + (t.pos[0].x - t.pos[2].x) * p.y) * sign; + T2 v = (t.pos[0].x * t.pos[1].y - t.pos[0].y * t.pos[1].x + (t.pos[0].y - t.pos[1].y) * p.x + (t.pos[1].x - t.pos[0].x) * p.y) * sign; + return s >= T2(0) && v >= T2(0) && (s + v) <= T2(2) * A * sign; + } - + + // overlaps(p,p) // Check if point overlaps with point (analagous to contains()) template - inline constexpr bool overlaps(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + inline constexpr bool overlaps(const olc::v_2d& p1, const olc::v_2d& p2) { return contains(p1, p2); } + // overlaps(l,p) // Checks if line segment overlaps with point template - inline constexpr bool overlaps(const line& l, const olc::v2d_generic& p) + inline constexpr bool overlaps(const line& l, const olc::v_2d& p) { return contains(l, p); } + // overlaps(r,p) // Checks if rectangle overlaps with point template - inline constexpr bool overlaps(const rect& r, const olc::v2d_generic& p) + inline constexpr bool overlaps(const rect& r, const olc::v_2d& p) { return contains(r, p); } + // overlaps(c,p) // Checks if circle overlaps with point template - inline constexpr bool overlaps(const circle& c, const olc::v2d_generic& p) + inline constexpr bool overlaps(const circle& c, const olc::v_2d& p) { return contains(c, p); } + // overlaps(t,p) // Checks if triangle overlaps with point template - inline constexpr bool overlaps(const triangle& t, const olc::v2d_generic& p) + inline constexpr bool overlaps(const triangle& t, const olc::v_2d& p) { return contains(t, p); } @@ -471,54 +1100,62 @@ namespace olc::utils::geom2d + // intersects(p,p) // Get intersection points where point intersects with point template - inline std::vector> intersects(const olc::v2d_generic& p1, const olc::v2d_generic& p2) + inline std::vector> intersects(const olc::v_2d& p1, const olc::v_2d& p2) { if (contains(p1, p2)) return { p1 }; - else - return {}; + + return {}; } + // intersects(l,p) // Get intersection points where line segment intersects with point template - inline std::vector> intersects(const line& l, const olc::v2d_generic& p) + inline std::vector> intersects(const line& l, const olc::v_2d& p) { if (contains(l, p)) return { p }; - else - return {}; + + return {}; } + // intersects(r,p) // Get intersection points where rectangle intersects with point template - inline std::vector> intersects(const rect& r, const olc::v2d_generic& p) + inline std::vector> intersects(const rect& r, const olc::v_2d& p) { - std::vector> vPoints; - if (contains(r.top(), p)) vPoints.push_back(p); - if (contains(r.bottom(), p)) vPoints.push_back(p); - if (contains(r.left(), p)) vPoints.push_back(p); - if (contains(r.right(), p)) vPoints.push_back(p); - return vPoints; + for (size_t i = 0; i < r.side_count(); i++) + if (contains(r.side(i), p)) + return { p }; + + return {}; } + // intersects(c,p) // Get intersection points where circle intersects with point template - inline std::vector> intersects(const circle& c, const olc::v2d_generic& p) + inline std::vector> intersects(const circle& c, const olc::v_2d& p) { if (std::abs((p - c.pos).mag2() - (c.radius * c.radius)) <= epsilon) return { p }; - else - return {}; + + return {}; } + // intersects(t,p) // Get intersection points where triangle intersects with point template - inline std::vector> intersects(const triangle& r, const olc::v2d_generic& p) + inline std::vector> intersects(const triangle& t, const olc::v_2d& p) { - // TODO: + for (size_t i = 0; i < t.side_count(); i++) + if (contains(t.side(i), p)) + return { p }; + return {}; + } @@ -535,21 +1172,23 @@ namespace olc::utils::geom2d // ================================================================================================================ // LINE =========================================================================================================== + // contains(p,l) // Check if point contains line segment template - inline constexpr bool contains(const olc::v2d_generic& p, const line& l) + inline constexpr bool contains([[maybe_unused]] const olc::v_2d& p, [[maybe_unused]] const line& l) { return false; // It can't! } + // contains(l,l) // Check if line segment contains line segment template inline constexpr bool contains(const line& l1, const line& l2) { - // TODO: Check if segments are colinear, and l1 exists within bounds of l2 - return false; + return overlaps(l1, l2.start) && overlaps(l1, l2.end); } + // contains(r,l) // Check if rectangle contains line segment template inline constexpr bool contains(const rect& r, const line& l) @@ -557,6 +1196,7 @@ namespace olc::utils::geom2d return contains(r, l.start) && contains(r, l.end); } + // contains(c,l) // Check if circle contains line segment template inline constexpr bool contains(const circle& c1, const line& l) @@ -564,6 +1204,7 @@ namespace olc::utils::geom2d return contains(c1, l.start) && contains(c1, l.end); } + // contains(t,l) // Check if triangle contains line segment template inline constexpr bool contains(const triangle& t, const line& l) @@ -573,107 +1214,160 @@ namespace olc::utils::geom2d - + // overlaps(p,l) // Check if point overlaps line segment template - inline constexpr bool overlaps(const olc::v2d_generic& p, const line& l) + inline constexpr bool overlaps(const olc::v_2d& p, const line& l) { return contains(l, p); } + // overlaps(l,l) // Check if line segment overlaps line segment template inline constexpr bool overlaps(const line& l1, const line& l2) { - float uA = ((l2.end.x-l2.start.x)*(l1.start.y-l2.start.y) - (l2.end.y-l2.start.y)*(l1.start.x-l2.start.x)) / ((l2.end.y-l2.start.y)*(l1.end.x-l1.start.x) - (l2.end.x-l2.start.x)*(l1.end.y-l1.start.y)); - float uB = ((l1.end.x-l1.start.x)*(l1.start.y-l2.start.y) - (l1.end.y-l1.start.y)*(l1.start.x-l2.start.x)) / ((l2.end.y-l2.start.y)*(l1.end.x-l1.start.x) - (l2.end.x-l2.start.x)*(l1.end.y-l1.start.y)); + double D = ((l2.end.y - l2.start.y) * (l1.end.x - l1.start.x) - (l2.end.x - l2.start.x) * (l1.end.y - l1.start.y)); + double uA = ((l2.end.x-l2.start.x)*(l1.start.y-l2.start.y) - (l2.end.y-l2.start.y)*(l1.start.x-l2.start.x)) / D; + double uB = ((l1.end.x-l1.start.x)*(l1.start.y-l2.start.y) - (l1.end.y-l1.start.y)*(l1.start.x-l2.start.x)) / D; return uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1; } + // overlaps(r,l) // Check if rectangle overlaps line segment template inline constexpr bool overlaps(const rect& r, const line& l) { - return overlaps(r.left(),l)|| - overlaps(r.top(),l)|| - overlaps(r.bottom(),l)|| - overlaps(r.right(),l); + return contains(r, l.start) + || overlaps(r.top(), l) + || overlaps(r.bottom(), l) + || overlaps(r.left(), l) + || overlaps(r.right(), l); } + // overlaps(c,l) // Check if circle overlaps line segment template inline constexpr bool overlaps(const circle& c, const line& l) { - // TODO: - return false; + auto vClosest = closest(l, c.pos); + return ((c.pos - vClosest).mag2() <= (c.radius * c.radius)); } + // overlaps(t,l) // Check if triangle overlaps line segment template inline constexpr bool overlaps(const triangle& t, const line& l) { - return overlaps(t, l.start) || overlaps(t, l.end); - - // TODO: This method is no good, it cant detect lines whose start and end - // points are outside the triangle + return overlaps(t, l.start) || overlaps(t.side(0), l) || overlaps(t.side(1), l) || overlaps(t.side(2), l); } - + // intersects(p,l) // Get intersection points where point intersects with line segment template - inline std::vector> intersects(const olc::v2d_generic& p, const line& l) + inline std::vector> intersects(const olc::v_2d& p, const line& l) { - // TODO: - return {}; + return intersects(l, p); } + // intersects(l,l) // Get intersection points where line segment intersects with line segment template - inline std::vector> intersects(const line& l1, const line& l2) + inline std::vector> intersects(const line& l1, const line& l2) { - float uA = ((l2.end.x-l2.start.x)*(l1.start.y-l2.start.y) - (l2.end.y-l2.start.y)*(l1.start.x-l2.start.x)) / ((l2.end.y-l2.start.y)*(l1.end.x-l1.start.x) - (l2.end.x-l2.start.x)*(l1.end.y-l1.start.y)); - float uB = ((l1.end.x-l1.start.x)*(l1.start.y-l2.start.y) - (l1.end.y-l1.start.y)*(l1.start.x-l2.start.x)) / ((l2.end.y-l2.start.y)*(l1.end.x-l1.start.x) - (l2.end.x-l2.start.x)*(l1.end.y-l1.start.y)); + float rd = l1.vector().cross(l2.vector()); + if (rd == 0) return {}; // Parallel or Colinear TODO: Return two points - if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) { - float intersectionX = l1.start.x + (uA * (l1.end.x-l1.start.x)); - float intersectionY = l1.start.y + (uA * (l1.end.y-l1.start.y)); - return {{intersectionX,intersectionY}}; - } - return {}; + //Inverse rd product + rd = 1.f / rd; + + //Cross products: + //rn = (b1b2 x b1a1) + float rn = ((l2.end.x - l2.start.x) * (l1.start.y - l2.start.y) - (l2.end.y - l2.start.y) * (l1.start.x - l2.start.x)) * rd; + //sn = (a1a2 x b1a1) + float sn = ((l1.end.x - l1.start.x) * (l1.start.y - l2.start.y) - (l1.end.y - l1.start.y) * (l1.start.x - l2.start.x)) * rd; + + //Return the intersection depth + //if (d) *d = rn; + + if (rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f) + return {}; // Intersection not within line segment + + return { l1.start + rn * l1.vector()}; } + // intersects(r,l) // Get intersection points where rectangle intersects with line segment template - inline std::vector> intersects(const rect& r, const line& l) + inline std::vector> intersects(const rect& r, const line& l) { - std::vector>intersections; - std::vector>result=intersects(r.left(),l); - if(result.size()>0)intersections.push_back(result[0]); - result=intersects(r.right(),l); - if(result.size()>0)intersections.push_back(result[0]); - result=intersects(r.top(),l); - if(result.size()>0)intersections.push_back(result[0]); - result=intersects(r.bottom(),l); - if(result.size()>0)intersections.push_back(result[0]); - return intersections; + std::vector> intersections; + + for (size_t i = 0; i < r.side_count(); i++) + { + auto v = intersects(r.side(i), l); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); } + // intersects(c,l) // Get intersection points where circle intersects with line segment template - inline std::vector> intersects(const circle& c, const line& l) + inline std::vector> intersects(const circle& c, const line& l) { - // TODO: - return {}; + const auto closestPointToSegment = closest(l, c.pos); + if (!overlaps(c, closestPointToSegment)) + { + // Circle is too far away + return {}; + } + + // Compute point closest to the circle on the line + const auto d = l.vector(); + const auto uLine = d.dot(c.pos - l.start) / d.mag2(); + const auto closestPointToLine = l.start + uLine * d; + const auto distToLine = (c.pos - closestPointToLine).mag2(); + + if (std::abs(distToLine - c.radius * c.radius) < epsilon) + { + // Circle "kisses" the line + return { closestPointToLine }; + } + + // Circle intersects the line + const auto length = std::sqrt(c.radius * c.radius - distToLine); + const auto p1 = closestPointToLine + l.vector().norm() * length; + const auto p2 = closestPointToLine - l.vector().norm() * length; + + std::vector> intersections; + intersections.reserve(2); + + if ((p1 - closest(l, p1)).mag2() < epsilon * epsilon) + intersections.push_back(p1); + if ((p2 - closest(l, p2)).mag2() < epsilon * epsilon) + intersections.push_back(p2); + + return internal::filter_duplicate_points(intersections); } + // intersects(t,l) // Get intersection points where triangle intersects with line segment template - inline std::vector> intersects(const triangle& t, const line& l) + inline std::vector> intersects(const triangle& t, const line& l) { - // TODO: - return {}; + std::vector> intersections; + + for (size_t i = 0; i < t.side_count(); i++) + { + auto v = intersects(t.side(i), l); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); } @@ -690,58 +1384,64 @@ namespace olc::utils::geom2d // ================================================================================================================ // RECTANGLE ====================================================================================================== + // contains(p,r) // Check if point contains rectangle template - inline constexpr bool contains(const olc::v2d_generic& p, const rect& r) + inline constexpr bool contains([[maybe_unused]] const olc::v_2d& p, [[maybe_unused]] const rect& r) { return false; // It can't! } + // contains(l,r) // Check if line segment contains rectangle template - inline constexpr bool contains(const line& l, const rect& r) + inline constexpr bool contains([[maybe_unused]] const line& l, [[maybe_unused]] const rect& r) { return false; // It can't } + // contains(r,r) // Check if rectangle contains rectangle template inline constexpr bool contains(const rect& r1, const rect& r2) { - return (r2.pos.x >= r1.pos.x) && (r2.pos.x + r2.size.x < r1.pos.x + r1.size.x) && - (r2.pos.y >= r1.pos.y) && (r2.pos.y + r2.size.y < r1.pos.y + r1.size.y); + return (r2.pos.x >= r1.pos.x) && (r2.pos.x + r2.size.x <= r1.pos.x + r1.size.x) && + (r2.pos.y >= r1.pos.y) && (r2.pos.y + r2.size.y <= r1.pos.y + r1.size.y); } + // contains(c,r) // Check if circle contains rectangle template inline constexpr bool contains(const circle& c, const rect& r) { return contains(c, r.pos) - && contains(c, olc::v2d_generic{ r.pos.x + r.size.x, r.pos.y }) - && contains(c, olc::v2d_generic{ r.pos.x, r.pos.y + r.size.y }) + && contains(c, olc::v_2d{ r.pos.x + r.size.x, r.pos.y }) + && contains(c, olc::v_2d{ r.pos.x, r.pos.y + r.size.y }) && contains(c, r.pos + r.size); } + // contains(t,r) // Check if triangle contains rectangle template inline constexpr bool contains(const triangle& t, const rect& r) { return contains(t, r.pos) && contains(t, r.pos + r.size) - && contains(t, olc::v2d_generic{ r.pos.x + r.size.x,r.pos.y }) - && contains(t, olc::v2d_generic{ r.pos.x, r.pos.y + r.size.y }); + && contains(t, olc::v_2d{ r.pos.x + r.size.x,r.pos.y }) + && contains(t, olc::v_2d{ r.pos.x, r.pos.y + r.size.y }); } - + // overlaps(p,r) // Check if point overlaps rectangle template - inline constexpr bool overlaps(const olc::v2d_generic& p, const rect& r) + inline constexpr bool overlaps(const olc::v_2d& p, const rect& r) { return overlaps(r, p); } + // overlaps(l,r) // Check if line segment overlaps rectangle template inline constexpr bool overlaps(const line& l, const rect& r) @@ -749,14 +1449,16 @@ namespace olc::utils::geom2d return overlaps(r, l); } + // overlaps(r,r) // Check if rectangle overlaps rectangle template inline constexpr bool overlaps(const rect& r1, const rect& r2) { - return (r1.pos.x < r2.pos.x + r2.size.x && r1.pos.x + r1.size.x >= r2.pos.x && - r1.pos.y < r2.pos.y + r2.size.y && r1.pos.y + r1.size.y >= r2.pos.y); + return (r1.pos.x <= r2.pos.x + r2.size.x && r1.pos.x + r1.size.x >= r2.pos.x && + r1.pos.y <= r2.pos.y + r2.size.y && r1.pos.y + r1.size.y >= r2.pos.y); } + // overlaps(c,r) // Check if circle overlaps rectangle template inline constexpr bool overlaps(const circle& c, const rect& r) @@ -764,63 +1466,85 @@ namespace olc::utils::geom2d // Inspired by this (very clever btw) // https://stackoverflow.com/questions/45370692/circle-rectangle-collision-response // But modified to work :P - T2 overlap = (olc::v2d_generic{ std::clamp(c.pos.x, r.pos.x, r.pos.x + r.size.x), std::clamp(c.pos.y, r.pos.y, r.pos.y + r.size.y) } - c.pos).mag2(); - if (std::isnan(overlap)) overlap = T2(0); - return (overlap - (c.radius * c.radius)) < T2(0); + double overlap = (olc::v_2d{ std::clamp(c.pos.x, r.pos.x, r.pos.x + r.size.x), std::clamp(c.pos.y, r.pos.y, r.pos.y + r.size.y) } - c.pos).mag2(); + if (std::isnan(overlap)) overlap = 0; + return (overlap - (c.radius * c.radius)) < 0; } + // overlaps(t,r) // Check if triangle overlaps rectangle template inline constexpr bool overlaps(const triangle& t, const rect& r) { - return contains(t, r.pos) - || contains(t, r.pos + r.size) - || contains(t, olc::v2d_generic{ r.pos.x + r.size.x, r.pos.y }) - || contains(t, olc::v2d_generic{ r.pos.x, r.pos.y + r.size.y }); - - // TODO: This method is no good, consider rectangle with all vertices - // outside of triangle, but edges still crossing + return overlaps(t, r.top()) + || overlaps(t, r.bottom()) + || overlaps(t, r.left()) + || overlaps(t, r.right()) + || contains(r, t.pos[0]); } - + // intersects(p,r) // Get intersection points where point intersects with rectangle template - inline std::vector> intersects(const olc::v2d_generic& p, const rect& r) + inline std::vector> intersects(const olc::v_2d& p, const rect& r) { return intersects(r, p); } + // intersects(l,r) // Get intersection points where line segment intersects with rectangle template - inline std::vector> intersects(const line& l, const rect& r) + inline std::vector> intersects(const line& l, const rect& r) { return intersects(r,l); } + // intersects(r,r) // Get intersection points where rectangle intersects with rectangle template - inline std::vector> intersects(const rect& r1, const rect& r2) + inline std::vector> intersects(const rect& r1, const rect& r2) { - // TODO: - return {}; + std::vector> intersections; + + for (size_t i = 0; i < r2.side_count(); i++) { + auto v = intersects(r1, r2.side(i)); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); } + // intersects(c,r) // Get intersection points where circle intersects with rectangle template - inline std::vector> intersects(const circle& c, const rect& r) + inline std::vector> intersects(const circle& c, const rect& r) { - // TODO: - return {}; + std::vector> intersections; + + for (size_t i = 0; i < r.side_count(); i++) + { + auto v = intersects(c, r.side(i)); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); } + // intersects(t,r) // Get intersection points where triangle intersects with rectangle template - inline std::vector> intersects(const triangle& t, const rect& r) + inline std::vector> intersects(const triangle& t, const rect& r) { - // TODO: - return {}; + std::vector> intersections; + + for (size_t i = 0; i < r.side_count(); i++) { + auto v = intersects(t, r.side(i)); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); } @@ -838,53 +1562,61 @@ namespace olc::utils::geom2d // ================================================================================================================ // CIRCLE ========================================================================================================= + // contains(p,c) // Check if point contains circle template - inline constexpr bool contains(const olc::v2d_generic& p, const circle& c) + inline constexpr bool contains([[maybe_unused]] const olc::v_2d& p, [[maybe_unused]] const circle& c) { return false; // It can't! } + // contains(l,c) // Check if line segment contains circle template - inline constexpr bool contains(const line& l, const circle& c) + inline constexpr bool contains([[maybe_unused]] const line& l, [[maybe_unused]] const circle& c) { return false; // It can't! } + // contains(r,c) // Check if rectangle contains circle template inline constexpr bool contains(const rect& r, const circle& c) { - // TODO: - return false; + return r.pos.x + c.radius <= c.pos.x + && c.pos.x <= r.pos.x + r.size.x - c.radius + && r.pos.y + c.radius <= c.pos.y + && c.pos.y <= r.pos.y + r.size.y - c.radius; } + // contains(c,c) // Check if circle contains circle template inline constexpr bool contains(const circle& c1, const circle& c2) { - return (c1.pos - c2.pos).mag2() <= (c1.radius - c2.radius) * (c1.radius - c2.radius); + return (std::sqrt(std::pow(c2.pos.x - c1.pos.x, 2) + std::pow(c2.pos.y - c1.pos.y, 2)) + c2.radius) <= c1.radius; + } + // contains(t,c) // Check if triangle contains circle template inline constexpr bool contains(const triangle& t, const circle& c) { - // TODO: - return false; + return contains(t, c.pos) && (c.pos - closest(t, c.pos)).mag2() >= c.radius * c.radius; } - + // overlaps(p,c) // Check if point overlaps circle template - inline constexpr bool overlaps(const olc::v2d_generic& p, const circle& c) + inline constexpr bool overlaps(const olc::v_2d& p, const circle& c) { return overlaps(c, p); } + // overlaps(l,c) // Check if line segment overlaps circle template inline constexpr bool overlaps(const line& l, const circle& c) @@ -892,6 +1624,7 @@ namespace olc::utils::geom2d return overlaps(c, l); } + // overlaps(r,c) // Check if rectangle overlaps circle template inline constexpr bool overlaps(const rect& r, const circle& c) @@ -899,6 +1632,7 @@ namespace olc::utils::geom2d return overlaps(c, r); } + // overlaps(c,c) // Check if circle overlaps circle template inline constexpr bool overlaps(const circle& c1, const circle& c2) @@ -906,55 +1640,97 @@ namespace olc::utils::geom2d return (c1.pos - c2.pos).mag2() <= (c1.radius + c2.radius) * (c1.radius + c2.radius); } + // overlaps(t,c) // Check if triangle overlaps circle template inline constexpr bool overlaps(const triangle& t, const circle& c) { - // TODO: - return false; + return contains(t, c.pos) || (c.pos - closest(t, c.pos)).mag2() <= c.radius * c.radius; } - + // intersects(p,c) // Get intersection points where point intersects with circle template - inline std::vector> intersects(const olc::v2d_generic& p, const circle& c) + inline std::vector> intersects(const olc::v_2d& p, const circle& c) { - // TODO: - return {}; + return intersects(c, p); } + // intersects(l,c) // Get intersection points where line segment intersects with circle template - inline std::vector> intersects(const line& l, const circle& c) + inline std::vector> intersects(const line& l, const circle& c) { - // TODO: - return {}; + return intersects(c, l); } + // intersects(r,c) // Get intersection points where rectangle intersects with circle template - inline std::vector> intersects(const rect& r, const circle& c) + inline std::vector> intersects(const rect& r, const circle& c) { - // TODO: - return {}; + return intersects(c, r); } + // intersects(c,c) // Get intersection points where circle intersects with circle template - inline std::vector> intersects(const circle& c1, const circle& c2) - { - // TODO: - return {}; - } - + inline std::vector> intersects(const circle& c1, const circle& c2) + { + if (c1.pos == c2.pos) return {}; // circles are either within one another so cannot intersect, or are + // identical so share all points which there's no good way to represent in return value. + v_2d between = c2.pos - c1.pos; + float dist2 = between.mag2(); + float radiusSum = c1.radius + c2.radius; + if (dist2 > radiusSum*radiusSum) return {}; // circles are too far apart to be touching. + if (contains(c1, c2) || contains(c2, c1)) return {}; // one circle is inside of the other, they can't be intersecting. + if (dist2 == radiusSum) return {c1.pos + between.norm() * c1.radius}; // circles are touching at exactly 1 point + // otherwise they're touching at 2 points. + // + // ______ ________ + // .'' ''.X' ''. X = intersections + // / / |\ \ O = chordCenter + // | | | | | In order to find the intersections we first find O. + // ( c1--(--O-)--c2 ) To do this, we find the distance c1->O by solving for the + // | | | | | two right triangles formed by the chord and c1->c2 (L). + // \ \ |/ / . Pythagorean theorem: + // '. .'X ,' .'|\ (L-x)^2 + h^2 = c1.r^2 + // ''----'' ''------'' c1.r / | \ c2.radius x^2 + h^2 = c2.r^2 + // .' h| \ Subtract 1 equation from the other and solve: + // /_____|___\ (L-x)^2 + h^2 - (x^2 + h^2) = c1.r^2 - c2.r^2 + // x L-x (L-x)^2 - x^2 = c1.r^2 - c2.r^2 + // L^2 - 2Lx = c1.r^2 - c2.r^2 + // 2Lx - L^2 = c2.r^2 - c1.r^2 + // v------------<-----------------<-----------------<-----. x = (L^2 + c2.r^2 - c1.r^2)/2 -. + // Next, we have to solve for the height h, and move '-------<--------------------<-----' + // that distance from O, perpendicular to c1->c2. + // + // Pythagorean theorem: x^2 + h^2 = c1.r^2 -> c1.r^2 - x^2 = h^2 -> h = sqrt(c1.r^2 - x^2) + // + // x is ccDist and h is halfChord. + // + float dist = std::sqrt(dist2); + float ccDist = (dist2 + c1.radius * c1.radius - c2.radius * c2.radius)/(2*dist); + v_2d chordCenter = c1.pos + between.norm() * ccDist; + v_2d halfChord = between.norm().perp() * std::sqrt(c1.radius * c1.radius - ccDist * ccDist); + return {chordCenter + halfChord, chordCenter - halfChord}; + } + + // intersects(t,c) // Get intersection points where triangle intersects with circle template - inline std::vector> intersects(const triangle& t, const circle& c) + inline std::vector> intersects(const triangle& t, const circle& c) { - // TODO: - return {}; + std::vector> intersections; + + for (size_t i = 0; i < t.side_count(); i++) { + auto v = intersects(c, t.side(i)); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); } @@ -972,54 +1748,63 @@ namespace olc::utils::geom2d // ================================================================================================================ // TRIANGLE ======================================================================================================= + // contains(p,t) // Check if point contains triangle template - inline constexpr bool contains(const olc::v2d_generic& p, const triangle& t) + inline constexpr bool contains([[maybe_unused]] const olc::v_2d& p, [[maybe_unused]] const triangle& t) { return false; // It can't! } + // contains(l,t) // Check if line segment contains triangle template - inline constexpr bool contains(const line& l, const triangle& t) + inline constexpr bool contains([[maybe_unused]] const line& l, [[maybe_unused]] const triangle& t) { return false; // It can't } + // contains(r,t) // Check if rectangle contains triangle template inline constexpr bool contains(const rect& r, const triangle& t) { - // TODO: - return false; + return contains(r, t.side(0)) + && contains(r, t.side(1)) + && contains(r, t.side(2)); } + // contains(c,t) // Check if circle contains triangle template inline constexpr bool contains(const circle& c, const triangle& t) { - // TODO: - return false; + return contains(c, t.pos[0]) + && contains(c, t.pos[1]) + && contains(c, t.pos[2]); } + // contains(t,t) // Check if triangle contains triangle template inline constexpr bool contains(const triangle& t1, const triangle& t2) { - // TODO: - return false; + return contains(t1, t2.pos[0]) + && contains(t1, t2.pos[1]) + && contains(t1, t2.pos[2]); } - + // overlaps(p,t) // Check if point overlaps triangle template - inline constexpr bool overlaps(const olc::v2d_generic& p, const triangle& t) + inline constexpr bool overlaps(const olc::v_2d& p, const triangle& t) { return overlaps(t, p); } + // overlaps(l,t) // Check if line segment overlaps triangle template inline constexpr bool overlaps(const line& l, const triangle& t) @@ -1027,6 +1812,7 @@ namespace olc::utils::geom2d return overlaps(t, l); } + // overlaps(r,t) // Check if rectangle overlaps triangle template inline constexpr bool overlaps(const rect& r, const triangle& t) @@ -1034,6 +1820,7 @@ namespace olc::utils::geom2d return overlaps(t, r); } + // overlaps(c,t) // Check if circle overlaps triangle template inline constexpr bool overlaps(const circle& c, const triangle& t) @@ -1041,57 +1828,607 @@ namespace olc::utils::geom2d return overlaps(t, c); } + // overlaps(t,t) // Check if triangle overlaps triangle template inline constexpr bool overlaps(const triangle& t1, const triangle& t2) { - // TODO: - return false; + return overlaps(t1, t2.side(0)) + || overlaps(t1, t2.side(1)) + || overlaps(t1, t2.side(2)) + || overlaps(t2, t1.pos[0]); } - + // intersects(p,t) // Get intersection points where point intersects with triangle template - inline std::vector> intersects(const olc::v2d_generic& p, const triangle& t) + inline std::vector> intersects(const olc::v_2d& p, const triangle& t) { - // TODO: - return {}; + return intersects(t, p); } + // intersects(l,t) // Get intersection points where line segment intersects with triangle template - inline std::vector> intersects(const line& l, const triangle& t) + inline std::vector> intersects(const line& l, const triangle& t) { - // TODO: - return {}; + return intersects(t, l); } + // intersects(r,t) // Get intersection points where rectangle intersects with triangle template - inline std::vector> intersects(const rect& r, const triangle& t) + inline std::vector> intersects(const rect& r, const triangle& t) { - // TODO: - return {}; + return intersects(t, r); } + // intersects(c,t) // Get intersection points where circle intersects with triangle template - inline std::vector> intersects(const circle& c, const triangle& t) + inline std::vector> intersects(const circle& c, const triangle& t) { - // TODO: - return {}; + return intersects(t, c); } + // intersects(t,t) // Get intersection points where triangle intersects with triangle template - inline std::vector> intersects(const triangle& t1, const triangle& t2) + inline std::vector> intersects(const triangle& t1, const triangle& t2) + { + std::vector> intersections; + + for (size_t i = 0; i < t2.side_count(); i++) { + auto v = intersects(t1, t2.side(i)); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); + } + + + // envelope_c(c) + // Return circle that fully encapsulates a point + template + inline constexpr circle envelope_c(const olc::v_2d& p) + { + return circle(p, 0); + } + + + + // envelope_c(l) + // Return circle that fully encapsulates a line + template + inline constexpr circle envelope_c(const line& l) + { + return {l.upoint(0.5),l.vector().mag()/2}; + } + + // envelope_c(r) + // Return circle that fully encapsulates a rectangle + template + inline constexpr circle envelope_c(const rect& r) + { + // Construct the circle from the rectangle's diagonal + return envelope_c(line(r.pos, r.pos + r.size)); + } + + // envelope_c(c) + // Return circle that fully encapsulates a circle + template + inline constexpr circle envelope_c(const circle& c) + { + return c; + } + + // envelope_c(t) + // Return circle that fully encapsulates a triangle + template + inline constexpr circle envelope_c(const triangle& t) + { + olc::v_2d circumcenter; + + double D = 2 * (t.pos[0].x * (t.pos[1].y - t.pos[2].y) + t.pos[1].x * (t.pos[2].y - t.pos[0].y) + t.pos[2].x * (t.pos[0].y - t.pos[1].y)); + circumcenter.x = T1(double( + (t.pos[0].x * t.pos[0].x + t.pos[0].y * t.pos[0].y) * (t.pos[1].y - t.pos[2].y) + + (t.pos[1].x * t.pos[1].x + t.pos[1].y * t.pos[1].y) * (t.pos[2].y - t.pos[0].y) + + (t.pos[2].x * t.pos[2].x + t.pos[2].y * t.pos[2].y) * (t.pos[0].y - t.pos[1].y) + ) / D); + circumcenter.y = T1(double( + (t.pos[0].x * t.pos[0].x + t.pos[0].y * t.pos[0].y) * (t.pos[2].x - t.pos[1].x) + + (t.pos[1].x * t.pos[1].x + t.pos[1].y * t.pos[1].y) * (t.pos[0].x - t.pos[2].x) + + (t.pos[2].x * t.pos[2].x + t.pos[2].y * t.pos[2].y) * (t.pos[1].x - t.pos[0].x) + ) / D); + + double r = 0; + for (auto& point : t.pos) { + r = std::max(r, double(std::hypot(circumcenter.x - point.x, circumcenter.y - point.y))); + } + + return {circumcenter, T1(r)}; + } + + + + + + + + + // envelope_r(p) + // Return rectangle that fully encapsulates a point + template + inline constexpr rect envelope_r(const olc::v_2d& p) + { + return rect(p, { 0,0 }); + } + + // envelope_r(l) + // Return rectangle that fully encapsulates a line + template + inline constexpr rect envelope_r(const line& l) + { + T1 min_x=std::min(l.start.x,l.end.x); + T1 min_y=std::min(l.start.y,l.end.y); + T1 size_x=std::abs(l.start.x-l.end.x); + T1 size_y=std::abs(l.start.y-l.end.y); + return {{min_x,min_y},{size_x,size_y}}; + } + + // envelope_r(r) + // Return rectangle that fully encapsulates a rectangle + template + inline constexpr rect envelope_r(const rect& r) + { + return r; + } + + // envelope_r(c) + // Return rectangle that fully encapsulates a circle + template + inline constexpr rect envelope_r(const circle& c) + { + return rect(c.pos - v_2d{c.radius, c.radius}, { c.radius * 2, c.radius * 2 }); + } + + // envelope_r(t) + // Return rectangle that fully encapsulates a triangle + template + inline constexpr rect envelope_r(const triangle& t) + { + auto vMin = t.pos[0].min(t.pos[1].min(t.pos[2])); + auto vMax = t.pos[0].max(t.pos[1].max(t.pos[2])); + return rect(vMin, vMax - vMin); + } + + template + inline constexpr auto bounding_box(T&& t) + { + return envelope_r(std::forward(t)); + } + + template + inline constexpr auto bounding_circle(T&& t) + { + return envelope_c(std::forward(t)); + } + + + // PROJECTIONS ========================================================================================================== + + // project(c,p) + // project a circle, onto a point, via a ray (i.e. how far along the ray can the circle travel until it contacts the point?) + template + inline std::optional> project(const circle& c, const olc::v_2d& p, const ray& q) + { + return project(c, circle(p, 0), q); + } + + + // project(c,c) + // project a circle, onto a circle, via a ray (i.e. how far along the ray can the circle travel until it contacts the other circle?) + template + inline std::optional> project(const circle& c1, const circle& c2, const ray& q) + { + // Inspired by https://math.stackexchange.com/a/929240 + + double A = q.direction.mag2(); + double B = 2.0 * (q.origin.dot(q.direction) - c2.pos.dot(q.direction)); + double C = c2.pos.mag2() + q.origin.mag2() - (2.0 * c2.pos.x * q.origin.x) - (2.0 * c2.pos.y * q.origin.y) - ((c1.radius + c2.radius) * (c1.radius + c2.radius)); + double D = B * B - 4.0 * A * C; + + if (D < 0.0) + return std::nullopt; + else + { + const auto sD = std::sqrt(D); + const auto s1 = (-B + sD) / (2.0 * A); + const auto s2 = (-B - sD) / (2.0 * A); + + if (s1 < 0 && s2 < 0) + return std::nullopt; + if (s1 < 0) + return q.origin + q.direction * s2; + if (s2 < 0) + return q.origin + q.direction * s1; + + return q.origin + q.direction * std::min(s1, s2); + } + } + + // project(c,l) + // project a circle, onto a line segment, via a ray + template + inline std::optional> project(const circle& c, const line& l, const ray& q) + { + // Treat line segment as capsule with radius that of the circle + // and treat the circle as a point + + // First do we hit ends of line segment, inflated to be circles + const auto vHitsStartCirc = intersects(q, circle(l.start, c.radius)); + const auto vHitsEndCirc = intersects(q, circle(l.end, c.radius)); + + // Now create two line segments in parallel to the original, that join + // up the end circles to form the sides of the capsule + const auto displace = l.vector().norm().perp() * c.radius; + const auto vHitsSide1 = intersects(q, line(l.start + displace, l.end + displace)); + const auto vHitsSide2 = intersects(q, line(l.start - displace, l.end - displace)); + + // Bring the multitude of points to one place + std::vector> vAllIntersections; + vAllIntersections.insert(vAllIntersections.end(), vHitsStartCirc.begin(), vHitsStartCirc.end()); + vAllIntersections.insert(vAllIntersections.end(), vHitsEndCirc.begin(), vHitsEndCirc.end()); + vAllIntersections.insert(vAllIntersections.end(), vHitsSide1.begin(), vHitsSide1.end()); + vAllIntersections.insert(vAllIntersections.end(), vHitsSide2.begin(), vHitsSide2.end()); + + if (vAllIntersections.size() == 0) + { + // No intersections at all, so + return std::nullopt; + } + + // Find closest + double dClosest = std::numeric_limits::max(); + olc::v_2d vClosest; + for (const auto& vContact : vAllIntersections) + { + double dDistance = (vContact - c.pos).mag2(); + if (dDistance < dClosest) + { + dClosest = dDistance; + vClosest = vContact; + } + } + + return vClosest; + } + + // project(c,r) + // project a circle, onto a rectangle, via a ray + template + inline std::optional> project(const circle& c, const rect& r, const ray& q) + { + // TODO: + return std::nullopt; + } + + // project(c,t) + // project a circle, onto a triangle, via a ray + template + inline std::optional> project(const circle& c, const triangle& t, const ray& q) + { + // TODO: + return std::nullopt; + } + + + // RAYS ================================================================================================================= + + // intersects(q,q) + // return intersection point (if it exists) of a ray and a ray + template + inline std::vector> intersects(const ray& q1, const ray& q2) + { + const auto origin_diff = q2.origin - q1.origin; + const auto cp1 = q1.direction.cross(q2.direction); + const auto cp2 = origin_diff.cross(q2.direction); + + if (cp1 == 0) // Early rejection + { + if (cp2 == 0) + return { q1.origin }; // co-linear + else + return {}; // parallel + } + + const auto cp3 = origin_diff.cross(q1.direction); + const auto t1 = cp2 / cp1; // distance along q1 to intersection + const auto t2 = cp3 / cp1; // distance along q2 to intersection + + if (t1 >= 0 && t2 >= 0) + return { q1.origin + q1.direction * t1 }; // Intersection, both rays positive + else + return {}; // Intersection, but behind a rays origin, so not really an intersection in context + } + + // intersects(q,p) + // return intersection point (if it exists) of a ray and a point + template + inline std::vector> intersects(const ray& q, const v_2d& p) + { + const line l = { q.origin, q.origin + q.direction }; + + if (std::abs(l.side(p)) < epsilon ) + return { p }; // Intersection + else + return {}; + } + + // intersects(q,l) + // return intersection point (if it exists) of a ray and a line segment + template + inline std::vector> intersects(const ray& q, const line& l) + { + const auto line_direction = l.vector(); + const auto origin_diff = l.start - q.origin; + const auto cp1 = q.direction.cross(line_direction); + const auto cp2 = origin_diff.cross(line_direction); + + if (cp1 == 0) // Early rejection + { + if (cp2 == 0) + return { q.origin }; // co-linear + else + return {}; // parallel + } + + const auto cp3 = origin_diff.cross(q.direction); + const auto t1 = cp2 / cp1; // distance along ray to intersection + const auto t2 = cp3 / cp1; // distance along line segment to intersection + + if (t1 >= 0 && t2 >= 0 && t2 <= 1) + return { q.origin + q.direction * t1 }; // Intersection, both rays positive + else + return {}; // Intersection, but behind a rays origin, or outside line segment bounds. + // so not really an intersection in context + } + + // collision(q,l) + // optionally returns collision point and collision normal of ray and a line segment, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const line& l) + { + const auto vIntersection = intersects(q, l); + if (vIntersection.size() > 0) + { + return { {vIntersection[0], l.vector().perp().norm() * l.side(q.origin)} }; + } + + return std::nullopt; + } + + // reflect(q,l) + // optionally returns a ray reflected off a line segement if collision occurs + template + inline std::optional> reflect(const ray& q, const line& l) + { + const auto vCollision = collision(q, l); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; + } + + // reflect(q,p) + // optionally returns a ray reflected off a point if collision occurs + template + inline std::optional> reflect(const ray& q, const olc::v_2d& p) { // TODO: - return {}; + return std::nullopt; + } + + // collision(q,r) + // optionally returns collision point and collision normal of ray and a line segment, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const rect& r) + { + olc::v_2d vClosestIntersection; + olc::v_2d vIntersectionNormal; + double dClosestDistance2 = std::numeric_limits::max(); + bool bCollide = false; + + for (size_t i = 0; i < r.side_count(); i++) + { + auto v = intersects(q, r.side(i)); + if (v.size() > 0) + { + bCollide = true; + double d = (v[0] - q.origin).mag2(); + if (d < dClosestDistance2) + { + dClosestDistance2 = d; + vClosestIntersection = v[0]; + vIntersectionNormal = r.side(i).vector().perp().norm(); + } + } + } + + if (bCollide) + { + return { {vClosestIntersection, vIntersectionNormal} }; + } + + return std::nullopt; + } + + // reflect(q,r) + // optionally returns a ray reflected off a rectangle if collision occurs + template + inline std::optional> reflect(const ray& q, const rect& r) + { + const auto vCollision = collision(q, r); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; } + // collision(q,c) + // optionally returns collision point and collision normal of ray and a circle, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const circle& c) + { + const auto vIntersection = intersects(q, c); + if (vIntersection.size() > 0) + { + return { {vIntersection[0], (vIntersection[0] - c.pos).norm()}}; + } + + return std::nullopt; + } + + // reflect(q,c) + // optionally returns a ray reflected off a circle if collision occurs + template + inline std::optional> reflect(const ray& q, const circle& c) + { + const auto vCollision = collision(q, c); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; + } + + // collision(q,r) + // optionally returns collision point and collision normal of ray and a triangle, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const triangle& t) + { + olc::v_2d vClosestIntersection; + olc::v_2d vIntersectionNormal; + double dClosestDistance2 = std::numeric_limits::max(); + bool bCollide = false; + + for (size_t i = 0; i < t.side_count(); i++) + { + auto v = intersects(q, t.side(i)); + if (v.size() > 0) + { + bCollide = true; + double d = (v[0] - q.origin).mag2(); + if (d < dClosestDistance2) + { + dClosestDistance2 = d; + vClosestIntersection = v[0]; + vIntersectionNormal = t.side(i).vector().perp().norm(); + } + } + } + + if (bCollide) + { + return { {vClosestIntersection, vIntersectionNormal} }; + } + + return std::nullopt; + } + + // reflect(q,t) + // optionally returns a ray reflected off a triangle if collision occurs + template + inline std::optional> reflect(const ray& q, const triangle& t) + { + const auto vCollision = collision(q, t); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; + } + + // reflect(q,r) + // can't reflect a ray of a ray + template + inline std::optional> reflect(const ray& q1, const ray& q2) + { + // Can't reflect! + return std::nullopt; + } + + + // intersects(q,c) + // Get intersection points where a ray intersects a circle + template + inline std::vector> intersects(const ray& q, const circle& c) + { + // Look familiar? + double A = q.direction.mag2(); + double B = 2.0 * (q.origin.dot(q.direction) - c.pos.dot(q.direction)); + double C = c.pos.mag2() + q.origin.mag2() - (2.0 * c.pos.x * q.origin.x) - (2.0 * c.pos.y * q.origin.y) - (c.radius * c.radius); + double D = B * B - 4.0 * A * C; + + if (D < 0.0) + return {}; + else + { + const auto sD = std::sqrt(D); + const auto s1 = (-B + sD) / (2.0 * A); + const auto s2 = (-B - sD) / (2.0 * A); + + if (s1 < 0 && s2 < 0) + return {}; + if (s1 < 0) + return { q.origin + q.direction * s2 }; + if (s2 < 0) + return { q.origin + q.direction * s1 }; + + return { q.origin + q.direction * std::min(s1, s2) }; + } + } + + // intersects(q,r) + // Get intersection points where a ray intersects a rectangle + template + inline std::vector> intersects(const ray& q, const rect& r) + { + std::vector> intersections; + + for (size_t i = 0; i < r.side_count(); i++) + { + auto v = intersects(q, r.side(i)); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); + } + + // intersects(q,t) + // Get intersection points where a ray intersects a triangle + template + inline std::vector> intersects(const ray& q, const triangle& t) + { + std::vector> intersections; + + for (size_t i = 0; i < t.side_count(); i++) + { + auto v = intersects(q, t.side(i)); + intersections.insert(intersections.end(), v.begin(), v.end()); + } + + return internal::filter_duplicate_points(intersections); + } } +using namespace olc; using namespace olc::utils; \ No newline at end of file diff --git a/Adventures in Lestoria/pixelGameEngine.cpp b/Adventures in Lestoria/pixelGameEngine.cpp index f841f5e6..220aaec1 100644 --- a/Adventures in Lestoria/pixelGameEngine.cpp +++ b/Adventures in Lestoria/pixelGameEngine.cpp @@ -41,6 +41,7 @@ All rights reserved. #include "olcPGEX_TTF.h" #define OLC_PGEX_VIEWPORT #include "olcPGEX_ViewPort.h" +#include "olcUTIL_Geometry2D.h" #define OLC_PGE_APPLICATION #include "olcPixelGameEngine.h" #define OLC_PGEX_TRANSFORMEDVIEW diff --git a/Adventures in Lestoria/util.h b/Adventures in Lestoria/util.h index 133288ba..aa81a505 100644 --- a/Adventures in Lestoria/util.h +++ b/Adventures in Lestoria/util.h @@ -38,6 +38,7 @@ All rights reserved. #pragma once #include #include "olcUTIL_Geometry2D.h" +#include "olcPGEX_TTF.h" #include namespace olc::util{