├── .gitignore ├── CHANGELOG ├── Config ├── DefaultEditor.ini ├── DefaultEngine.ini └── DefaultGame.ini ├── Content └── Maps │ └── EmptyLevel.umap ├── GeometricTests.uproject ├── LICENSE ├── README.md └── Source ├── GeometricTests.Target.cs ├── GeometricTests ├── GeometricTestLibrary.h ├── GeometricTests.Build.cs ├── GeometricTests.cpp ├── GeometricTests.h ├── GeometricTestsGameModeBase.cpp ├── GeometricTestsGameModeBase.h ├── Math │ ├── LinearAlgebra │ │ ├── Quaternion.h │ │ └── Vector.h │ └── Operations │ │ └── MathOperations.h └── Primitives │ ├── AABB.h │ ├── Circle.h │ ├── Plane.h │ ├── Ray.h │ └── Triangle.h └── GeometricTestsEditor.Target.cs /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | # Visual Studio 2015 user specific files 5 | .vs/ 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.ipa 36 | 37 | # These project files can be generated by the engine 38 | *.xcodeproj 39 | *.xcworkspace 40 | *.sln 41 | *.suo 42 | *.opensdf 43 | *.sdf 44 | *.VC.db 45 | *.VC.opendb 46 | 47 | # Precompiled Assets 48 | SourceArt/**/*.png 49 | SourceArt/**/*.tga 50 | 51 | # Binary Files 52 | Binaries/* 53 | Plugins/*/Binaries/* 54 | 55 | # Builds 56 | Build/* 57 | 58 | # Debug 59 | Debug/ 60 | 61 | # Whitelist PakBlacklist-.txt files 62 | !Build/*/ 63 | Build/*/** 64 | !Build/*/PakBlacklist*.txt 65 | 66 | # Don't ignore icon files in Build 67 | !Build/**/*.ico 68 | 69 | # Built data for maps 70 | *_BuiltData.uasset 71 | 72 | # Configuration files generated by the Editor 73 | Saved/* 74 | 75 | # Compiled source files for the engine to use 76 | Intermediate/* 77 | Plugins/*/Intermediate/* 78 | 79 | # Cache files for the editor to use 80 | LocalDerivedDataCache/* 81 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2018-12-05: v1.0.0: 2 | + Initial Commit 3 | 4 | 2018-12-11: v1.1.0: 5 | + Added copying and moving behavior to each of the geometric primitive data structures 6 | + Fixed logging messages in GeometricTestLibrary.h 7 | + Simplified Vector2 syntax in Vector.h 8 | + Added new primitive to library, Triangle.h 9 | 10 | 2019-01-08: v1.1.1: 11 | + Improved comments in GeometricTestLibrary.h 12 | 13 | 2019-01-10: v1.1.2: 14 | + Negated "r" for solving of reflection vector in GeometricTestLibrary.h 15 | 16 | 2019-02-07: v1.1.3: 17 | + Added Quaternion.h 18 | 19 | 2019-04-07: v1.2.0: 20 | + Fixed solutions for intersection of two spheres and intersection of sphere and plane 21 | 22 | 2019-04-10: v1.2.1: 23 | + Removed typos from lines 655-657 in GeometricTestLibrary.h 24 | -------------------------------------------------------------------------------- /Config/DefaultEditor.ini: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Config/DefaultEngine.ini: -------------------------------------------------------------------------------- 1 | [URL] 2 | [/Script/EngineSettings.GameMapsSettings] 3 | EditorStartupMap=/Game/Maps/ClosestPointOnPlane.ClosestPointOnPlane 4 | GameDefaultMap=/Game/Maps/ClosestPointOnPlane.ClosestPointOnPlane 5 | GlobalDefaultGameMode=/Script/GeometricTests.GeometricTestsGameModeBase 6 | 7 | [/Script/HardwareTargeting.HardwareTargetingSettings] 8 | TargetedHardwareClass=Desktop 9 | AppliedTargetedHardwareClass=Desktop 10 | DefaultGraphicsPerformance=Maximum 11 | AppliedDefaultGraphicsPerformance=Maximum 12 | 13 | [/Script/IOSRuntimeSettings.IOSRuntimeSettings] 14 | bSupportsPortraitOrientation=False 15 | bSupportsUpsideDownOrientation=False 16 | bSupportsLandscapeLeftOrientation=True 17 | PreferredLandscapeOrientation=LandscapeLeft 18 | 19 | [/Script/Engine.PhysicsSettings] 20 | DefaultGravityZ=-980.000000 21 | DefaultTerminalVelocity=4000.000000 22 | DefaultFluidFriction=0.300000 23 | SimulateScratchMemorySize=262144 24 | RagdollAggregateThreshold=4 25 | TriangleMeshTriangleMinAreaThreshold=5.000000 26 | bEnableAsyncScene=False 27 | bEnableShapeSharing=False 28 | bEnablePCM=True 29 | bEnableStabilization=False 30 | bWarnMissingLocks=True 31 | bEnable2DPhysics=False 32 | PhysicErrorCorrection=(PingExtrapolation=0.100000,PingLimit=100.000000,ErrorPerLinearDifference=1.000000,ErrorPerAngularDifference=1.000000,MaxRestoredStateError=1.000000,MaxLinearHardSnapDistance=400.000000,PositionLerp=0.000000,AngleLerp=0.400000,LinearVelocityCoefficient=100.000000,AngularVelocityCoefficient=10.000000,ErrorAccumulationSeconds=0.500000,ErrorAccumulationDistanceSq=15.000000,ErrorAccumulationSimilarity=100.000000) 33 | LockedAxis=Invalid 34 | DefaultDegreesOfFreedom=Full3D 35 | BounceThresholdVelocity=200.000000 36 | FrictionCombineMode=Average 37 | RestitutionCombineMode=Average 38 | MaxAngularVelocity=3600.000000 39 | MaxDepenetrationVelocity=0.000000 40 | ContactOffsetMultiplier=0.020000 41 | MinContactOffset=2.000000 42 | MaxContactOffset=8.000000 43 | bSimulateSkeletalMeshOnDedicatedServer=True 44 | DefaultShapeComplexity=CTF_UseSimpleAndComplex 45 | bDefaultHasComplexCollision=True 46 | bSuppressFaceRemapTable=False 47 | bSupportUVFromHitResults=False 48 | bDisableActiveActors=False 49 | bDisableKinematicStaticPairs=False 50 | bDisableKinematicKinematicPairs=False 51 | bDisableCCD=False 52 | bEnableEnhancedDeterminism=False 53 | MaxPhysicsDeltaTime=0.033333 54 | bSubstepping=False 55 | bSubsteppingAsync=False 56 | MaxSubstepDeltaTime=0.016667 57 | MaxSubsteps=6 58 | SyncSceneSmoothingFactor=0.000000 59 | AsyncSceneSmoothingFactor=0.990000 60 | InitialAverageFrameRate=0.016667 61 | PhysXTreeRebuildRate=10 62 | DefaultBroadphaseSettings=(bUseMBPOnClient=False,bUseMBPOnServer=False,MBPBounds=(Min=(X=0.000000,Y=0.000000,Z=0.000000),Max=(X=0.000000,Y=0.000000,Z=0.000000),IsValid=0),MBPNumSubdivs=2) 63 | -------------------------------------------------------------------------------- /Config/DefaultGame.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1robertslattery/GeometricTestLibrary/73b309e08afd3f31f5b4c2f4a8d3cf33e8cd0699/Config/DefaultGame.ini -------------------------------------------------------------------------------- /Content/Maps/EmptyLevel.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1robertslattery/GeometricTestLibrary/73b309e08afd3f31f5b4c2f4a8d3cf33e8cd0699/Content/Maps/EmptyLevel.umap -------------------------------------------------------------------------------- /GeometricTests.uproject: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "EngineAssociation": "4.21", 4 | "Category": "", 5 | "Description": "", 6 | "Modules": [ 7 | { 8 | "Name": "GeometricTests", 9 | "Type": "Runtime", 10 | "LoadingPhase": "Default" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Geometric Test Library 2 | Solves 2D and 3D math problems, including, `closest point`, `intersection`, `line of sight` and `reflection vector`. 3 | 4 | ## OVERVIEW 5 | 6 | This project aims to teach 3D math. Everything can be found in the header file `GeometricTestLibrary.h`. 7 | Since these tests are commonly used in video games, this repository includes the Unreal Engine 4 project `GeometricTests.uproject`. 8 | These tests are designed to be used with any `C++` application or game engine, however. The project is released under the Apache 2.0 License. 9 | 10 | **Examples:** 11 | - 1. Closest Point in AABB 12 | - 2. Closest Point on a Ray 13 | - 3. Closest Point on a Plane 14 | - 4. Closest Point on a Sphere 15 | - 5. Intersection AABB-Plane 16 | - 6. Intersection of Two Lines in 2D 17 | - 7. Intersection Ray-AABB 18 | - 8. Intersection Ray-Plane 19 | - 9. Intersection Ray-Triangle 20 | - 10. Intersection of Two Rays in 3D 21 | - 11. Dynamic Intersection Sphere-Plane 22 | - 12. Static Intersection Sphere-Plane 23 | - 13. Dynamic Intersection of Two Spheres 24 | - 14. Static Intersection of Two Spheres 25 | - 15. Intersection of Three Planes 26 | - 16. Intersection of Two AABBs 27 | - 17. Reflection Vector 28 | - 18. Barycentric Coordinates of Triangle in 3D 29 | 30 | ## FILES AND FOLDERS 31 | 32 | | Files and Folders | Description | 33 | | --------------------- |:-----------------------------------------------------:| 34 | | `Config` | UE4 project configuration files | 35 | | `Content` | UE4 project files | 36 | | `Source` | Project source | 37 | | `CHANGELOG` | Log to track changes in respository | 38 | | `LICENSE` | Apache 2.0 License | 39 | | `GeometricTests.uproject` | UE4 project | 40 | | `README` | This file | 41 | 42 | ### Config 43 | 44 | | Files | Description | 45 | | ----------------------------- |:-----------------------------------------------------:| 46 | | `DefaultEditor.ini` | UE4 Config File | 47 | | `DefaultEngine.ini` | UE4 Config File | 48 | | `DefaultGame.ini` | UE4 Config File | 49 | 50 | ### Content/Maps 51 | 52 | | Files | Description | 53 | | ----------------------------- |:-----------------------------------------------------:| 54 | | `EmptyLevel.umap` | UE4 Level | 55 | 56 | ### Source 57 | 58 | | Files and Folders | Description | 59 | | ----------------------------- |:-----------------------------------------------------:| 60 | | `GeometricTests` | Geometric Tests Source | 61 | | `GeometricTests.Target.cs` | UE4 Build System | 62 | | `GeometricTestsEditor.Target.cs` | UE4 Build System | 63 | 64 | ### Source/GeometricTests 65 | 66 | | Files and Folders | Description | 67 | | ----------------------------- |:-----------------------------------------------------:| 68 | | `Math` | Math Directory | 69 | | `Primitives` | Geometric Primitives Directory | 70 | | `GeometricTestLibrary.h` | Geometric Test Library | 71 | | `GeometricTest.Build.cs` | UE4 Build System | 72 | | `GeometricTests.h` | Header: Module implementation for UE4 Project | 73 | | `GeometricTests.cpp` | Source: Module implementation for UE4 Project | 74 | | `GeometricTestsGameModeBase.h` | Header: UE4 Game Mode Base | 75 | | `GeometricTestsGameModeBase.cpp` | Source: UE4 Game Mode Base | 76 | 77 | ### Source/GeometricTests/Math/LinearAlgebra 78 | 79 | | Files | Description | 80 | | ------------- |:-----------------------------------------------------:| 81 | | `Quaternion.h` | Templated struct that handles quaternions | 82 | | `Vector.h` | Templated struct that handles vector math | 83 | 84 | ### Source/GeometricTests/Math/Operations 85 | 86 | | Files | Description | 87 | | ------------- |:-----------------------------------------------------:| 88 | | `MathOperations.h` | Common math functions | 89 | 90 | ### Source/GeometricTests/Primitives 91 | 92 | | Files | Description | 93 | | ------------- |:-----------------------------------------------------:| 94 | | `AABB.h` | Axis-Aligned Bounding Box Data | 95 | | `Circle.h` | Circle Data | 96 | | `Plane.h` | Plane Data | 97 | | `Ray.h` | Ray Data | 98 | | `Triangle.h` | Triangle Data | 99 | 100 | ## LICENSE 101 | 102 | > Apache 2.0 License 103 | > 104 | > Copyright (c) 2018-2019 Robert Slattery 105 | > 106 | > Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 107 | > 108 | > http://www.apache.org/licenses/LICENSE-2.0 109 | > 110 | > Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------------------- /Source/GeometricTests.Target.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | using UnrealBuildTool; 18 | using System.Collections.Generic; 19 | 20 | public class GeometricTestsTarget : TargetRules 21 | { 22 | public GeometricTestsTarget(TargetInfo Target) : base(Target) 23 | { 24 | Type = TargetType.Game; 25 | 26 | ExtraModuleNames.AddRange( new string[] { "GeometricTests" } ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/GeometricTests/GeometricTestLibrary.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "CoreMinimal.h" 20 | #include "UObject/ObjectMacros.h" 21 | #include "UObject/Object.h" 22 | #include "UObjectGlobals.h" 23 | #include "Math/LinearAlgebra/Vector.h" 24 | #include "Math/Operations/MathOperations.h" 25 | #include "Primitives/AABB.h" 26 | #include "Primitives/Circle.h" 27 | #include "Primitives/Plane.h" 28 | #include "Primitives/Ray.h" 29 | #include "Engine.h" 30 | #include 31 | #include 32 | #include "GeometricTestLibrary.generated.h" 33 | 34 | /* 35 | * GeometricTestLibrary.h 36 | * 37 | * Solves a series of 2D and 3D math problems, 38 | * including, closest point, intersection 39 | * and line of sight. 40 | * 41 | * Examples: 42 | * 43 | * 1. Closest Point in AABB 44 | * 2. Closest Point on a Ray 45 | * 3. Closest Point on a Plane 46 | * 4. Closest Point on a Sphere 47 | * 5. Intersection AABB-Plane 48 | * 6. Intersection of Two Lines in 2D 49 | * 7. Intersection Ray-AABB (Common for Line of Sight Tests) 50 | * 8. Intersection Ray-Plane 51 | * 9. Intersection Ray-Triangle 52 | * 10. Intersection of Two Rays in 3D 53 | * 11. Dynamic Intersection Sphere-Plane 54 | * 12. Static Intersection Sphere-Plane 55 | * 13. Dynamic Intersection of Two Spheres 56 | * 14. Static Intersection of Two Spheres 57 | * 15. Intersection of Three Planes 58 | * 16. Intersection of Two AABBs 59 | * 17. Reflection Vector 60 | * 18. Barycentric Coordinates of Triangle in 3D 61 | * 62 | * Updated April 7, 2019 63 | */ 64 | UCLASS() 65 | class GEOMETRICTESTS_API UGeometricTestLibrary : public UObject 66 | { 67 | GENERATED_BODY() 68 | 69 | public: 70 | 71 | // Closest Point in AABB 72 | template 73 | static Vector3 ClosestPointInAABB( 74 | const Vector3& Point 75 | , const AABB& AABB_Ref); 76 | 77 | // Closest Point on a Ray 78 | template 79 | static Vector3 ClosestPointOnRay( 80 | const Vector3& Point 81 | , const Vector3& RayOrigin 82 | , const Vector3& RayDelta); 83 | 84 | // Closest Point On Plane 85 | template 86 | static Vector3 ClosestPointOnPlane( 87 | const Vector3& Point // q 88 | , const Vector3& PlaneNormal // n 89 | , float PlaneD); // p*PlaneNormal = PlaneD 90 | 91 | // Closest Point On Sphere 92 | template 93 | static Vector3 ClosestPointOnSphere( 94 | const Vector3& Point 95 | , const Vector3& SphereCenter 96 | , float SphereRadius); 97 | 98 | // Intersection AABB-Plane 99 | template 100 | static int DoesAABBPlaneIntersect( 101 | const Vector3& PlaneNormal 102 | , float D 103 | , const AABB& AABB_Ref); 104 | 105 | // Intersection of Two Lines in 2D 106 | template 107 | static Vector2 DoLinesIntersect( 108 | const Vector2& Origin1 109 | , const Vector2& Delta1 110 | , const Vector2& Origin2 111 | , const Vector2& Delta2); 112 | 113 | // Intersection Ray-AABB 114 | template 115 | static float DoesRayAABBIntersect( 116 | const Vector3& RayOrigin 117 | , const Vector3& RayDelta 118 | , const AABB& AABB_Ref 119 | , Vector3* ReturnNormal); 120 | 121 | // Intersection Ray-Plane 122 | template 123 | static bool DoesRayPlaneIntersect( 124 | const Vector3& RayOrigin 125 | , const Vector3& RayDelta 126 | , const Vector3& SurfaceNormal 127 | , float PlaneD); 128 | 129 | // Intersection Ray-Sphere 130 | template 131 | static bool DoesRaySphereIntersect( 132 | const Vector3& SphereCenter 133 | , float SphereRadius 134 | , const Vector3& RayOrigin 135 | , const Vector3& RayDelta); 136 | 137 | // Intersection Ray-Triangle 138 | template 139 | static float DoesRayTriangleIntersect( 140 | const Vector3& RayOrigin // origin of ray 141 | , const Vector3& RayDelta // direction and length of ray 142 | , const Vector3& Vertex1 // triangle vertices 143 | , const Vector3& Vertex2 // . 144 | , const Vector3& Vertex3 // . 145 | , float MinT); // closest intersection found so far 146 | 147 | // Intersection Two 3D Rays 148 | template 149 | static bool DoRaysIntersect( 150 | const Vector3& RayOrigin1 // p1 151 | , const Vector3& RayDelta1 // d1 152 | , const Vector3& RayOrigin2 // p2 153 | , const Vector3& RayDelta2); // d2 154 | 155 | // Dynamic Intersection Sphere-Plane 156 | template 157 | static int DoesSpherePlaneIntersect_Dynamic( 158 | const Vector3& PlaneNormal // must be normalized first 159 | , float PlaneD 160 | , const Vector3& SphereDeltaVector 161 | , const Vector3& SphereCenter 162 | , float SphereRadius); 163 | 164 | // Static Intersection Sphere-Plane 165 | template 166 | static int DoesSpherePlaneIntersect_Static( 167 | const Vector3& PlaneNormal // must be normalized first 168 | , float PlaneD // p*PlaneNormal = PlaneD 169 | , const Vector3& SphereCenter // center of sphere 170 | , float SphereRadius); // radius of sphere 171 | 172 | // Dynamic Intersection of Two Spheres 173 | template 174 | static bool DoSpheresIntersect_Dynamic( 175 | const Vector3& StationaryDeltaVector 176 | , const Vector3& MovingDeltaVector 177 | , const Vector3& StationarySphereCenter 178 | , const Vector3& MovingSphereCenter 179 | , float StationarySphereRadius 180 | , float MovingSphereRadius); 181 | 182 | // Static Intersection of Two Spheres 183 | template 184 | static bool DoSpheresIntersect_Static( 185 | const Vector3& SphereCenter1 186 | , float SphereRadius1 187 | , const Vector3& SphereCenter2 188 | , float SphereRadius2); 189 | 190 | // Intersection of Three Planes 191 | template 192 | static Vector3 PointOfIntersection( 193 | const Vector3& PlaneNormal1 // must be normalized first 194 | , float PlaneD1 // p*PlaneNormal = PlaneD 195 | , const Vector3& PlaneNormal2 // must be normalized first 196 | , float PlaneD2 // p*PlaneNormal2 = PlaneD2 197 | , const Vector3& PlaneNormal3 // must be normalized first 198 | , float PlaneD3); // p*PlaneNormal3 = PlaneD3 199 | 200 | // Intersection of Two AABBs 201 | template 202 | static bool DoAABBsIntersect( 203 | const AABB& A 204 | , const AABB& B); 205 | 206 | // Reflection Vector 207 | template 208 | static Vector3 SolveReflectionVector( 209 | const Vector3& SurfaceNormal 210 | , const Vector3& LightDelta); 211 | 212 | // Barycentric Coordinates of Triangle in 3D 213 | template 214 | static Vector3 SolveBarycentricCoordinates3D( 215 | const Vector3 Vertices[3] // vertices of the triangle 216 | , const Vector3& Point // p 217 | , float Barycentric[3]); // barycentric coordinates 218 | 219 | protected: 220 | 221 | // Constructor 222 | UGeometricTestLibrary() = default; 223 | 224 | // Destructor 225 | ~UGeometricTestLibrary() = default; 226 | 227 | // UE4: UObject handles copying and moving 228 | }; 229 | 230 | /* 231 | * Closest Point in an AABB (Axis-Aligned Bounding Box) 232 | * 233 | * To find the closest point on an AABB, we just clamp 234 | * the X, Y and Z positions of the point to the AABB 235 | * 236 | * q = given point 237 | */ 238 | template 239 | inline static Vector3 UGeometricTestLibrary::ClosestPointInAABB( 240 | const Vector3& Point // q 241 | , const AABB& AABB_Ref) 242 | { 243 | Vector3 Result = Vector3::ZeroVector; 244 | 245 | // Print q 246 | GEngine->AddOnScreenDebugMessage(1, 30.f, FColor::Red, TEXT("\nPoint q is...")); 247 | GEngine->AddOnScreenDebugMessage( 248 | 2, 30.f, FColor::Red 249 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 250 | , Point.X, Point.Y, Point.Z)); 251 | 252 | // Solve by "pushing" q onto B along each axis 253 | if (Point.X < AABB_Ref.GetMin().X) Result.X = (T)AABB_Ref.GetMin().X; 254 | else if (Point.X > AABB_Ref.GetMax().X) Result.X = (T)AABB_Ref.GetMax().X; 255 | 256 | if (Point.Y < AABB_Ref.GetMin().Y) Result.Y = (T)AABB_Ref.GetMin().Y; 257 | else if (Point.Y > AABB_Ref.GetMax().Y) Result.Y = (T)AABB_Ref.GetMax().Y; 258 | 259 | if (Point.Z < AABB_Ref.GetMin().Z) Result.Z = (T)AABB_Ref.GetMin().Z; 260 | else if (Point.Z > AABB_Ref.GetMax().Z) Result.Z = (T)AABB_Ref.GetMax().Z; 261 | 262 | // Print Result 263 | GEngine->AddOnScreenDebugMessage(3, 30.f, FColor::Red, TEXT("Closest point in AABB is...")); 264 | GEngine->AddOnScreenDebugMessage( 265 | 4, 30.f, FColor::Red 266 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 267 | , Result.X, Result.Y, Result.Z)); 268 | 269 | // If Result is already inside the box, this returns the original point 270 | return Result; 271 | } 272 | 273 | /* 274 | * Closest Point on a Ray 275 | * 276 | * Given a point q, we wish to find the point q` 277 | * which is the result of projecting q onto a ray R 278 | * 279 | * t = Ď * v = Ď * (q - p0) 280 | * q` = p(t) = p0 + t*Ď = p0 + (Ď * (q - p0))Ď 281 | * 282 | * Where: 283 | * 284 | * q = given point 285 | * p0 = ray origin 286 | * Ď = normalized ray delta vector, a.k.a. unit vector 287 | * v = q - p0 288 | */ 289 | template 290 | inline static Vector3 UGeometricTestLibrary::ClosestPointOnRay( 291 | const Vector3& Point // q 292 | , const Vector3& RayOrigin // p0 293 | , const Vector3& RayDelta) // D (unnormalized) 294 | { 295 | Vector3 Result = Vector3::ZeroVector; 296 | 297 | // Print q 298 | GEngine->AddOnScreenDebugMessage(1, 30.f, FColor::Red, TEXT("\nPoint q is...")); 299 | GEngine->AddOnScreenDebugMessage( 300 | 2, 30.f, FColor::Red 301 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 302 | , Point.X, Point.Y, Point.Z)); 303 | 304 | // Solve Ď 305 | Vector3 D = MyMathLibrary::Normalize(RayDelta); 306 | 307 | // Solve v = q - p0 308 | Vector3 v = Point - RayOrigin; 309 | 310 | // Solve t 311 | float t = MyMathLibrary::DotProduct(D, v); 312 | 313 | // Solve R, the parametric ray 314 | Vector3 R = RayOrigin + (D*t); 315 | 316 | // If t < 0 or t > length of ray, then q` is not within the ray, 317 | // in which case, the closest point to q on R will 318 | // be the ray origin (if t < 0) or endpoint (if t > length of ray) 319 | if (t < 0) 320 | { 321 | GEngine->AddOnScreenDebugMessage( 322 | 3, 30.f, FColor::Red 323 | , TEXT("\nResult not within the ray! Closest point is ray origin!, GeometricTestLibrary.h:323\n")); 324 | 325 | return Result; 326 | } 327 | else if (t > R.Magnitude()) // t > length of ray 328 | { 329 | GEngine->AddOnScreenDebugMessage( 330 | 4, 30.f, FColor::Red 331 | , TEXT("\nResult not within the ray! Closest point is the endpoint!, GeometricTestLibrary.h:331\n")); 332 | 333 | return Result; 334 | } 335 | 336 | // Solve q` 337 | Result = R; 338 | 339 | // Print q` 340 | GEngine->AddOnScreenDebugMessage(5, 30.f, FColor::Red, TEXT("\nClosest point to q is...")); 341 | GEngine->AddOnScreenDebugMessage( 342 | 6, 30.f, FColor::Red 343 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 344 | , Result.X, Result.Y, Result.Z)); 345 | 346 | // Return closest point on parametic ray 347 | return Result; 348 | } 349 | 350 | /* 351 | * Closest Point on a Plane 352 | * 353 | * Given a point q, we wish to find the point q` 354 | * which is the result of projecting q onto a plane P 355 | * 356 | * q` = q + (d - q * ň)ň 357 | * 358 | * Where: 359 | * 360 | * q = given point 361 | * ň = normalized plane normal, a.k.a. unit vector 362 | * d = p*n = the plane equation, the distance from the plane to the point 363 | * 364 | * NOTE: We will flip d - q and then take inverse dot product 365 | */ 366 | template 367 | inline static Vector3 UGeometricTestLibrary::ClosestPointOnPlane( 368 | const Vector3& Point // q 369 | , const Vector3& PlaneNormal // n (unnormalized) 370 | , float PlaneD) // p*PlaneNormal = PlaneD 371 | { 372 | Vector3 Result = Vector3::ZeroVector; 373 | 374 | // Print q 375 | GEngine->AddOnScreenDebugMessage(1, 30.f, FColor::Red, TEXT("Point q is...")); 376 | GEngine->AddOnScreenDebugMessage( 377 | 2, 30.f, FColor::Red 378 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 379 | , Point.X, Point.Y, Point.Z)); 380 | 381 | // Solve ň 382 | Vector3 NormalizedPlaneNormal = MyMathLibrary::Normalize(PlaneNormal); 383 | 384 | // Solve q - d, flipping sign of d 385 | Vector3 Diff = Point - PlaneD; 386 | 387 | // Solve q - d * ň, with inverse dot product 388 | // 389 | // Get the shortest distance between a point and a plane. The output is signed so it holds information 390 | // as to which side of the plane normal the point is. 391 | float Distance = -MyMathLibrary::DotProduct(Diff, NormalizedPlaneNormal); 392 | 393 | // Solve (d - q * ň)ň 394 | NormalizedPlaneNormal *= Distance; 395 | 396 | // Solve q` 397 | Result = Point + NormalizedPlaneNormal; 398 | 399 | // Print q` 400 | GEngine->AddOnScreenDebugMessage(3, 30.f, FColor::Red, TEXT("Closest Point to q is...")); 401 | GEngine->AddOnScreenDebugMessage( 402 | 4, 30.f, FColor::Red 403 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 404 | , Result.X, Result.Y, Result.Z)); 405 | 406 | // Return closest point on plane 407 | return Result; 408 | } 409 | 410 | /* 411 | * Closest Point on a Sphere 412 | * 413 | * Given a point q, we wish to find q`, which 414 | * is the closest point on the circle to q 415 | * 416 | * q` = q + d * (||d|| - r / ||d||) 417 | * 418 | * Where: 419 | * 420 | * q = Given Point 421 | * r = radius of sphere 422 | * c = center of sphere 423 | * d = c - q 424 | * ||d|| = Magnitude of d 425 | */ 426 | template 427 | inline static Vector3 UGeometricTestLibrary::ClosestPointOnSphere( 428 | const Vector3& Point // q 429 | , const Vector3& SphereCenter // c 430 | , float SphereRadius) // r 431 | { 432 | Vector3 Result = Vector3::ZeroVector; 433 | 434 | // Print q 435 | GEngine->AddOnScreenDebugMessage(1, 30.f, FColor::Red, TEXT("\nPoint q is...")); 436 | GEngine->AddOnScreenDebugMessage( 437 | 2, 30.f, FColor::Red 438 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 439 | , Point.X, Point.Y, Point.Z)); 440 | 441 | // Solve d = c - q 442 | Vector3 d = SphereCenter - Point; 443 | 444 | // Solve ||d|| 445 | float dMag = d.Magnitude(); 446 | 447 | // If ||d|| < r, then q is inside the sphere 448 | if (dMag < SphereRadius) 449 | { 450 | GEngine->AddOnScreenDebugMessage( 451 | 3, 30.f, FColor::Red 452 | , TEXT("\nFailure! Point q is inside circle!, GeometricTestLibrary.h:452")); 453 | 454 | return Result; 455 | } 456 | 457 | // Solve ||d|| - r 458 | float numerator = dMag - SphereRadius; 459 | 460 | // Solve d * (||d|| - r / ||d||) 461 | Vector3 rhs = d * (numerator / dMag); 462 | 463 | // Solve q` 464 | Result = Point + rhs; 465 | 466 | // Print q` 467 | GEngine->AddOnScreenDebugMessage(4, 30.f, FColor::Red, TEXT("\nClosest Point to q is...")); 468 | GEngine->AddOnScreenDebugMessage( 469 | 5, 30.f, FColor::Red 470 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 471 | , Result.X, Result.Y, Result.Z)); 472 | 473 | // Return closest point on a circle or sphere 474 | return Result; 475 | } 476 | 477 | /* 478 | * Intersection of an AABB and a plane 479 | * 480 | * Common for collision detection and ray tracing 481 | * 482 | * <0 Box is completely on the back side of the plane 483 | * >0 Box is completely on the front side of the plane 484 | * 0 Box intersects the plane 485 | */ 486 | template 487 | inline static int UGeometricTestLibrary::DoesAABBPlaneIntersect( 488 | const Vector3& PlaneNormal 489 | , float D // the D from Plane 490 | , const AABB& AABB_Ref) 491 | { 492 | // Inspect the normal and solve the min and max D values 493 | float MinD = 0.f; 494 | float MaxD = 0.f; 495 | 496 | if (PlaneNormal.X > 0.0f) 497 | { 498 | MinD = PlaneNormal.X * AABB_Ref.GetMin().X; 499 | MaxD = PlaneNormal.X * AABB_Ref.GetMax().X; 500 | } 501 | else 502 | { 503 | MinD = PlaneNormal.X * AABB_Ref.GetMax().X; 504 | MaxD = PlaneNormal.X * AABB_Ref.GetMin().X; 505 | } 506 | 507 | if (PlaneNormal.Y > 0.0f) 508 | { 509 | MinD += PlaneNormal.Y * AABB_Ref.GetMin().Y; 510 | MaxD += PlaneNormal.Y * AABB_Ref.GetMax().Y; 511 | } 512 | else 513 | { 514 | MinD += PlaneNormal.Y * AABB_Ref.GetMax().Y; 515 | MaxD += PlaneNormal.Y * AABB_Ref.GetMin().Y; 516 | } 517 | 518 | if (PlaneNormal.Z > 0.0f) 519 | { 520 | MinD += PlaneNormal.Z * AABB_Ref.GetMin().Z; 521 | MaxD += PlaneNormal.Z * AABB_Ref.GetMax().Z; 522 | } 523 | else 524 | { 525 | MinD += PlaneNormal.Z * AABB_Ref.GetMax().Z; 526 | MaxD += PlaneNormal.Z * AABB_Ref.GetMin().Z; 527 | } 528 | 529 | // Check if completely on the front side of the plane 530 | if (MinD >= D) return 1; 531 | 532 | // Check if completely on the back side of the plane 533 | if (MaxD <= D) return -1; 534 | 535 | // Return intersection of AABB and plane 536 | return 0; 537 | } 538 | 539 | /* 540 | * Intersection of two lines in 2D 541 | * 542 | * Given lines defined in 2D by: 543 | * 544 | * d1 = a1*x + b1*y 545 | * d2 = a2*x + b2*y 546 | * 547 | * We can solve for the point of intersection. 548 | * 549 | * x = b2*d1 - b1*d2 / a1*b2 - a2*b1 550 | * y = a1*d2 - a2*d1 / a1*b2 - a2*b1 551 | */ 552 | template 553 | inline static Vector2 UGeometricTestLibrary::DoLinesIntersect( 554 | const Vector2& Origin1 555 | , const Vector2& Delta1 556 | , const Vector2& Origin2 557 | , const Vector2& Delta2) 558 | { 559 | Vector2 Result = Vector2::ZeroVector; 560 | 561 | // Line AB 562 | // d1 = a1*x + b1*y 563 | const float a1 = Delta1.Y - Origin1.Y; 564 | const float b1 = Origin1.X - Delta1.X; 565 | const float d1 = a1*(Origin1.X) + b1*(Origin1.Y); 566 | 567 | // Line CD 568 | // d2 = a2*x + b2*y 569 | const float a2 = Delta2.Y - Origin2.Y; 570 | const float b2 = Origin2.X - Delta2.X; 571 | const float d2 = a2*(Origin2.X) + b2*(Origin2.Y); 572 | 573 | // Solve a1*b2 - a2*b1 574 | const float Determinant = (a1*b2) - (a2*b1); 575 | 576 | // Solve b2*d1 - b1*d2 577 | const float NumeratorX = ((b2*d1) - (b1*d2)); 578 | 579 | // Solve a1*d2 - a2*d1 580 | const float NumeratorY = ((a1*d2) - (a2*d1)); 581 | 582 | // If the lines are coincident, there are an infinite number of solutions 583 | if (NumeratorX == 0.f && NumeratorY == 0.f && Determinant == 0.f) 584 | { 585 | GEngine->AddOnScreenDebugMessage( 586 | 1, 30.f, FColor::Red 587 | , TEXT("\nLines are coincident! Infinte solutions!, GeometricTestLibrary.h:587")); 588 | 589 | return Result; 590 | } 591 | 592 | // If the denominator of both equations is zero, there are no solutions and no intersection 593 | if (Determinant == 0.f) 594 | { 595 | GEngine->AddOnScreenDebugMessage( 596 | 2, 30.f, FColor::Red 597 | , TEXT("\nLines are parallel! No solutions and no intersection!, GeometricTestLibrary.h:597")); 598 | 599 | return Result; 600 | } 601 | else 602 | { 603 | // Solve x = b2*d1 - b1*d2 / a1*b2 - a2*b1 604 | const float x = NumeratorX / Determinant; 605 | 606 | // Solve y = a1*d2 - a2*d1 / a1*b2 - a2*b1 607 | const float y = NumeratorY / Determinant; 608 | 609 | // Check if the x and y coordinates are within both lines 610 | if (x < std::min(Origin1.X, Delta1.X) || x > std::max(Origin1.X, Delta1.X) || 611 | x < std::min(Origin2.X, Delta2.X) || x > std::max(Origin2.X, Delta2.X)) 612 | { 613 | GEngine->AddOnScreenDebugMessage( 614 | 2, 30.f, FColor::Red 615 | , TEXT("\nFAILURE! X coordinates outside of lines!, GeometricTestLibrary.h:615\n")); 616 | 617 | return Result; 618 | } 619 | 620 | if (y < std::min(Origin1.Y, Delta1.Y) || y > std::max(Origin1.Y, Delta1.Y) || 621 | y < std::min(Origin2.Y, Delta2.Y) || y > std::max(Origin2.Y, Delta2.Y)) 622 | { 623 | GEngine->AddOnScreenDebugMessage( 624 | 2, 30.f, FColor::Red 625 | , TEXT("\nFAILURE! Y coordinates outside of lines!, GeometricTestLibrary.h:625\n")); 626 | 627 | return Result; 628 | } 629 | 630 | Result.Set((T)x, (T)y); 631 | } 632 | 633 | // Print Result 634 | GEngine->AddOnScreenDebugMessage(3, 30.f, FColor::Red, TEXT("\nPoint of intersection of two lines is...")); 635 | GEngine->AddOnScreenDebugMessage( 636 | 4, 30.f, FColor::Red 637 | , FString::Printf(TEXT("X: %f, Y: %f\n") 638 | , Result.X, Result.Y)); 639 | 640 | // Returns the point of intersection of two lines 641 | return Result; 642 | } 643 | 644 | /* 645 | * Intersection of a Ray and an AABB 646 | * 647 | * Common for line of sight or tests that require 648 | * trivial rejection on complex objects. 649 | * 650 | * Determine which side of the box will be intersected 651 | * and then perform ray-plane intersection test on 652 | * that side. If the point of intersection with the 653 | * plane is within AABB, there is intersection. 654 | * Otherwise, there is not. 655 | */ 656 | template 657 | inline static float UGeometricTestLibrary::DoesRayAABBIntersect( 658 | const Vector3& RayOrigin // origin of ray 659 | , const Vector3& RayDelta // length and direction of ray 660 | , const AABB& AABB_Ref // AABB data 661 | , Vector3* ReturnNormal) // normal to return 662 | { 663 | const float NoIntersection = FLT_MAX; // Bogus value 664 | 665 | // Check for point inside box, trivial reject, 666 | // and determine parametric distance to each front face 667 | bool IsInside = true; 668 | 669 | float xt = 0.f, xn = 0.f; 670 | 671 | if (RayOrigin.X < AABB_Ref.GetMin().X) 672 | { 673 | xt = AABB_Ref.GetMin().X - RayOrigin.X; 674 | 675 | if (xt > RayDelta.X) return NoIntersection; 676 | 677 | xt /= RayDelta.X; 678 | IsInside = false; 679 | xn = -1.0f; 680 | } 681 | else if (RayOrigin.X > AABB_Ref.GetMax().X) 682 | { 683 | xt = AABB_Ref.GetMax().X - RayOrigin.X; 684 | 685 | if (xt < RayDelta.X) return NoIntersection; 686 | 687 | xt /= RayDelta.X; 688 | IsInside = false; 689 | xn = 1.0f; 690 | } 691 | else 692 | xt = -1.0f; 693 | 694 | float yt = 0.f, yn = 0.f; 695 | 696 | if (RayOrigin.Y < AABB_Ref.GetMin().Y) 697 | { 698 | yt = AABB_Ref.GetMin().Y - RayOrigin.Y; 699 | 700 | if (yt > RayDelta.Y) return NoIntersection; 701 | 702 | yt /= RayDelta.Y; 703 | IsInside = false; 704 | yn = -1.0f; 705 | } 706 | else if (RayOrigin.Y > AABB_Ref.GetMax().Y) 707 | { 708 | yt = AABB_Ref.GetMax().Y - RayOrigin.Y; 709 | 710 | if (yt < RayDelta.Y) return NoIntersection; 711 | 712 | yt /= RayDelta.Y; 713 | IsInside = false; 714 | yn = 1.0f; 715 | } 716 | else 717 | yt = -1.0f; 718 | 719 | float zt = 0.f, zn = 0.f; 720 | 721 | if (RayOrigin.Z < AABB_Ref.GetMin().Z) 722 | { 723 | zt = AABB_Ref.GetMin().Z - RayOrigin.Z; 724 | 725 | if (zt > RayDelta.Z) return NoIntersection; 726 | 727 | zt /= RayDelta.Z; 728 | IsInside = false; 729 | zn = -1.0f; 730 | } 731 | else if (RayOrigin.Z > AABB_Ref.GetMax().Z) 732 | { 733 | zt = AABB_Ref.GetMax().Z - RayOrigin.Z; 734 | 735 | if (zt < RayDelta.Z) return NoIntersection; 736 | 737 | zt /= RayDelta.Z; 738 | IsInside = false; 739 | zn = 1.0f; 740 | } 741 | else 742 | zt = -1.0f; 743 | 744 | // If ray origin is inside box, then return intersection 745 | if (IsInside) 746 | { 747 | if (ReturnNormal != nullptr) 748 | *ReturnNormal = -RayDelta; // unnormalized 749 | 750 | return 0.0f; 751 | } 752 | 753 | // Select the farthest plane, the plane of intersection 754 | int PlaneID = 0; 755 | float t = xt; 756 | 757 | if (yt > t) 758 | { 759 | PlaneID = 1; 760 | t = yt; 761 | } 762 | 763 | if (zt > t) 764 | { 765 | PlaneID = 2; 766 | t = zt; 767 | } 768 | 769 | switch (PlaneID) 770 | { 771 | case 0: // intersect with yz plane 772 | { 773 | float y = RayOrigin.Y + RayDelta.Y*t; 774 | if (y < AABB_Ref.GetMin().Y || y > AABB_Ref.GetMax().Y) return NoIntersection; 775 | 776 | float z = RayOrigin.Z + RayDelta.Z*t; 777 | if (z < AABB_Ref.GetMin().Z || z > AABB_Ref.GetMax().Z) return NoIntersection; 778 | 779 | if (ReturnNormal != nullptr) 780 | ReturnNormal->Set(xn, 0.0f, 0.0f); 781 | } break; 782 | 783 | case 1: // intersect with xz plane 784 | { 785 | float x = RayOrigin.X + RayDelta.X*t; 786 | if (x < AABB_Ref.GetMin().X || x > AABB_Ref.GetMax().X) return NoIntersection; 787 | 788 | float z = RayOrigin.Z + RayDelta.Z*t; 789 | if (z < AABB_Ref.GetMin().Z || z > AABB_Ref.GetMax().Z) return NoIntersection; 790 | 791 | if (ReturnNormal != nullptr) 792 | ReturnNormal->Set(0.0f, yn, 0.0f); 793 | } break; 794 | 795 | case 2: // intersect with xy plane 796 | { 797 | float x = RayOrigin.X + RayDelta.X*t; 798 | if (x < AABB_Ref.GetMin().X || x > AABB_Ref.GetMax().X) return NoIntersection; 799 | 800 | float y = RayOrigin.Y + RayDelta.Y*t; 801 | if (y < AABB_Ref.GetMin().Y || y > AABB_Ref.GetMax().Y) return NoIntersection; 802 | 803 | if (ReturnNormal != nullptr) 804 | ReturnNormal->Set(0.0f, 0.0f, zn); 805 | } break; 806 | } 807 | 808 | // Return parametric point of intersection 809 | return t; 810 | } 811 | 812 | /* 813 | * Intersection of a ray and a plane 814 | * 815 | * Solve for t at the point of intersection: 816 | * 817 | * t = d - p0*n / ň*n 818 | * 819 | * Where: 820 | * 821 | * p0 = ray origin vector 822 | * n = surface normal of plane, i.e., cross product of two non-parallel edges of a polygon 823 | * ň = normalized ray delta vector, a.k.a. unit vector 824 | * d = p*n, the plane equation, the distance from the plane to a point 825 | */ 826 | template 827 | inline static bool UGeometricTestLibrary::DoesRayPlaneIntersect( 828 | const Vector3& RayOrigin 829 | , const Vector3& RayDelta 830 | , const Vector3& SurfaceNormal // must be normalized 831 | , float PlaneD) 832 | { 833 | bool Result = false; 834 | 835 | // Solve normalized surface normal 836 | Vector3 NormalizedSurfaceNormal = MyMathLibrary::Normalize(SurfaceNormal); 837 | 838 | // Solve d - p0 839 | Vector3 Diff = RayOrigin - PlaneD; 840 | 841 | // Solve ň 842 | Vector3 DeltaNormal = MyMathLibrary::Normalize(RayDelta); 843 | 844 | // Solve numerator (d - p0*n) 845 | float numerator = -MyMathLibrary::DotProduct(Diff, NormalizedSurfaceNormal); 846 | 847 | // Solve ň*n 848 | float denominator = MyMathLibrary::DotProduct(DeltaNormal, NormalizedSurfaceNormal); 849 | 850 | // If denominator is zero, then ray is parallel to the plane 851 | // and there is no intersection 852 | if (denominator == 0.f) 853 | { 854 | GEngine->AddOnScreenDebugMessage( 855 | 1, 30.f, FColor::Red 856 | , TEXT("\nRay parallel to plane! No intersection!, GeometricTestLibrary.h:856\n")); 857 | 858 | return Result; 859 | } 860 | 861 | // Solve d - p0*n / ň*n 862 | float t = numerator / denominator; 863 | 864 | // Solve R, the parametric ray 865 | Vector3 R = RayOrigin + (DeltaNormal*t); 866 | 867 | // TODO: Allow intersection only with front of plane (i.e., denominator < 0) 868 | // Thus, intersection only if the ray points in a direction opposite 869 | // to the normal of the plane. 870 | 871 | // Return true if t is within range 872 | // If t < 0 or t > length of ray, intersection does not occur 873 | if (t < 0 || t > R.Magnitude()) 874 | { 875 | GEngine->AddOnScreenDebugMessage( 876 | 1, 30.f, FColor::Red 877 | , TEXT("\nFAILURE! No intersection!, GeometricTestLibrary.h:877\n")); 878 | 879 | Result = false; 880 | } 881 | else 882 | { 883 | GEngine->AddOnScreenDebugMessage( 884 | 1, 30.f, FColor::Red 885 | , TEXT("\nSUCCESS! Ray and Plane intersect!, GeometricTestLibrary.h:885\n")); 886 | 887 | Result = true; 888 | } 889 | 890 | return Result; 891 | } 892 | 893 | /* 894 | * Intersection of a ray and a sphere 895 | * 896 | * Solve for t at the point of intersection: 897 | * 898 | * t = a - sqrt(r^2 - e^2 + a^2) 899 | * 900 | * Where: 901 | * 902 | * a = e * Ď, the length of this vector 903 | * Ď = normalized ray delta vector, a.k.a. unit vector 904 | * p0 = ray origin 905 | * r = radius of sphere 906 | * c = center of sphere 907 | * e = c - p0 908 | */ 909 | template 910 | inline static bool UGeometricTestLibrary::DoesRaySphereIntersect( 911 | const Vector3& SphereCenter 912 | , float SphereRadius 913 | , const Vector3& RayOrigin 914 | , const Vector3& RayDelta) 915 | { 916 | bool Result = false; 917 | 918 | // Solve Ď 919 | Vector3 D = MyMathLibrary::Normalize(RayDelta); 920 | 921 | // Solve e, e^2 922 | Vector3 e = SphereCenter - RayOrigin; 923 | float e2 = MyMathLibrary::DotProduct(e, e); 924 | 925 | // Solve r^2 926 | float r2 = pow(SphereRadius, 2); 927 | 928 | // if e^2 < r^2, the ray origin is inside the sphere 929 | if (e2 < r2) 930 | { 931 | GEngine->AddOnScreenDebugMessage( 932 | 1, 30.f, FColor::Red 933 | , TEXT("Intersection at point of ray origin!, GeometricTestLibrary.h:933")); 934 | 935 | Result = true; 936 | return Result; 937 | } 938 | 939 | // Solve a, a^2 940 | float a = MyMathLibrary::DotProduct(e, D); 941 | float a2 = pow(a, 2); 942 | 943 | // Solve sqrt(r^2 - e^2 + a^2) 944 | float SqrtVal = (r2 - e2) + a2; 945 | float f = sqrt(SqrtVal); 946 | 947 | // If the argument square root is negative, 948 | // then the ray does not intersect. 949 | if (SqrtVal < 0.f) 950 | { 951 | GEngine->AddOnScreenDebugMessage( 952 | 2, 30.f, FColor::Red 953 | , TEXT("\nFAILURE! No intersection!, Square root value is negative!, GeometricTestLibrary.h:953\n")); 954 | 955 | return Result; 956 | } 957 | 958 | // Solve a - sqrt(r^2 - e^2 + a^2) 959 | float t = a - f; 960 | 961 | // Solve R, the parametric ray 962 | Vector3 R = RayOrigin + (D*t); 963 | 964 | // If t < 0 or t > length of ray, intersection does not occur 965 | if (t < 0.f || t > R.Magnitude()) 966 | { 967 | GEngine->AddOnScreenDebugMessage( 968 | 3, 30.f, FColor::Red 969 | , TEXT("\nFAILURE! No intersection!, GeometricTestLibrary.h:969\n")); 970 | 971 | Result = false; 972 | } 973 | else 974 | { 975 | GEngine->AddOnScreenDebugMessage( 976 | 4, 30.f, FColor::Red 977 | , TEXT("\nSUCCESS! Ray and sphere intersected at t = 0!, GeometricTestLibrary.h:977\n")); 978 | 979 | Result = true; 980 | } 981 | 982 | return Result; 983 | } 984 | 985 | /* 986 | * Intersection of a Ray and a Triangle 987 | * 988 | * Solve the point where the ray intersects the 989 | * plane containing the triangle. Then test to 990 | * see whether point is inside triangle by 991 | * solving barycentric coordinates of the point. 992 | * 993 | * We are testing collisions where the ray 994 | * approaches the triangle from the front side. 995 | */ 996 | template 997 | inline static float UGeometricTestLibrary::DoesRayTriangleIntersect( 998 | const Vector3& RayOrigin // origin of ray 999 | , const Vector3& RayDelta // direction and length of ray 1000 | , const Vector3& Vertex1 // triangle vertices 1001 | , const Vector3& Vertex2 // ... 1002 | , const Vector3& Vertex3 // ... 1003 | , float MinT) // closest intersection found so far, start at 1.0f 1004 | { 1005 | const float NoIntersection = FLT_MAX; 1006 | 1007 | // Solve clockwise edge vectors 1008 | Vector3 e1 = Vertex2 - Vertex1; 1009 | Vector3 e2 = Vertex3 - Vertex2; 1010 | 1011 | // Solve Surface Normal (unnormalized), i.e., the cross product of two non-parallel edges 1012 | Vector3 n = MyMathLibrary::CrossProduct(e1, e2); 1013 | 1014 | // Solve gradient which tells us how steep of an 1015 | // angle we are approaching the front side of the triangle 1016 | float dot = MyMathLibrary::DotProduct(n, RayDelta); 1017 | 1018 | // Check for a ray that is parallel to the triangle, 1019 | // or not pointing towards the front face of the triangle. 1020 | // This will also reject degenerate triangles and rays as well. 1021 | if (!(dot < 0.0f)) 1022 | return NoIntersection; 1023 | 1024 | // Solve d value for the plane equation 1025 | float d = MyMathLibrary::DotProduct(n, Vertex1); 1026 | 1027 | // Solve parametric point of intersection with the plane 1028 | // containing the triangle, checking at the earliest 1029 | // possible stages for trivial rejection 1030 | float t = d - MyMathLibrary::DotProduct(n, RayOrigin); 1031 | 1032 | // Is ray origin on the backside of the polygon? 1033 | if (!(t <= 0.0f)) 1034 | return NoIntersection; 1035 | 1036 | // Closer intersection already found? 1037 | if (!(t >= dot * MinT)) 1038 | return NoIntersection; 1039 | 1040 | // Ray intersects the plane 1041 | t /= dot; 1042 | check(t >= 0.0f && t <= MinT); // "check" is from UE4. In C++, use "assert". 1043 | 1044 | // Solve p, the 3D point of intersection 1045 | Vector3 p = RayOrigin + (RayDelta*t); 1046 | 1047 | // Dominant axis to select which plane to project onto 1048 | float u0 = 0.f, u1 = 0.f, u2 = 0.f; 1049 | float v0 = 0.f, v1 = 0.f, v2 = 0.f; 1050 | 1051 | if (std::fabs(n.X) > std::fabs(n.Y)) 1052 | { 1053 | if (std::fabs(n.X) > std::fabs(n.Z)) 1054 | { 1055 | u0 = p.Y - Vertex1.Y; 1056 | u1 = Vertex2.Y - Vertex1.Y; 1057 | u2 = Vertex3.Y - Vertex1.Y; 1058 | 1059 | v0 = p.Z - Vertex1.Z; 1060 | v1 = Vertex2.Z - Vertex1.Z; 1061 | v2 = Vertex3.Z - Vertex1.Z; 1062 | } 1063 | else 1064 | { 1065 | u0 = p.X - Vertex1.X; 1066 | u1 = Vertex2.X - Vertex1.X; 1067 | u2 = Vertex3.X - Vertex1.X; 1068 | 1069 | v0 = p.Y - Vertex1.Y; 1070 | v1 = Vertex2.Y - Vertex1.Y; 1071 | v2 = Vertex3.Y - Vertex1.Y; 1072 | } 1073 | } 1074 | else 1075 | { 1076 | if (std::fabs(n.Y) > std::fabs(n.Z)) 1077 | { 1078 | u0 = p.X - Vertex1.X; 1079 | u1 = Vertex2.X - Vertex1.X; 1080 | u2 = Vertex3.X - Vertex1.X; 1081 | 1082 | v0 = p.Z - Vertex1.Z; 1083 | v1 = Vertex2.Z - Vertex1.Z; 1084 | v2 = Vertex3.Z - Vertex1.Z; 1085 | } 1086 | else 1087 | { 1088 | u0 = p.X - Vertex1.X; 1089 | u1 = Vertex2.X - Vertex1.X; 1090 | u2 = Vertex3.X - Vertex1.X; 1091 | 1092 | v0 = p.Y - Vertex1.Y; 1093 | v1 = Vertex2.Y - Vertex1.Y; 1094 | v2 = Vertex3.Y - Vertex1.Y; 1095 | } 1096 | } 1097 | 1098 | // Solve Denominator 1099 | float Denominator = u1*v2 - v1*u2; 1100 | if (!(Denominator != 0.0f)) return NoIntersection; 1101 | Denominator = 1.0f / Denominator; 1102 | 1103 | // Solve barycentric coordinates, checking for out of range at each step 1104 | float alpha = (u0*v2 - v0*u2) * Denominator; 1105 | if (!(alpha >= 0.0f)) return NoIntersection; 1106 | 1107 | float beta = (u1*v0 - v1*u0) * Denominator; 1108 | if (!(beta >= 0.0f)) return NoIntersection; 1109 | 1110 | float gamma = 1.0f - alpha - beta; 1111 | if (!(gamma >= 0.0f)) return NoIntersection; 1112 | 1113 | // Return parametric point of intersection 1114 | return t; 1115 | } 1116 | 1117 | /* 1118 | * Intersection of two rays in 3D 1119 | * 1120 | * Given two rays in 3D defined parametrically by: 1121 | * 1122 | * r1(t1) = p1 + t1*d1 1123 | * r2(t2) = p2 + t1*d2 1124 | * 1125 | * We can solve for the point of intersection. 1126 | * 1127 | * t1 = ((p2 - p1) x d2) * (d1 x d2) / ||d1 x d2||^2 1128 | * t2 = ((p2 - p1) x d1) * (d1 x d2) / ||d1 x d2||^2 1129 | * 1130 | * Where: 1131 | * 1132 | * x = cross product 1133 | * p1, p2 = origin vectors 1134 | * d1, d2 = delta vectors 1135 | * ||d1 x d2||^2 = the magnitude of the cross product of the delta vectors, squared 1136 | * 1137 | * NOTE: the range of t1 and t2 is not restricted. 1138 | * 1139 | * There will be 1 solution, no solutions, or infinite 1140 | * solutions (coincident lines). 3D has another case called "skew", 1141 | * meaning the lines do not share a common plane. 1142 | */ 1143 | template 1144 | inline static bool UGeometricTestLibrary::DoRaysIntersect( 1145 | const Vector3& RayOrigin1 // p1 1146 | , const Vector3& RayDelta1 // d1 1147 | , const Vector3& RayOrigin2 // p2 1148 | , const Vector3& RayDelta2) // d2 1149 | { 1150 | // Solve p2 - p1 1151 | Vector3 OriginDistance = RayOrigin2 - RayOrigin1; 1152 | 1153 | // Solve ((p2 - p1) x d2) 1154 | Vector3 CrossProdT1 = MyMathLibrary::CrossProduct(OriginDistance, RayDelta2); 1155 | 1156 | // Solve ((p2 - p1) x d1) 1157 | Vector3 CrossProdT2 = MyMathLibrary::CrossProduct(OriginDistance, RayDelta1); 1158 | 1159 | // Solve ||d1 x d2||^2 1160 | Vector3 CrossProdDirs = MyMathLibrary::CrossProduct(RayDelta1, RayDelta2); 1161 | float CrossProdMagnitude = CrossProdDirs.Magnitude(); 1162 | float Denominator = pow(CrossProdMagnitude, 2); 1163 | 1164 | // Solve ((p2 - p1) x d2) * (d1 x d2) 1165 | float Numerator1 = MyMathLibrary::DotProduct(CrossProdT1, CrossProdDirs); 1166 | 1167 | // Solve ((p2 - p1) x d1) * (d1 x d2) 1168 | float Numerator2 = MyMathLibrary::DotProduct(CrossProdT2, CrossProdDirs); 1169 | 1170 | // If the lines are coincident, there are an infinite number of solutions 1171 | // All numerators and denominators are zero in this case 1172 | if (Numerator1 == 0.f && Numerator2 == 0.f && Denominator == 0.f) 1173 | { 1174 | GEngine->AddOnScreenDebugMessage( 1175 | 1, 30.f, FColor::Red 1176 | , TEXT("\nRays are coincident! Infinite number of solutions!, GeometricTestLibrary.h:1176")); 1177 | 1178 | return false; 1179 | } 1180 | 1181 | // If the lines are parallel, then the cross product of d1 and d2 is the zero vector 1182 | // Therefore, the denominator of both equations is zero 1183 | if (Denominator == 0.f) 1184 | { 1185 | GEngine->AddOnScreenDebugMessage( 1186 | 2, 30.f, FColor::Red 1187 | , TEXT("\nRays are parallel! No solutions and no intersection!, GeometricTestLibrary.h:1187")); 1188 | 1189 | return false; 1190 | } 1191 | 1192 | // Solve ((p2 - p1) x d2) * (d1 x d2) / ||d1 x d2||^2 1193 | float t1 = Numerator1 / Denominator; 1194 | 1195 | // Solve ((p2 - p1) x d1) * (d1 x d2) / ||d1 x d2||^2 1196 | float t2 = Numerator2 / Denominator; 1197 | 1198 | // Solve R1, R2 for point of intersection 1199 | Vector3 R1 = RayOrigin1 + (RayDelta1*t1); 1200 | Vector3 R2 = RayOrigin2 + (RayDelta2*t2); 1201 | 1202 | // Return true if the two rays intersect at t1 == 0 && t2 == 0 1203 | if (t1 < 0 || t1 > R1.Magnitude() || t2 < 0 || t2 > R2.Magnitude()) 1204 | { 1205 | GEngine->AddOnScreenDebugMessage( 1206 | 2, 30.f, FColor::Red 1207 | , TEXT("\nRays are skew! They are neither parallel nor do they intersect!, GeometricTestLibrary.h:1207")); 1208 | 1209 | return false; 1210 | } 1211 | else 1212 | { 1213 | GEngine->AddOnScreenDebugMessage( 1214 | 2, 30.f, FColor::Red 1215 | , TEXT("\nSUCCESS! Rays intersect!, GeometricTestLibrary.h:1215")); 1216 | 1217 | return true; 1218 | } 1219 | } 1220 | 1221 | /* 1222 | * Dynamic (moving) sphere and static (stationary) plane intersection: 1223 | * 1224 | * Solve for t, the point of first intersection 1225 | * 1226 | * t = d - c*ň + r \ Ď*ň 1227 | * 1228 | * Where: 1229 | * 1230 | * d = p*ň, the plane equation, the distance from the plane to a point 1231 | * c = center of sphere 1232 | * r = radius of sphere 1233 | * Ď = normalized delta vector, a.k.a. unit vector 1234 | * ň = normalized surface normal of plane 1235 | */ 1236 | template 1237 | inline static int UGeometricTestLibrary::DoesSpherePlaneIntersect_Dynamic( 1238 | const Vector3& PlaneNormal // must be normalized first 1239 | , float PlaneD 1240 | , const Vector3& SphereDeltaVector 1241 | , const Vector3& SphereCenter 1242 | , float SphereRadius) 1243 | { 1244 | // Solve normalized plane normal 1245 | Vector3 NormalizedPlaneNormal = MyMathLibrary::Normalize(PlaneNormal); 1246 | 1247 | // Solve d 1248 | float Dot = MyMathLibrary::DotProduct(NormalizedPlaneNormal, SphereCenter); 1249 | float d = Dot - PlaneD; 1250 | 1251 | // Solve c*ň 1252 | float cn = MyMathLibrary::DotProduct(SphereCenter, NormalizedPlaneNormal); 1253 | 1254 | // Solve Ď 1255 | Vector3 DeltaNormal = MyMathLibrary::Normalize(SphereDeltaVector); 1256 | 1257 | // Solve Ď*ň 1258 | float Denominator = MyMathLibrary::DotProduct(DeltaNormal, NormalizedPlaneNormal); 1259 | 1260 | // If Denominator is zero, there is no intersection 1261 | if (Denominator == 0.f) 1262 | return INT_MAX; 1263 | 1264 | // Solve t = d - c*ň + r / Ď*ň 1265 | float t = d - cn + SphereRadius / Denominator; 1266 | 1267 | return 0; 1268 | } 1269 | 1270 | /* 1271 | * Static intersection of a sphere and a plane 1272 | * 1273 | * Given a sphere and plane, determine which side of 1274 | * the plane the sphere is on. 1275 | * 1276 | * <0 Sphere is completely on the back 1277 | * >0 Sphere is completely on the front 1278 | * 0 Sphere straddles plane 1279 | */ 1280 | template 1281 | inline static int UGeometricTestLibrary::DoesSpherePlaneIntersect_Static( 1282 | const Vector3& PlaneNormal // must be normalized first 1283 | , float PlaneD // p*PlaneNormal = PlaneD 1284 | , const Vector3& SphereCenter // center of sphere 1285 | , float SphereRadius) // radius of sphere 1286 | { 1287 | /* 1288 | * Solved by calculating distance from center 1289 | * of sphere to the plane: 1290 | * 1291 | * d = n*c - (p*n) 1292 | */ 1293 | 1294 | // Solve normalized plane normal 1295 | Vector3 NormalizedPlaneNormal = MyMathLibrary::Normalize(PlaneNormal); 1296 | 1297 | // Solve d 1298 | float Dot = MyMathLibrary::DotProduct(NormalizedPlaneNormal, SphereCenter); 1299 | float d = Dot - PlaneD; 1300 | 1301 | // On the front side? 1302 | if (d >= SphereRadius) 1303 | return 1; 1304 | 1305 | // On the back side? 1306 | if (d <= SphereRadius) 1307 | return -1; 1308 | 1309 | // Return intersection of sphere and the plane 1310 | return 0; 1311 | } 1312 | 1313 | /* 1314 | * Dynamic intersection of two circles or spheres 1315 | * 1316 | * Solve for t, the point of first intersection: 1317 | * 1318 | * t = e*Ď - sqrt((e*Ď)^2 + r^2 - e*e) 1319 | * 1320 | * Where: 1321 | * 1322 | * Ď = normalized delta vector 1323 | * D = moving delta vector - stationary delta vector 1324 | * e = stationary sphere center - moving sphere center 1325 | * ||e|| = magnitude of e 1326 | * r = sum of the sphere radii 1327 | * 1328 | * If ||e|| < r, then the spheres are intersecting at t = 0 1329 | * If t < 0 or t > length of total relative displacement, intersection does not occur 1330 | * If the square root argument is negative, there is no intersection 1331 | */ 1332 | template 1333 | inline static bool UGeometricTestLibrary::DoSpheresIntersect_Dynamic( 1334 | const Vector3& StationaryDeltaVector 1335 | , const Vector3& MovingDeltaVector 1336 | , const Vector3& StationarySphereCenter 1337 | , const Vector3& MovingSphereCenter // Defined at t = 0 1338 | , float StationarySphereRadius 1339 | , float MovingSphereRadius) 1340 | { 1341 | bool Result = false; 1342 | 1343 | // Solve D, Ď 1344 | Vector3 D = MovingDeltaVector - StationaryDeltaVector; 1345 | Vector3 NormalizedD = MyMathLibrary::Normalize(D); 1346 | 1347 | // Solve e, ||e|| 1348 | Vector3 e = StationarySphereCenter - MovingSphereCenter; 1349 | float eMag = e.Magnitude(); 1350 | 1351 | // Solve r, r^2 1352 | float r = StationarySphereRadius + MovingSphereRadius; 1353 | float RadiusSquared = pow(r, 2); 1354 | 1355 | // Solve e*Ď, (e*Ď)^2 1356 | float LHS = MyMathLibrary::DotProduct(e, NormalizedD); 1357 | float DotSquared = pow(LHS, 2); 1358 | 1359 | // Solve e*e 1360 | float eDot = MyMathLibrary::DotProduct(e, e); 1361 | 1362 | // Solve sqrt((e * Ď)^2 + r^2 - e*e) 1363 | float SqrtVal = (DotSquared + RadiusSquared) - eDot; 1364 | float RHS = sqrt(SqrtVal); 1365 | 1366 | // If the square root argument is negative, there is no intersection 1367 | if (SqrtVal < 0.f) 1368 | { 1369 | GEngine->AddOnScreenDebugMessage( 1370 | 1, 30.f, FColor::Red 1371 | , TEXT("\nFAILURE! No intersection! Square root value is negative!, GeometricTestLibrary.h:1371\n")); 1372 | 1373 | Result = false; 1374 | return Result; 1375 | } 1376 | 1377 | // Solve t 1378 | float t = LHS - RHS; 1379 | 1380 | // If ||e|| < r, then the spheres are intersecting at t = 0 during the time in question 1381 | if (eMag < r) 1382 | { 1383 | GEngine->AddOnScreenDebugMessage( 1384 | 3, 30.f, FColor::Red 1385 | , TEXT("\nSUCCESS! Spheres intersected at t = 0!, GeometricTestLibrary.h:1385\n")); 1386 | 1387 | Result = true; 1388 | } 1389 | 1390 | return Result; 1391 | } 1392 | 1393 | /* 1394 | * Static intersection of two circles or spheres 1395 | * 1396 | * Check if d^2 < (r1 + r2)^2 1397 | * 1398 | * Where: 1399 | * 1400 | * d = distance between the sphere centers 1401 | * r1, r2 = radii of spheres 1402 | */ 1403 | template 1404 | inline static bool UGeometricTestLibrary::DoSpheresIntersect_Static( 1405 | const Vector3& SphereCenter1 1406 | , float SphereRadius1 1407 | , const Vector3& SphereCenter2 1408 | , float SphereRadius2) 1409 | { 1410 | // Solve d 1411 | float Distance = MyMathLibrary::Distance(SphereCenter1, SphereCenter2); 1412 | 1413 | // Solve squares 1414 | float DistanceSquared = pow(Distance, 2); 1415 | float SumRadii = SphereRadius1 + SphereRadius2; 1416 | float RadiiSquared = pow(SumRadii, 2); 1417 | 1418 | // Solve d^2 < (r1 + r2)^2 1419 | if (DistanceSquared < RadiiSquared) 1420 | { 1421 | GEngine->AddOnScreenDebugMessage( 1422 | 1, 30.f, FColor::Red 1423 | , TEXT("\nSUCCESS! Spheres intersect!, GeometricTestLibrary.h:1423\n")); 1424 | 1425 | return true; 1426 | } 1427 | else 1428 | { 1429 | GEngine->AddOnScreenDebugMessage( 1430 | 2, 30.f, FColor::Red 1431 | , TEXT("\nFAILURE! Spheres do not intersect!, GeometricTestLibrary.h:1431\n")); 1432 | 1433 | return false; 1434 | } 1435 | } 1436 | 1437 | /* 1438 | * Intersection of three planes 1439 | * 1440 | * Solve for t, the point of intersection: 1441 | * 1442 | * t = d1*(n2 x n3) + d2*(n3 x n1) + d3*(n1 x n2) / (n1 x n2) * n3 1443 | * 1444 | * Where: 1445 | * 1446 | * x = cross product 1447 | * n = plane normal, a.k.a. surface normal, a.k.a. cross product of two non-parallel edges of polygon 1448 | * d = p*n = The Plane Equation (ax + by + cz + d = 0), the distance from the plane to the point (i.e., d1 = p*n1) 1449 | * 1450 | * If any pair of planes is parallel, the point of intersection 1451 | * either does not exist or is not unique. The denominator of 1452 | * the equation will be zero in this case. 1453 | */ 1454 | template 1455 | inline static Vector3 UGeometricTestLibrary::PointOfIntersection( 1456 | const Vector3& PlaneNormal1 // must be normalized first 1457 | , float PlaneD1 // p*PlaneNormal = PlaneD1 1458 | , const Vector3& PlaneNormal2 // must be normalized first 1459 | , float PlaneD2 // p*PlaneNormal2 = PlaneD2 1460 | , const Vector3& PlaneNormal3 // must be normalized first 1461 | , float PlaneD3) // p*PlaneNormal3 = PlaneD3 1462 | { 1463 | Vector3 Result = Vector3::ZeroVector; 1464 | 1465 | // Normalized Plane Normals 1466 | Vector3 NormalizedPlaneNormal1 = MyMathLibrary::Normalize(PlaneNormal1); 1467 | Vector3 NormalizedPlaneNormal2 = MyMathLibrary::Normalize(PlaneNormal2); 1468 | Vector3 NormalizedPlaneNormal3 = MyMathLibrary::Normalize(PlaneNormal3); 1469 | 1470 | // Solve Cross Products 1471 | Vector3 CrossProd1 = MyMathLibrary::CrossProduct(NormalizedPlaneNormal1, NormalizedPlaneNormal2); 1472 | Vector3 CrossProd2 = MyMathLibrary::CrossProduct(NormalizedPlaneNormal2, NormalizedPlaneNormal3); 1473 | Vector3 CrossProd3 = MyMathLibrary::CrossProduct(NormalizedPlaneNormal3, NormalizedPlaneNormal1); 1474 | 1475 | // Solve d1*(n2 x n3) 1476 | CrossProd2 *= PlaneD1; 1477 | 1478 | // Solve d2*(n3 x n1) 1479 | CrossProd3 *= PlaneD2; 1480 | 1481 | // Solve d3*(n1 x n2) 1482 | CrossProd1 *= PlaneD3; 1483 | 1484 | // Solve Numerator 1485 | Vector3 Numerator = CrossProd2 + CrossProd3 + CrossProd1; 1486 | 1487 | // Solve (n1 x n2) * n3 1488 | float Denominator = MyMathLibrary::DotProduct(CrossProd1, NormalizedPlaneNormal3); 1489 | 1490 | // If any pair of planes is parallel, the point of intersection 1491 | // either does not exist or is not unique. The denominator of 1492 | // the equation will be zero in this case. 1493 | if (Denominator == 0.f) 1494 | { 1495 | GEngine->AddOnScreenDebugMessage( 1496 | 1, 30.f, FColor::Red 1497 | , TEXT("\nFAILURE! A pair of planes are parallel! No intersection!, GeometricTestLibrary.h:1497")); 1498 | 1499 | return Result; 1500 | } 1501 | 1502 | // Solve t 1503 | Result = Numerator / Denominator; 1504 | 1505 | // Print Result 1506 | GEngine->AddOnScreenDebugMessage(2, 30.f, FColor::Red, TEXT("\nPoint of intersection of three planes is...")); 1507 | GEngine->AddOnScreenDebugMessage( 1508 | 3, 30.f, FColor::Red 1509 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 1510 | , Result.X, Result.Y, Result.Z)); 1511 | 1512 | // Return the point of intersection 1513 | return Result; 1514 | } 1515 | 1516 | // Intersection of Two AABBs 1517 | template 1518 | inline static bool UGeometricTestLibrary::DoAABBsIntersect( 1519 | const AABB& A 1520 | , const AABB& B) 1521 | { 1522 | /* 1523 | * Separating Axis Test 1524 | * 1525 | * If there is no overlap on a particular axis, 1526 | * then the two AABBs do not intersect 1527 | */ 1528 | 1529 | if (A.GetMin().X >= B.GetMax().X) return false; 1530 | if (A.GetMax().X <= B.GetMin().X) return false; 1531 | 1532 | if (A.GetMin().Y >= B.GetMax().Y) return false; 1533 | if (A.GetMax().Y <= B.GetMin().Y) return false; 1534 | 1535 | if (A.GetMin().Z >= B.GetMax().Z) return false; 1536 | if (A.GetMax().Z <= B.GetMin().Z) return false; 1537 | 1538 | // Overlap on all three axes, so their intersection must be non-empty 1539 | return true; 1540 | } 1541 | 1542 | /* 1543 | * Reflection Vector ("Perfect Mirror Bounce") 1544 | * 1545 | * Formula: 1546 | * 1547 | * r = 2(n * l)n - l 1548 | * 1549 | * But in order to "bounce", we must negate the r: 1550 | * 1551 | * r = -2(n * l)n + l 1552 | * 1553 | * Where: 1554 | * 1555 | * n = normalized surface normal 1556 | * l = normalized delta of light source 1557 | */ 1558 | template 1559 | inline static Vector3 UGeometricTestLibrary::SolveReflectionVector( 1560 | const Vector3& SurfaceNormal 1561 | , const Vector3& LightDelta) 1562 | { 1563 | Vector3 Result = Vector3::ZeroVector; 1564 | 1565 | // Solve n 1566 | const Vector3 NormalizedSurfaceNormal = MyMathLibrary::Normalize(SurfaceNormal); 1567 | 1568 | // Solve l 1569 | const Vector3 LightNormal = MyMathLibrary::Normalize(LightDelta); 1570 | 1571 | // Solve -2(n * l) 1572 | const float Dot = -2 * MyMathLibrary::DotProduct(NormalizedSurfaceNormal, LightNormal); 1573 | 1574 | // Solve n + l 1575 | const Vector3 Sum = NormalizedSurfaceNormal + LightNormal; 1576 | 1577 | // Solve r 1578 | Result = Sum * Dot; 1579 | 1580 | // Print r 1581 | GEngine->AddOnScreenDebugMessage(1, 30.f, FColor::Red, TEXT("\nReflection vector of l about n is...")); 1582 | GEngine->AddOnScreenDebugMessage( 1583 | 2, 30.f, FColor::Red 1584 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 1585 | , Result.X, Result.Y, Result.Z)); 1586 | 1587 | // Return the reflection vector 1588 | return Result; 1589 | } 1590 | 1591 | /* 1592 | * TODO: Barycentric Coordinates of a Triangle in 2D 1593 | * 1594 | * Solve for (b1, b2, b3): 1595 | * 1596 | * b1 = (py - y3)*(x2 - x3) + (y2 - y3)*(x3 - px) / (y1 - y3)*(x2 - x3) + (y2 - y3)*(x3 - x1) 1597 | * b2 = (py - y1)*(x3 - x1) + (y3 - y1)*(x1 - px) / (y1 - y3)*(x2 - x3) + (y2 - y3)*(x3 - x1) 1598 | * b3 = (py - y2)*(x1 - x2) + (y1 - y2)*(x2 - px) / (y1 - y3)*(x2 - x3) + (y2 - y3)*(x3 - x1) 1599 | * 1600 | * Where: 1601 | * 1602 | * p = given point 1603 | * x1, x2, x3 = 1604 | * y1, y2, y3 = 1605 | */ 1606 | 1607 | // Barycentric Coordinates of a Triangle in 3D 1608 | template 1609 | inline static Vector3 UGeometricTestLibrary::SolveBarycentricCoordinates3D( 1610 | const Vector3 Vertices[3] // vertices of the triangle 1611 | , const Vector3& Point // p 1612 | , float Barycentric[3]) // barycentric coordinates 1613 | { 1614 | Vector3 Result = Vector3::ZeroVector; 1615 | 1616 | // Solve two clockwise edge vectors 1617 | Vector3 d1 = Vertices[1] - Vertices[0]; 1618 | Vector3 d2 = Vertices[2] - Vertices[1]; 1619 | 1620 | // Solve n, the surface normal, unnormalized 1621 | Vector3 n = MyMathLibrary::CrossProduct(d1, d2); 1622 | 1623 | // Locate dominant axis of normal and select plane of projection 1624 | float u1, u2, u3, u4; 1625 | float v1, v2, v3, v4; 1626 | 1627 | if ((std::fabs(n.X) >= std::fabs(n.Y)) && (std::fabs(n.X) >= std::fabs(n.Z))) 1628 | { 1629 | // Discard X and project onto yz plane 1630 | u1 = Vertices[0].Y - Vertices[2].Y; 1631 | u2 = Vertices[1].Y - Vertices[2].Y; 1632 | u3 = Point.Y - Vertices[0].Y; 1633 | u4 = Point.Y - Vertices[2].Y; 1634 | 1635 | v1 = Vertices[0].Z - Vertices[2].Z; 1636 | v2 = Vertices[1].Z - Vertices[2].Z; 1637 | v3 = Point.Z - Vertices[0].Z; 1638 | v4 = Point.Z - Vertices[2].Z; 1639 | } 1640 | else if (std::fabs(n.Y) >= std::fabs(n.Z)) 1641 | { 1642 | // Discard Y and project onto xz plane 1643 | u1 = Vertices[0].Z - Vertices[2].Z; 1644 | u2 = Vertices[1].Z - Vertices[2].Z; 1645 | u3 = Point.Z - Vertices[0].Z; 1646 | u4 = Point.Z - Vertices[2].Z; 1647 | 1648 | v1 = Vertices[0].X - Vertices[2].X; 1649 | v2 = Vertices[1].X - Vertices[2].X; 1650 | v3 = Point.X - Vertices[0].X; 1651 | v4 = Point.X - Vertices[2].X; 1652 | } 1653 | else 1654 | { 1655 | // Discard Z and project onto xy plane 1656 | u1 = Vertices[0].X - Vertices[2].X; 1657 | u2 = Vertices[1].X - Vertices[2].X; 1658 | u3 = Point.X - Vertices[0].X; 1659 | u4 = Point.X - Vertices[2].X; 1660 | 1661 | v1 = Vertices[0].Y - Vertices[2].Y; 1662 | v2 = Vertices[1].Y - Vertices[2].Y; 1663 | v3 = Point.Y - Vertices[0].Y; 1664 | v4 = Point.Y - Vertices[2].Y; 1665 | } 1666 | 1667 | // Solve denominator 1668 | float Denominator = v1*u2 - v2*u1; 1669 | 1670 | // If denominator is zero, there are no coordinates because the triangle has zero area 1671 | if (Denominator == 0.f) 1672 | { 1673 | GEngine->AddOnScreenDebugMessage( 1674 | 1, 30.f, FColor::Red 1675 | , TEXT("\nFAILURE! No coordinates!, GeometricTestLibrary.h:1675\n")); 1676 | 1677 | return Result; 1678 | } 1679 | 1680 | // Solve barycentric coordinates 1681 | float OneOverDenom = 1 / Denominator; 1682 | Barycentric[0] = (v4*u2 - v2*u4) * OneOverDenom; 1683 | Barycentric[1] = (v1*u3 - v3*u1) * OneOverDenom; 1684 | Barycentric[2] = 1.f - Barycentric[0] - Barycentric[1]; 1685 | 1686 | Result.Set((float)Barycentric[0], (float)Barycentric[1], (float)Barycentric[2]); 1687 | 1688 | // Print Result 1689 | GEngine->AddOnScreenDebugMessage(2, 30.f, FColor::Red, TEXT("\nBarycentric coordinates of triangle are...")); 1690 | GEngine->AddOnScreenDebugMessage( 1691 | 3, 30.f, FColor::Red 1692 | , FString::Printf(TEXT("X: %f, Y: %f, Z: %f\n") 1693 | , Result.X, Result.Y, Result.Z)); 1694 | 1695 | // Return barycentric coordinates of triangle 1696 | return Result; 1697 | } 1698 | 1699 | /* 1700 | * These previous problems are courtesy of 1701 | * "3D Math Primer for Graphics and Game Development" by Dunn & Parberry: 1702 | * 1703 | * Intersection of AABB-Plane 1704 | * Intersection Ray-AABB 1705 | * Intersection of Ray-Triangle 1706 | * Intersection of Two AABBs 1707 | * Barycentric Coordinates of a Triangle in 3D 1708 | */ 1709 | -------------------------------------------------------------------------------- /Source/GeometricTests/GeometricTests.Build.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | using UnrealBuildTool; 18 | 19 | public class GeometricTests : ModuleRules 20 | { 21 | public GeometricTests(ReadOnlyTargetRules Target) : base(Target) 22 | { 23 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 24 | 25 | PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); 26 | 27 | PrivateDependencyModuleNames.AddRange(new string[] { }); 28 | 29 | // Uncomment if you are using Slate UI 30 | // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); 31 | 32 | // Uncomment if you are using online features 33 | // PrivateDependencyModuleNames.Add("OnlineSubsystem"); 34 | 35 | // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/GeometricTests/GeometricTests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "GeometricTests.h" 18 | #include "Modules/ModuleManager.h" 19 | 20 | IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, GeometricTests, "GeometricTests" ); 21 | -------------------------------------------------------------------------------- /Source/GeometricTests/GeometricTests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "CoreMinimal.h" 20 | 21 | -------------------------------------------------------------------------------- /Source/GeometricTests/GeometricTestsGameModeBase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "GeometricTestsGameModeBase.h" 18 | #include "GeometricTestLibrary.h" 19 | #include "Math/LinearAlgebra/Vector.h" 20 | #include "Math/Operations/MathOperations.h" 21 | #include "Primitives/AABB.h" 22 | #include "Primitives/Circle.h" 23 | #include "Primitives/Plane.h" 24 | #include "Primitives/Ray.h" 25 | #include "Engine.h" 26 | 27 | void AGeometricTestsGameModeBase::BeginPlay() 28 | { 29 | Super::BeginPlay(); 30 | 31 | // Closest Point in AABB 32 | //TEST_ClosestPointInAABB(); 33 | 34 | // Closest Point on Ray 35 | //TEST_ClosestPointOnRay(); 36 | 37 | // Closest Point on Plane 38 | //TEST_ClosestPointOnPlane(); 39 | 40 | // Closest Point on Sphere 41 | //TEST_ClosestPointOnSphere(); 42 | 43 | // Intersection AABB-Plane 44 | //TEST_DoesAABBPlaneIntersect(); 45 | 46 | // Intersection of Two Lines in 2D 47 | //TEST_DoLinesIntersect(); 48 | 49 | // Intersection Ray-AABB 50 | //TEST_DoesRayAABBIntersect(); 51 | 52 | // Intersection Ray-Plane 53 | //TEST_DoesRayPlaneIntersect(); 54 | 55 | // Intersection Ray-Sphere 56 | //TEST_DoesRaySphereIntersect(); 57 | 58 | // Intersection Ray-Triangle 59 | //TEST_DoesRayTriangleIntersect(); 60 | 61 | // Intersection of Two Rays in 3D 62 | //TEST_DoRaysIntersect(); 63 | 64 | // Dynamic Intersection Sphere-Plane 65 | TEST_DoesSpherePlaneIntersect_Dynamic(); 66 | 67 | // Static Intersection Sphere-Plane 68 | //TEST_DoesSpherePlaneIntersect_Static(); 69 | 70 | // Dynamic Intersection of Two Circles or Spheres 71 | //TEST_DoSpheresIntersect_Dynamic(); 72 | 73 | // Static Intersection of Two Circles or Spheres 74 | //TEST_DoSpheresIntersect_Static(); 75 | 76 | // Intersection of Three Planes 77 | //TEST_DoThreePlanesIntersect(); 78 | 79 | // Intersection of Two AABBs 80 | //TEST_DoAABBsIntersect(); 81 | 82 | // Reflection Vector 83 | //TEST_SolveReflectionVector(); 84 | 85 | // Barycentric Coordinates in 3D 86 | //TEST_SolveBarycentricCoordinates3D(); 87 | } 88 | 89 | void AGeometricTestsGameModeBase::TEST_ClosestPointInAABB() 90 | { 91 | const Vector3 Point = Vector3(6.f, 3.f, -4.f); 92 | 93 | const Vector3 MinBounds = Vector3(-1.f, -1.f, -1.f); 94 | const Vector3 MaxBounds = Vector3(5.f, 5.f, 5.f); 95 | AABB MyAABB(MinBounds, MaxBounds); 96 | 97 | UGeometricTestLibrary::ClosestPointInAABB(Point, MyAABB); 98 | } 99 | 100 | void AGeometricTestsGameModeBase::TEST_ClosestPointOnRay() 101 | { 102 | const Vector3 Point = Vector3(12.f, 6.f, 4.f); 103 | //const Vector3 Point = Vector3(5.f, 5.f, 6.f); 104 | 105 | const Vector3 RayOrigin = Vector3(2.f, 2.f, 4.f); 106 | const Vector3 RayDelta = Vector3(10.f, 15.f, 4.f); 107 | Ray MyRay(RayOrigin, RayDelta); 108 | 109 | UGeometricTestLibrary::ClosestPointOnRay(Point, MyRay.GetOrigin(), MyRay.GetDelta()); 110 | } 111 | 112 | void AGeometricTestsGameModeBase::TEST_ClosestPointOnPlane() 113 | { 114 | const Vector3 Point = Vector3(12.f, 6.f, 4.f); 115 | 116 | const float A = 2.f; 117 | const float B = 3.f; 118 | const float C = 1.f; 119 | const float D = 3.f; 120 | Plane MyPlane(A, B, C, D); 121 | 122 | UGeometricTestLibrary::ClosestPointOnPlane(Point, MyPlane.Normal, MyPlane.D); 123 | } 124 | 125 | void AGeometricTestsGameModeBase::TEST_ClosestPointOnSphere() 126 | { 127 | const Vector3 Point = Vector3(12.f, 6.f, 4.f); 128 | 129 | const Vector3 SphereCenter = Vector3(0.f, 0.f, 0.f); 130 | const float SphereRadius = 10.f; 131 | Circle MyCircle(SphereRadius, SphereCenter); 132 | 133 | UGeometricTestLibrary::ClosestPointOnSphere(Point, MyCircle.GetCenter(), MyCircle.GetRadius()); 134 | } 135 | 136 | void AGeometricTestsGameModeBase::TEST_DoesAABBPlaneIntersect() 137 | { 138 | const float A = 2.f; 139 | const float B = 3.f; 140 | const float C = 1.f; 141 | const float D = 3.f; 142 | Plane MyPlane(A, B, C, D); 143 | 144 | const Vector3 MinBounds = Vector3(-1.f, -1.f, -1.f); 145 | const Vector3 MaxBounds = Vector3(5.f, 5.f, 5.f); 146 | AABB MyAABB(MinBounds, MaxBounds); 147 | 148 | UGeometricTestLibrary::DoesAABBPlaneIntersect(MyPlane.Normal, MyPlane.D, MyAABB); 149 | } 150 | 151 | void AGeometricTestsGameModeBase::TEST_DoLinesIntersect() 152 | { 153 | const Vector2 Origin1 = Vector2(1.f, 1.f); 154 | const Vector2 Delta1 = Vector2(7.f, 15.f); 155 | 156 | //const Vector2 Origin2 = Vector2(-1.f, 5.f); 157 | //const Vector2 Delta2 = Vector2(-1.f, 2.f); 158 | const Vector2 Origin2 = Vector2(-1.f, 5.f); 159 | const Vector2 Delta2 = Vector2(8.f, 12.f); 160 | 161 | UGeometricTestLibrary::DoLinesIntersect(Origin1, Delta1, Origin2, Delta2); 162 | } 163 | 164 | void AGeometricTestsGameModeBase::TEST_DoesRayAABBIntersect() 165 | { 166 | Vector3* ReturnNormal = nullptr; 167 | 168 | const Vector3 RayOrigin = Vector3(-1.f, 2.f, 5.f); 169 | const Vector3 RayDelta = Vector3(-1.f, 5.f, 7.f); 170 | Ray MyRay(RayOrigin, RayDelta); 171 | 172 | const Vector3 MinBounds = Vector3(-1.f, -1.f, -1.f); 173 | const Vector3 MaxBounds = Vector3(5.f, 5.f, 5.f); 174 | AABB MyAABB(MinBounds, MaxBounds); 175 | 176 | UGeometricTestLibrary::DoesRayAABBIntersect(MyRay.GetOrigin(), MyRay.GetDelta(), MyAABB, ReturnNormal); 177 | 178 | /* 179 | * NOTE: AABB can be replaced by any box, square, capsule, etc. 180 | */ 181 | } 182 | 183 | void AGeometricTestsGameModeBase::TEST_DoesRayPlaneIntersect() 184 | { 185 | const Vector3 RayOrigin = Vector3(1.f, 1.f, 1.f); 186 | const Vector3 RayDelta = Vector3(7.f, 15.f, 18.f); 187 | Ray MyRay(RayOrigin, RayDelta); 188 | 189 | const float A = -1.f; 190 | const float B = 2.f; 191 | const float C = 1.f; 192 | const float D = 2.f; 193 | Plane MyPlane(A, B, C, D); 194 | 195 | UGeometricTestLibrary::DoesRayPlaneIntersect( 196 | MyRay.GetOrigin() 197 | , MyRay.GetDelta() 198 | , MyPlane.Normal 199 | , MyPlane.D); 200 | } 201 | 202 | void AGeometricTestsGameModeBase::TEST_DoesRaySphereIntersect() 203 | { 204 | const Vector3 RayOrigin = Vector3(0.f, 0.f, 0.f); 205 | const Vector3 RayDelta = Vector3(5.f, 8.f, 5.f); 206 | Ray MyRay(RayOrigin, RayDelta); 207 | 208 | const Vector3 SphereCenter = Vector3(3.f, 3.f, 3.f); 209 | const float SphereRadius = 5.f; 210 | Circle MyCircle(SphereRadius, SphereCenter); 211 | 212 | UGeometricTestLibrary::DoesRaySphereIntersect( 213 | MyCircle.GetCenter() 214 | , MyCircle.GetRadius() 215 | , MyRay.GetOrigin() 216 | , MyRay.GetDelta()); 217 | } 218 | 219 | void AGeometricTestsGameModeBase::TEST_DoesRayTriangleIntersect() 220 | { 221 | const Vector3 RayOrigin = Vector3(1.f, 1.f, 1.f); 222 | const Vector3 RayDelta = Vector3(7.f, 15.f, 18.f); 223 | Ray MyRay(RayOrigin, RayDelta); 224 | 225 | const Vector3 Vertex1 = Vector3(2.f, 3.f, 1.f); 226 | const Vector3 Vertex2 = Vector3(3.f, 5.f, 2.f); 227 | const Vector3 Vertex3 = Vector3(2.f, 2.f, 2.f); 228 | 229 | float MinT = 1.f; 230 | 231 | UGeometricTestLibrary::DoesRayTriangleIntersect( 232 | MyRay.GetOrigin() 233 | , MyRay.GetDelta() 234 | , Vertex1 235 | , Vertex2 236 | , Vertex3 237 | , MinT); 238 | } 239 | 240 | void AGeometricTestsGameModeBase::TEST_DoRaysIntersect() 241 | { 242 | const Vector3 RayOrigin1 = Vector3(10.f, 15.f, 1.f); 243 | const Vector3 RayDelta1 = Vector3(49.f, 25.f, 1.f); 244 | 245 | const Vector3 RayOrigin2 = Vector3(20.f, 10.f, 1.f); 246 | const Vector3 RayDelta2 = Vector3(32.f, 32.f, 1.f); 247 | 248 | Ray Ray1(RayOrigin1, RayDelta1); 249 | Ray Ray2(RayOrigin2, RayDelta2); 250 | 251 | UGeometricTestLibrary::DoRaysIntersect( 252 | Ray1.GetOrigin() 253 | , Ray1.GetDelta() 254 | , Ray2.GetOrigin() 255 | , Ray2.GetDelta()); 256 | } 257 | 258 | void AGeometricTestsGameModeBase::TEST_DoesSpherePlaneIntersect_Dynamic() 259 | { 260 | const float A = 2.f; 261 | const float B = 3.f; 262 | const float C = 1.f; 263 | const float D = 3.f; 264 | Plane MyPlane(A, B, C, D); 265 | 266 | const Vector3 SphereCenter = Vector3(3.f, 3.f, 3.f); 267 | const float SphereRadius = 5.f; 268 | Circle MyCircle(SphereRadius, SphereCenter); 269 | 270 | Vector3 SphereDeltaVector = Vector3(2.f, 3.5f, 0.f); 271 | //Vector3 SphereDeltaVector = Vector3(11.f, 3.5f, -9.f); 272 | 273 | UGeometricTestLibrary::DoesSpherePlaneIntersect_Dynamic( 274 | MyPlane.Normal 275 | , MyPlane.D 276 | , SphereDeltaVector 277 | , MyCircle.GetCenter() 278 | , MyCircle.GetRadius()); 279 | } 280 | 281 | void AGeometricTestsGameModeBase::TEST_DoesSpherePlaneIntersect_Static() 282 | { 283 | const float A = 2.f; 284 | const float B = 3.f; 285 | const float C = 1.f; 286 | const float D = 3.f; 287 | Plane MyPlane(A, B, C, D); 288 | 289 | const Vector3 SphereCenter = Vector3(-5.f, -5.f, -5.f); 290 | const float SphereRadius = 5.f; 291 | Circle MyCircle(SphereRadius, SphereCenter); 292 | 293 | UGeometricTestLibrary::DoesSpherePlaneIntersect_Static( 294 | MyPlane.Normal 295 | , MyPlane.D 296 | , MyCircle.GetCenter() 297 | , MyCircle.GetRadius()); 298 | } 299 | 300 | void AGeometricTestsGameModeBase::TEST_DoSpheresIntersect_Dynamic() 301 | { 302 | Vector3 StationaryDeltaVector = Vector3(10.f, 2.f, -9.f); 303 | Vector3 MovingDeltaVector = Vector3(11.f, 3.5f, -9.f); 304 | 305 | const Vector3 StationarySphereCenter = Vector3(-5.f, -5.f, -5.f); 306 | Vector3 MovingSphereCenter = Vector3::ZeroVector; 307 | 308 | const float StationarySphereRadius = 5.f; 309 | const float MovingSphereRadius = 6.f; 310 | 311 | Circle MovingCircle(MovingSphereRadius, MovingSphereCenter); 312 | Circle StationaryCircle(StationarySphereRadius, StationarySphereCenter); 313 | 314 | UGeometricTestLibrary::DoSpheresIntersect_Dynamic( 315 | StationaryDeltaVector 316 | , MovingDeltaVector 317 | , StationaryCircle.GetCenter() 318 | , MovingCircle.GetCenter() 319 | , StationaryCircle.GetRadius() 320 | , MovingCircle.GetRadius()); 321 | } 322 | 323 | void AGeometricTestsGameModeBase::TEST_DoSpheresIntersect_Static() 324 | { 325 | const Vector3 SphereCenter1 = Vector3::ZeroVector; 326 | const Vector3 SphereCenter2 = Vector3(-5.f, -5.f, -5.f); 327 | 328 | const float SphereRadius1 = 12.f; 329 | const float SphereRadius2 = 2.5f; 330 | 331 | Circle Circle1(SphereRadius1, SphereCenter1); 332 | Circle Circle2(SphereRadius2, SphereCenter2); 333 | 334 | UGeometricTestLibrary::DoSpheresIntersect_Static( 335 | Circle1.GetCenter() 336 | , Circle1.GetRadius() 337 | , Circle2.GetCenter() 338 | , Circle2.GetRadius()); 339 | } 340 | 341 | void AGeometricTestsGameModeBase::TEST_DoThreePlanesIntersect() 342 | { 343 | float A1 = 2.f; 344 | float B1 = 3.f; 345 | float C1 = 1.f; 346 | float D1 = 3.f; 347 | Plane Plane1(A1, B1, C1, D1); 348 | 349 | float A2 = -1.f; 350 | float B2 = 2.f; 351 | float C2 = 1.f; 352 | float D2 = 2.f; 353 | Plane Plane2(A2, B2, C2, D2); 354 | 355 | float A3 = 6.f; 356 | float B3 = -5.f; 357 | float C3 = 2.f; 358 | float D3 = -8.f; 359 | Plane Plane3(A3, B3, C3, D3); 360 | 361 | UGeometricTestLibrary::PointOfIntersection( 362 | Plane1.Normal 363 | , Plane1.D 364 | , Plane2.Normal 365 | , Plane2.D 366 | , Plane3.Normal 367 | , Plane3.D); 368 | } 369 | 370 | void AGeometricTestsGameModeBase::TEST_DoAABBsIntersect() 371 | { 372 | const Vector3 MinBoundsA = Vector3(-1.f, -1.f, -1.f); 373 | const Vector3 MaxBoundsA = Vector3(5.f, 5.f, 5.f); 374 | AABB A(MinBoundsA, MaxBoundsA); 375 | 376 | const Vector3 MinBoundsB = Vector3(1.f, 2.f, 1.f); 377 | const Vector3 MaxBoundsB = Vector3(3, 2.f, 3.f); 378 | AABB B(MinBoundsB, MaxBoundsB); 379 | 380 | UGeometricTestLibrary::DoAABBsIntersect(A, B); 381 | } 382 | 383 | void AGeometricTestsGameModeBase::TEST_SolveReflectionVector() 384 | { 385 | Vector3 LightDelta = Vector3(-3.f, -5.f, 7.f); 386 | 387 | const float A = 6.f; 388 | const float B = -5.f; 389 | const float C = 2.f; 390 | const float D = -8.f; 391 | Plane MyPlane(A, B, C, D); 392 | 393 | UGeometricTestLibrary::SolveReflectionVector(MyPlane.Normal, LightDelta); 394 | } 395 | 396 | void AGeometricTestsGameModeBase::TEST_SolveBarycentricCoordinates3D() 397 | { 398 | const Vector3 Vertices[3] = { Vector3(-3.f, -5.f, 7.f) 399 | , Vector3(1.f, 2.f, 1.f) 400 | , Vector3(3, 2.f, 3.f) }; 401 | 402 | const Vector3 Point = Vector3(0.f, 6.f, 4.f); 403 | 404 | float Barycentric[3] = { 1, 1, 1 }; 405 | 406 | UGeometricTestLibrary::SolveBarycentricCoordinates3D(Vertices, Point, Barycentric); 407 | } 408 | 409 | -------------------------------------------------------------------------------- /Source/GeometricTests/GeometricTestsGameModeBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "CoreMinimal.h" 20 | #include "GameFramework/GameModeBase.h" 21 | #include "GeometricTestsGameModeBase.generated.h" 22 | 23 | /** 24 | * 25 | */ 26 | UCLASS() 27 | class GEOMETRICTESTS_API AGeometricTestsGameModeBase : public AGameModeBase 28 | { 29 | GENERATED_BODY() 30 | 31 | public: 32 | 33 | AGeometricTestsGameModeBase() = default; 34 | ~AGeometricTestsGameModeBase() = default; 35 | 36 | // UE4: UObject copying and moving disabled 37 | 38 | protected: 39 | 40 | virtual void BeginPlay() override; 41 | 42 | private: 43 | 44 | /* 45 | * Closest Point Tests 46 | */ 47 | void TEST_ClosestPointInAABB(); 48 | void TEST_ClosestPointOnRay(); 49 | void TEST_ClosestPointOnPlane(); 50 | void TEST_ClosestPointOnSphere(); 51 | 52 | /* 53 | * Intersection Tests 54 | */ 55 | void TEST_DoesAABBPlaneIntersect(); 56 | void TEST_DoLinesIntersect(); 57 | void TEST_DoesRayAABBIntersect(); 58 | void TEST_DoesRayPlaneIntersect(); 59 | void TEST_DoesRaySphereIntersect(); 60 | void TEST_DoesRayTriangleIntersect(); 61 | void TEST_DoRaysIntersect(); 62 | void TEST_DoesSpherePlaneIntersect_Dynamic(); 63 | void TEST_DoesSpherePlaneIntersect_Static(); 64 | void TEST_DoSpheresIntersect_Dynamic(); 65 | void TEST_DoSpheresIntersect_Static(); 66 | void TEST_DoThreePlanesIntersect(); 67 | void TEST_DoAABBsIntersect(); 68 | 69 | /* 70 | * Reflection Vector 71 | */ 72 | void TEST_SolveReflectionVector(); 73 | 74 | /* 75 | * Barycentric Coordinates 76 | */ 77 | void TEST_SolveBarycentricCoordinates3D(); 78 | }; 79 | -------------------------------------------------------------------------------- /Source/GeometricTests/Math/LinearAlgebra/Quaternion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include "Vector.h" 22 | 23 | /* 24 | * Quaternion.h 25 | * 26 | * A quaternion is a 4D Vector that contains 27 | * a scalar component (W) and a 3D Vector component (V): 28 | * 29 | * { W, V } or { W, (X, Y, Z) } 30 | * 31 | * A quaternion contains an axis and an angle. Rotation 32 | * values are stored in degrees. 33 | */ 34 | 35 | template 36 | struct Quaternion 37 | { 38 | 39 | public: 40 | 41 | //~ Quaternion Variables. Commonly use 4-byte float or 8-byte double. 42 | T W; // 4 bytes 43 | T X; // 4 bytes 44 | T Y; // 4 bytes 45 | T Z; // 4 bytes 46 | //~ Total Memory Load: 16 bytes 47 | 48 | // Constructor: No Arguments, Zero Rotation 49 | inline explicit Quaternion() : W(0), X(0), Y(0), Z(0) {} 50 | 51 | // Constructor: Passing Four Coordinates 52 | inline constexpr Quaternion( 53 | const T& _W 54 | , const T& _X 55 | , const T& _Y 56 | , const T& _Z) : 57 | W(_W) 58 | , X(_X) 59 | , Y(_Y) 60 | , Z(_Z) 61 | {} 62 | 63 | // Constructor: Convert from axis-angle format in radians 64 | inline explicit Quaternion(const Vector3& Axis, const float Radians) 65 | { 66 | const float HalfAngle = 0.5f * Radians; 67 | W = std::cos(HalfAngle); 68 | X = Axis.GetX() * std::sin(HalfAngle); 69 | Y = Axis.GetY() * std::sin(HalfAngle); 70 | Z = Axis.GetZ() * std::sin(HalfAngle); 71 | } 72 | 73 | ~Quaternion() = default; 74 | 75 | inline constexpr T GetW() const { return W; } 76 | inline constexpr T GetX() const { return X; } 77 | inline constexpr T GetY() const { return Y; } 78 | inline constexpr T GetZ() const { return Z; } 79 | 80 | inline T Magnitude() 81 | { 82 | return sqrt(pow(W, 2) + pow(X, 2) + pow(Y, 2) + pow(Z, 2)); 83 | } 84 | 85 | inline T DotProduct(const Quaternion& LHS, const Quaternion& RHS) 86 | { 87 | return (LHS.W*RHS.W + LHS.X*RHS.X + LHS.Y*RHS.Y + LHS.Z*RHS.Z); 88 | } 89 | 90 | inline Quaternion Inverse(const Quaternion& Quat) 91 | { 92 | return Quaternion(Quat.W, -Quat.X, -Quat.Y, -Quat.Z); 93 | } 94 | 95 | static const Quaternion ZeroRotation; 96 | 97 | //~ Begin Operator Overloads 98 | inline bool operator==(const Quaternion& Other) const 99 | { 100 | return (W == Other.W 101 | && X == Other.X 102 | && Y == Other.Y 103 | && Z == Other.Z); 104 | } 105 | 106 | inline bool operator!=(const Quaternion& Other) const 107 | { 108 | return (W != Other.W 109 | || X != Other.X 110 | || Y != Other.Y 111 | || Z != Other.Z); 112 | } 113 | 114 | inline Quaternion operator+(const Quaternion& Other) const 115 | { 116 | return Quaternion(W + Other.W, X + Other.X, Y + Other.Y, Z + Other.Z); 117 | } 118 | 119 | inline Quaternion operator+(float Bias) const 120 | { 121 | return Quaternion(W + Bias, X + Bias, Y + Bias, Z + Bias); 122 | } 123 | 124 | inline Quaternion operator-() const 125 | { 126 | return { -W, -X, -Y, -Z }; 127 | } 128 | 129 | inline Quaternion operator-(const Quaternion& Other) const 130 | { 131 | return Quaternion(W - Other.W, X - Other.X, Y - Other.Y, Z - Other.Z); 132 | } 133 | 134 | inline Quaternion operator-(float Bias) const 135 | { 136 | return Quaternion(W - Bias, X - Bias, Y - Bias, Z - Bias); 137 | } 138 | 139 | inline Quaternion operator*(float Scalar) const 140 | { 141 | return Quaternion(W * Scalar, X * Scalar, Y * Scalar, Z * Scalar); 142 | } 143 | 144 | inline Quaternion operator*(const Quaternion& Other) const 145 | { 146 | return Quaternion(W * Other.W, X * Other.X, Y * Other.Y, Z * Other.Z); 147 | } 148 | 149 | inline Quaternion operator*=(float Scalar) 150 | { 151 | W *= Scalar; 152 | X *= Scalar; 153 | Y *= Scalar; 154 | Z *= Scalar; 155 | return *this; 156 | } 157 | 158 | inline Quaternion operator*=(const Quaternion& Other) 159 | { 160 | W *= Other.W; 161 | X *= Other.X; 162 | Y *= Other.Y; 163 | Z *= Other.Z; 164 | return *this; 165 | } 166 | //~ End Operator Overloads 167 | 168 | // Copy Constructor 169 | Quaternion(const Quaternion& Other) : 170 | W(Other.W) 171 | , X(Other.X) 172 | , Y(Other.Y) 173 | , Z(Other.Z) 174 | {} 175 | 176 | // Copy-Assignment Operator 177 | Quaternion& operator=(const Quaternion& Other) 178 | { 179 | if (this != &Other) 180 | { 181 | X = Other.X; 182 | Y = Other.Y; 183 | Z = Other.Z; 184 | } 185 | 186 | return *this; 187 | } 188 | 189 | // Move Constructor 190 | Quaternion(Quaternion&& Other) : 191 | W(0) 192 | , X(0) 193 | , Y(0) 194 | , Z(0) 195 | { *this = std::move(Other); } 196 | 197 | // Move-Assignment Operator 198 | Quaternion& operator=(Quaternion&& Other) 199 | { 200 | if (this != &Other) 201 | { 202 | W = Other.W; 203 | X = Other.X; 204 | Y = Other.Y; 205 | Z = Other.Z; 206 | 207 | Other.W = 0; 208 | Other.X = 0; 209 | Other.Y = 0; 210 | Other.Z = 0; 211 | } 212 | 213 | return *this; 214 | } 215 | }; 216 | 217 | template Quaternion const Vector3::ZeroRotation = Quaternion(0, 0, 0, 0); 218 | 219 | template 220 | inline Quaternion operator*(const Quaternion& LHS, float Scalar) 221 | { 222 | return LHS.operator*(Scalar); 223 | } -------------------------------------------------------------------------------- /Source/GeometricTests/Math/LinearAlgebra/Vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "CoreMinimal.h" 20 | #include 21 | #include 22 | 23 | /* 24 | * Vector.h 25 | * 26 | * A vector is a directed line segment with 27 | * a direction and a magnitude (length). A vector 28 | * may have any nonnegative length. 29 | */ 30 | 31 | // 2D Vectors (Using for Intersection of Two Lines in 2D) 32 | template 33 | struct Vector2 34 | { 35 | 36 | public: 37 | 38 | //~ 2D Vector Variables. Commonly use 4-byte float or 8-byte double. 39 | T X; // 4 bytes 40 | T Y; // 4 bytes 41 | //~ Total Memory Load: 8 bytes 42 | 43 | // Constructor: No Arguments 44 | inline explicit Vector2() : X(0), Y(0) {} 45 | 46 | // Constructor: Passing Two Coordinates 47 | inline Vector2( 48 | const T& _X 49 | , const T& _Y) : 50 | X(_X) 51 | , Y(_Y) 52 | {} 53 | 54 | inline constexpr T GetX() const { return X; } 55 | inline constexpr T GetY() const { return Y; } 56 | 57 | inline void Set(const T& _X, const T& _Y) 58 | { 59 | X = _X; 60 | Y = _Y; 61 | } 62 | 63 | // The magnitude (length) of a vector is the square root of the sum 64 | // of the squares of the components of the vector 65 | inline T Magnitude() 66 | { 67 | return sqrt(pow(X, 2) + pow(Y, 2)); 68 | } 69 | 70 | // Vector Directions 71 | static const Vector2 ZeroVector; 72 | static const Vector2 ForwardVector; 73 | static const Vector2 BackwardVector; 74 | static const Vector2 RightVector; 75 | static const Vector2 LeftVector; 76 | 77 | //~ Begin Operator Overloads 78 | bool operator==(const Vector2& Other) const 79 | { 80 | return (X == Other.X 81 | && Y == Other.Y); 82 | } 83 | 84 | bool operator!=(const Vector2& Other) const 85 | { 86 | return (X != Other.X 87 | || Y != Other.Y); 88 | } 89 | 90 | bool operator<(const Vector2& Other) const 91 | { 92 | if (X != Other.X) return X < Other.X; 93 | else if (Y != Other.Y) return Y < Other.Y; 94 | else return false; 95 | } 96 | 97 | bool operator>(const Vector2& Other) const 98 | { 99 | if (X != Other.X) return X > Other.X; 100 | else if (Y != Other.Y) return Y > Other.Y; 101 | else return false; 102 | } 103 | 104 | inline T& operator[](int Index) 105 | { 106 | check(Index >= 0 && Index < 2); // In C++, use "assert". 107 | if (Index == 0) return X; 108 | else return Y; 109 | } 110 | 111 | inline T operator[](int Index) const 112 | { 113 | check(Index >= 0 && Index < 2); // In C++, use "assert". 114 | if (Index == 0) return X; 115 | else return Y; 116 | } 117 | 118 | inline Vector2 operator-() const 119 | { 120 | return{ -X, -Y }; 121 | } 122 | 123 | inline Vector2 operator*(T Scalar) const 124 | { 125 | return Vector2(X * Scalar, Y * Scalar); 126 | } 127 | 128 | inline Vector2 operator*(const Vector2& Other) const 129 | { 130 | return Vector2(X * Other.X, Y * Other.Y); 131 | } 132 | 133 | inline Vector2 operator*=(T Scalar) const 134 | { 135 | X *= Scalar; 136 | Y *= Scalar; 137 | return *this; 138 | } 139 | 140 | inline Vector2 operator*=(const Vector2& Other) const 141 | { 142 | X *= Other.X; 143 | Y *= Other.Y; 144 | return *this; 145 | } 146 | //~ End Operator Overloads 147 | 148 | // Copy-Assignment Operator returns *this 149 | Vector2& operator=(const Vector2& Other) 150 | { 151 | X = Other.X; 152 | Y = Other.Y; 153 | return *this; 154 | } 155 | }; 156 | 157 | // 3D Vectors 158 | template 159 | struct Vector3 160 | { 161 | 162 | public: 163 | 164 | //~ 3D Vector Variables. Commonly use 4-byte float or 8-byte double. 165 | T X; // 4 bytes 166 | T Y; // 4 bytes 167 | T Z; // 4 bytes 168 | //~ Total Memory Load: 12 bytes 169 | 170 | // Constructor: No Arguments 171 | inline explicit Vector3() : X(0), Y(0), Z(0) {} 172 | 173 | // Constructor: Passing Three Coordinates 174 | inline Vector3( 175 | const T& _X 176 | , const T& _Y 177 | , const T& _Z) : 178 | X(_X) 179 | , Y(_Y) 180 | , Z(_Z) 181 | {} 182 | 183 | inline constexpr T GetX() const { return X; } 184 | inline constexpr T GetY() const { return Y; } 185 | inline constexpr T GetZ() const { return Z; } 186 | 187 | inline void Set(const T& _X, const T& _Y, const T& _Z) 188 | { 189 | X = _X; 190 | Y = _Y; 191 | Z = _Z; 192 | } 193 | 194 | // The magnitude (length) of a vector is the square root of the sum 195 | // of the squares of the components of the vector 196 | inline T Magnitude() 197 | { 198 | return sqrt(pow(X, 2) + pow(Y, 2) + pow(Z, 2)); 199 | } 200 | 201 | // Vector Directions 202 | static const Vector3 ZeroVector; 203 | static const Vector3 UpVector; 204 | static const Vector3 DownVector; 205 | static const Vector3 ForwardVector; 206 | static const Vector3 BackwardVector; 207 | static const Vector3 RightVector; 208 | static const Vector3 LeftVector; 209 | 210 | //~ Begin Operator Overloads 211 | inline bool operator==(const Vector3& Other) const 212 | { 213 | return (X == Other.X 214 | && Y == Other.Y 215 | && Z == Other.Z); 216 | } 217 | 218 | inline bool operator!=(const Vector3& Other) const 219 | { 220 | return (X != Other.X 221 | || Y != Other.Y 222 | || Z != Other.Z); 223 | } 224 | 225 | inline bool operator<(const Vector3& Other) const 226 | { 227 | if (X != Other.X) return X < Other.X; 228 | else if (Y != Other.Y) return Y < Other.Y; 229 | else if (Z != Other.Z) return Z < Other.Z; 230 | else return false; 231 | } 232 | 233 | inline bool operator>(const Vector3& Other) const 234 | { 235 | if (X != Other.X) return X > Other.X; 236 | else if (Y != Other.Y) return Y > Other.Y; 237 | else if (Z != Other.Z) return Z > Other.Z; 238 | else return false; 239 | } 240 | 241 | inline T& operator[](int Index) 242 | { 243 | check(Index >= 0 && Index < 3); // In C++, use "assert". 244 | if (Index == 0) return X; 245 | else if (Index == 1) return Y; 246 | else return Z; 247 | } 248 | 249 | inline T operator[](int Index) const 250 | { 251 | check(Index >= 0 && Index < 3); // In C++, use "assert". 252 | if (Index == 0) return X; 253 | else if (Index == 1) return Y; 254 | else return Z; 255 | } 256 | 257 | inline Vector3 operator+(const Vector3& Other) const 258 | { 259 | return Vector3(X + Other.X, Y + Other.Y, Z + Other.Z); 260 | } 261 | 262 | inline Vector3 operator+(float Bias) const 263 | { 264 | return Vector3(X + Bias, Y + Bias, Z + Bias); 265 | } 266 | 267 | inline Vector3 operator-() const 268 | { 269 | return { -X, -Y, -Z }; 270 | } 271 | 272 | inline Vector3 operator-(const Vector3& Other) const 273 | { 274 | return Vector3(X - Other.X, Y - Other.Y, Z - Other.Z); 275 | } 276 | 277 | inline Vector3 operator-(float Bias) const 278 | { 279 | return Vector3(X - Bias, Y - Bias, Z - Bias); 280 | } 281 | 282 | inline Vector3 operator*(float Scalar) const 283 | { 284 | return Vector3(X * Scalar, Y * Scalar, Z * Scalar); 285 | } 286 | 287 | inline Vector3 operator*(const Vector3& Other) const 288 | { 289 | return Vector3(X * Other.X, Y * Other.Y, Z * Other.Z); 290 | } 291 | 292 | inline Vector3 operator*=(float Scalar) 293 | { 294 | X *= Scalar; 295 | Y *= Scalar; 296 | Z *= Scalar; 297 | return *this; 298 | } 299 | 300 | inline Vector3 operator*=(const Vector3& Other) 301 | { 302 | X *= Other.X; 303 | Y *= Other.Y; 304 | Z *= Other.Z; 305 | return *this; 306 | } 307 | 308 | inline Vector3 operator/(float Scalar) const 309 | { 310 | const float RScale = 1.f / Scalar; 311 | return Vector3(X * RScale, Y * RScale, Z * RScale); 312 | } 313 | 314 | inline Vector3 operator/(const Vector3& Other) const 315 | { 316 | return Vector3(X / Other.X, Y / Other.Y, Z / Other.Z); 317 | } 318 | //~ End Operator Overloads 319 | 320 | // Copy-Assignment Operator returns *this 321 | Vector3& operator=(const Vector3& Other) 322 | { 323 | X = Other.X; 324 | Y = Other.Y; 325 | Z = Other.Z; 326 | return *this; 327 | } 328 | }; 329 | 330 | template Vector2 const Vector2::ZeroVector = Vector2(0.0, 0.0); 331 | template Vector2 const Vector2::ForwardVector = Vector2(0.0, 1.0); 332 | template Vector2 const Vector2::BackwardVector = Vector2(0.0, -1.0); 333 | template Vector2 const Vector2::RightVector = Vector2(1.0, 0.0); 334 | template Vector2 const Vector2::LeftVector = Vector2(-1.0, 0.0); 335 | 336 | template Vector3 const Vector3::ZeroVector = Vector3(0.0, 0.0, 0.0); 337 | template Vector3 const Vector3::UpVector = Vector3(0.0, 0.0, 1.0); 338 | template Vector3 const Vector3::DownVector = Vector3(0.0, 0.0, -1.0); 339 | template Vector3 const Vector3::ForwardVector = Vector3(0.0, 1.0, 0.0); 340 | template Vector3 const Vector3::BackwardVector = Vector3(0.0, -1.0, 0.0); 341 | template Vector3 const Vector3::RightVector = Vector3(1.0, 0.0, 0.0); 342 | template Vector3 const Vector3::LeftVector = Vector3(-1.0, 0.0, 0.0); 343 | 344 | template 345 | inline Vector2 operator*(const Vector2& LHS, T Scalar) 346 | { 347 | return LHS.operator*(Scalar); 348 | } 349 | 350 | template 351 | inline Vector3 operator*(const Vector3& LHS, float Scalar) 352 | { 353 | return LHS.operator*(Scalar); 354 | } -------------------------------------------------------------------------------- /Source/GeometricTests/Math/Operations/MathOperations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "../LinearAlgebra/Vector.h" 20 | #include 21 | #include 22 | 23 | /* 24 | * MathOperations.h 25 | * 26 | * Non-member functions for vector math 27 | */ 28 | namespace MyMathLibrary 29 | { 30 | // Solves the dot product of two 3D vectors 31 | template 32 | inline T DotProduct(const Vector3& LHS, const Vector3& RHS, const int Size = 3) 33 | { 34 | T Result = 0.0; 35 | 36 | for (int i = 0; i < Size; ++i) 37 | Result += LHS[i] * RHS[i]; 38 | 39 | return Result; 40 | } 41 | 42 | // Solves the cross product of two 3D vectors 43 | template 44 | inline Vector3 CrossProduct(const Vector3& LHS, const Vector3& RHS) 45 | { 46 | return Vector3(LHS.Y*RHS.Z - LHS.Z*RHS.Y, 47 | LHS.Z*RHS.X - LHS.X*RHS.Z, 48 | LHS.X*RHS.Y - LHS.Y*RHS.X); 49 | } 50 | 51 | // Solves the normal of a 3D vector, a.k.a. unit vector 52 | template 53 | inline Vector3 Normalize(const Vector3& Vector) 54 | { 55 | Vector3 Result = Vector3::ZeroVector; 56 | 57 | // Find the Vector Magnitude 58 | T Magnitude = sqrt(pow(Vector.X, 2) + pow(Vector.Y, 2) + pow(Vector.Z, 2)); 59 | 60 | Result = Vector / Magnitude; 61 | 62 | return Result; 63 | } 64 | 65 | // 3D Vector Distance Formula 66 | template 67 | inline T Distance(const Vector3& LHS, const Vector3& RHS) 68 | { 69 | T DiffX = LHS.X - RHS.X; 70 | T DiffY = LHS.Y - RHS.Y; 71 | T DiffZ = LHS.Z - RHS.Z; 72 | return sqrt((pow(DiffX, 2) + pow(DiffY, 2) + pow(DiffZ, 2))); 73 | } 74 | 75 | // Solves the best-fit plane normal for a set of points 76 | template 77 | inline Vector3 BestFitNormal(const Vector3 Vector[], int N) 78 | { 79 | Vector3 Result = Vector3::ZeroVector; 80 | 81 | Vector3 *Previous = &Vector[N - 1]; 82 | 83 | for (int i = 0; i < N; ++i) 84 | { 85 | const Vector3 *Current = &Vector[i]; 86 | 87 | Result.X += (Previous->Z + Current->Z) * (Previous->Y - Current->Y); 88 | Result.Y += (Previous->X + Current->X) * (Previous->Z - Current->Z); 89 | Result.Z += (Previous->Y + Current->Y) * (Previous->X - Current->X); 90 | 91 | Previous = Current; 92 | } 93 | 94 | Normalize(Result); 95 | return Result; 96 | } 97 | 98 | // Center of gravity of a triangle 99 | template 100 | inline Vector3 CenterOfGravity(const Vector3& V1, const Vector3& V2, const Vector3& V3) 101 | { 102 | return ((V1 + V2 + V3) / 3); 103 | } 104 | 105 | // Incenter of a triangle 106 | template 107 | inline Vector3 InCenter( 108 | const Vector3& V1 109 | , const Vector3& V2 110 | , const Vector3& V3 111 | , const Vector3& L1 112 | , const Vector3& L2 113 | , const Vector3& L3) 114 | { 115 | Vector3 Perimeter = L1 + L2 + L3; 116 | Vector3 Numerator = (L1*V1) + (L2*V2) + (L3*V3); 117 | return (Numerator / Perimeter); 118 | } 119 | 120 | /* 121 | * TODO: Circumcenter of a triangle 122 | * 123 | * Solve for t: 124 | * 125 | * t = (c2 + c3)*v1 + (c3 + c1)*v2 + (c1 + c2)*v3 / 2*c 126 | * 127 | * Where: 128 | * 129 | * v1, v2, v3 = vertices of triangle 130 | * e1, e2, e3 = edge of triangle 131 | * d1 = -e2*e3 132 | * d2 = -e3*e1 133 | * d3 = -e1*e2 134 | * c1 = d2*d3 135 | * c2 = d3*d1 136 | * c3 = d1*d2 137 | * c = c1 + c2 + c3 138 | */ 139 | } 140 | 141 | -------------------------------------------------------------------------------- /Source/GeometricTests/Primitives/AABB.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "../Math/LinearAlgebra/Vector.h" 20 | 21 | /* 22 | * AABB.h 23 | * 24 | * Axis-Aligned Bounding Box 25 | * 26 | * Defined by the extreme points pMin and pMax: 27 | * 28 | * B = [pMin, pMax] 29 | */ 30 | template 31 | struct AABB 32 | { 33 | 34 | public: 35 | 36 | // Constructor: No Arguments 37 | inline explicit AABB() : 38 | Min(Vector3::ZeroVector) 39 | , Max(Vector3::ZeroVector) 40 | {} 41 | 42 | // Constructor: Passing Min and Max 43 | inline explicit AABB( 44 | const Vector3& _Min 45 | , const Vector3& _Max) : 46 | Min(_Min) 47 | , Max(_Max) 48 | {} 49 | 50 | // Destructor 51 | ~AABB() = default; 52 | 53 | // Copy Constructor 54 | AABB(AABB const&) = delete; 55 | 56 | // Copy-Assignment Operator 57 | AABB& operator=(const AABB&) = delete; 58 | 59 | // Move Constructor 60 | AABB(AABB&&) = delete; 61 | 62 | // Move-Assignment Operator 63 | AABB& operator=(AABB&&) = delete; 64 | 65 | inline void Clear() const 66 | { 67 | GetMin().X = GetMin().Y = GetMin().Z = FLT_MAX; 68 | GetMax().X = GetMax().Y = GetMax().Z = -FLT_MAX; 69 | } 70 | 71 | inline void Add(const Vector3& Point) 72 | { 73 | if (Point.X < GetMin().X) GetMin().X = (T)Point.X; 74 | if (Point.X > GetMax().X) GetMax().X = (T)Point.X; 75 | 76 | if (Point.Y < GetMin().X) GetMin().Y = (T)Point.Y; 77 | if (Point.Y > GetMax().X) GetMax().Y = (T)Point.Y; 78 | 79 | if (Point.Z < GetMin().X) GetMin().Z = (T)Point.Z; 80 | if (Point.Z > GetMax().X) GetMax().Z = (T)Point.Z; 81 | } 82 | 83 | inline constexpr Vector3 GetMin() const { return Min; } 84 | inline constexpr Vector3 GetMax() const { return Max; } 85 | 86 | inline void Set(const Vector3& _Min, const Vector3& _Max) 87 | { 88 | Min = _Min; 89 | Max = _Max; 90 | } 91 | 92 | private: 93 | 94 | //~ AABB Variables 95 | Vector3 Min; 96 | Vector3 Max; 97 | //~ End AABB Variables 98 | }; 99 | -------------------------------------------------------------------------------- /Source/GeometricTests/Primitives/Circle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "../Math/LinearAlgebra/Vector.h" 20 | 21 | /* 22 | * Circle.h 23 | * 24 | * Defined by a center and radius: 25 | * 26 | * (x - h)^2 + (y - k)^2 = r^2 27 | * 28 | * Where: 29 | * 30 | * (h, k) = center 31 | * r = radius 32 | */ 33 | template 34 | struct Circle 35 | { 36 | 37 | public: 38 | 39 | // Constructor: No Arguments 40 | inline explicit Circle() : 41 | Radius(0.f) 42 | , Center(Vector3::ZeroVector) 43 | {} 44 | 45 | // Constructor: Passing Radius and Center 46 | inline explicit Circle( 47 | float _Radius 48 | , Vector3 _Center = Vector3::ZeroVector) : 49 | Radius(_Radius) 50 | , Center(_Center) 51 | {} 52 | 53 | // Destructor 54 | ~Circle() = default; 55 | 56 | // Copy Constructor 57 | Circle(Circle const&) = delete; 58 | 59 | // Copy-Assignment Operator 60 | Circle& operator=(const Circle&) = delete; 61 | 62 | // Move Constructor 63 | Circle(Circle&&) = delete; 64 | 65 | // Move-Assignment Operator 66 | Circle& operator=(Circle&&) = delete; 67 | 68 | inline constexpr float GetRadius() const { return Radius; } 69 | inline constexpr Vector3 GetCenter() const { return Center; } 70 | 71 | inline void Set(const float _Radius, const Vector3& _Center) 72 | { 73 | Radius = _Radius; 74 | Center = _Center; 75 | } 76 | 77 | private: 78 | 79 | //~ Circle Variables 80 | float Radius; // r (4 bytes) 81 | Vector3 Center; // (h, k) 82 | //~ End Circle Variables 83 | 84 | }; 85 | -------------------------------------------------------------------------------- /Source/GeometricTests/Primitives/Plane.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "../Math/LinearAlgebra/Vector.h" 20 | #include "../Math/Operations/MathOperations.h" 21 | 22 | /* 23 | * Plane.h 24 | * 25 | * An infinite surface defined in 3D space by: 26 | * 27 | * Vector Notation: p * n = d 28 | * Scalar Notation: ax + by + cz + d = 0 29 | * 30 | * n = [a, b, c] 31 | */ 32 | template 33 | struct Plane 34 | { 35 | 36 | public: 37 | 38 | //~ Plane Variables 39 | Vector3 Normal; 40 | float D; // 4 bytes 41 | //~ End Plane Variables 42 | 43 | // Constructor: Using 3 vector points 44 | inline explicit Plane(const T& _A, const T& _B, const T& _C, const T& _D) 45 | { 46 | Normal.X = (T)_A; 47 | Normal.Y = (T)_B; 48 | Normal.Z = (T)_C; 49 | D = (T)_D; 50 | } 51 | 52 | // Constructor: Using a vector point with a vector normal 53 | inline explicit Plane(const Vector3& _Normal, const Vector3& _Point) 54 | { 55 | Normal = _Normal; 56 | D = -MyMathLibrary::DotProduct(_Normal, _Point); 57 | } 58 | 59 | // Destructor 60 | ~Plane() = default; 61 | 62 | // Copy Constructor 63 | Plane(Plane const&) = delete; 64 | 65 | // Copy-Assignment Operator 66 | Plane& operator=(const Plane&) = delete; 67 | 68 | // Move Constructor 69 | Plane(Plane&&) = delete; 70 | 71 | // Move-Assignment Operator 72 | Plane& operator=(Plane&&) = delete; 73 | }; -------------------------------------------------------------------------------- /Source/GeometricTests/Primitives/Ray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "../Math/LinearAlgebra/Vector.h" 20 | 21 | /* 22 | * Ray.h 23 | * 24 | * A ray is a directed line segment defined by: 25 | * 26 | * p(t) = p0 + t*d 27 | * 28 | * Where: 29 | * 30 | * p0 = ray origin vector 31 | * d = delta vector, which contains length and direction 32 | * 33 | * t is restricted to normalized range [0, 1] 34 | */ 35 | template 36 | struct Ray 37 | { 38 | 39 | public: 40 | 41 | // Constructor: No Arguments 42 | inline explicit Ray() : 43 | Origin(Vector3::ZeroVector) 44 | , Delta(Vector3::ZeroVector) 45 | {} 46 | 47 | // Constructor: Passing Origin and Delta 48 | inline explicit Ray( 49 | const Vector3& _Origin 50 | , const Vector3& _Delta) : 51 | Origin(_Origin) 52 | , Delta(_Delta) 53 | {} 54 | 55 | // Destructor 56 | ~Ray() = default; 57 | 58 | // Copy Constructor 59 | Ray(Ray const&) = delete; 60 | 61 | // Copy-Assignment Operator 62 | Ray& operator=(const Ray&) = delete; 63 | 64 | // Move Constructor 65 | Ray(Ray&&) = delete; 66 | 67 | // Move-Assignment Operator 68 | Ray& operator=(Ray&&) = delete; 69 | 70 | inline constexpr Vector3 GetOrigin() const { return Origin; } 71 | inline constexpr Vector3 GetDelta() const { return Delta; } 72 | 73 | inline void Set(const Vector3& _Origin, const Vector3& _Delta) 74 | { 75 | Origin = _Origin; 76 | Delta = _Delta; 77 | } 78 | 79 | private: 80 | 81 | //~ Ray Variables 82 | Vector3 Origin; // p0 83 | Vector3 Delta; // d 84 | //~ End Ray Variables 85 | }; 86 | -------------------------------------------------------------------------------- /Source/GeometricTests/Primitives/Triangle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "../Math/LinearAlgebra/Vector.h" 20 | 21 | /* 22 | * Triangle.h 23 | * 24 | * Defined by vertices A, B, and C: 25 | * 26 | * Triangle(T) = [A, B, C] 27 | * 28 | * Area of Triangle = b*h / 2 29 | */ 30 | template 31 | struct Triangle 32 | { 33 | 34 | public: 35 | 36 | // Constructor: Passing A, B, C 37 | inline explicit Triangle( 38 | const Vector3& _VertexA 39 | , const Vector3& _VertexB 40 | , const Vector3& _VertexC) : 41 | VertexPosition[0](_VertexA) 42 | , VertexPosition[1](_VertexB) 43 | , VertexPosition[2](_VertexC) 44 | {} 45 | 46 | // Destructor 47 | ~Triangle() = default; 48 | 49 | // Copy Constructor 50 | Triangle(Triangle const&) = delete; 51 | 52 | // Copy-Assignment Operator 53 | Triangle& operator=(const Triangle&) = delete; 54 | 55 | // Move Constructor 56 | Triangle(Triangle&&) = delete; 57 | 58 | // Move-Assignment Operator 59 | Triangle& operator=(Triangle&&) = delete; 60 | 61 | inline constexpr Vector3 GetVertexA() const { return VertexPosition[0]; } 62 | inline constexpr Vector3 GetVertexB() const { return VertexPosition[1]; } 63 | inline constexpr Vector3 GetVertexC() const { return VertexPosition[2]; } 64 | 65 | private: 66 | 67 | //~ Triangle Variables 68 | Vector3 VertexPosition[3]; 69 | //~ End Triangle Variables 70 | }; 71 | -------------------------------------------------------------------------------- /Source/GeometricTestsEditor.Target.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Robert Slattery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | using UnrealBuildTool; 18 | using System.Collections.Generic; 19 | 20 | public class GeometricTestsEditorTarget : TargetRules 21 | { 22 | public GeometricTestsEditorTarget(TargetInfo Target) : base(Target) 23 | { 24 | Type = TargetType.Editor; 25 | 26 | ExtraModuleNames.AddRange( new string[] { "GeometricTests" } ); 27 | } 28 | } 29 | --------------------------------------------------------------------------------