1 /* 2 Copyright (c) 2011-2021 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 /** 30 * Copyright: Timur Gafarov 2011-2021. 31 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0). 32 * Authors: Timur Gafarov 33 */ 34 module dlib.geometry.aabb; 35 36 import std.math; 37 import std.algorithm; 38 import dlib.math.vector; 39 import dlib.geometry.sphere; 40 41 /// Axis-aligned bounding box 42 struct AABB 43 { 44 Vector3f center; 45 Vector3f size; 46 Vector3f pmin, pmax; 47 48 this(Vector3f newPosition, Vector3f newSize) 49 { 50 center = newPosition; 51 size = newSize; 52 53 pmin = center - size; 54 pmax = center + size; 55 } 56 57 @property float topHeight() 58 { 59 return (center.y + size.y); 60 } 61 62 @property float bottomHeight() 63 { 64 return (center.y - size.y); 65 } 66 67 Vector3f closestPoint(Vector3f point) 68 { 69 Vector3f closest; 70 closest.x = (point.x < pmin.x)? pmin.x : ((point.x > pmax.x)? pmax.x : point.x); 71 closest.y = (point.y < pmin.y)? pmin.y : ((point.y > pmax.y)? pmax.y : point.y); 72 closest.z = (point.z < pmin.z)? pmin.z : ((point.z > pmax.z)? pmax.z : point.z); 73 return closest; 74 } 75 76 bool containsPoint(Vector3f point) 77 { 78 return !(point.x < pmin.x || point.x > pmax.x || 79 point.y < pmin.y || point.y > pmax.y || 80 point.z < pmin.z || point.z > pmax.z); 81 } 82 83 // TODO: move the following into 84 // separate intersection module 85 86 bool intersectsAABB(AABB b) 87 { 88 Vector3f t = b.center - center; 89 return fabs(t.x) <= (size.x + b.size.x) && 90 fabs(t.y) <= (size.y + b.size.y) && 91 fabs(t.z) <= (size.z + b.size.z); 92 } 93 94 bool intersectsSphere( 95 Sphere sphere, 96 out Vector3f collisionNormal, 97 out float penetrationDepth) 98 { 99 penetrationDepth = 0.0f; 100 collisionNormal = Vector3f(0.0f, 0.0f, 0.0f); 101 102 if (containsPoint(sphere.center)) 103 return true; 104 105 Vector3f xClosest = closestPoint(sphere.center); 106 Vector3f xDiff = sphere.center - xClosest; 107 108 float fDistSquared = xDiff.lengthsqr(); 109 if (fDistSquared > sphere.radius * sphere.radius) 110 return false; 111 112 float fDist = sqrt(fDistSquared); 113 penetrationDepth = sphere.radius - fDist; 114 collisionNormal = xDiff / fDist; 115 collisionNormal.normalize(); 116 return true; 117 } 118 119 private bool intersectsRaySlab( 120 float slabmin, 121 float slabmax, 122 float raystart, 123 float rayend, 124 ref float tbenter, 125 ref float tbexit) 126 { 127 float raydir = rayend - raystart; 128 129 if (fabs(raydir) < 1.0e-9f) 130 { 131 if (raystart < slabmin || raystart > slabmax) 132 return false; 133 else 134 return true; 135 } 136 137 float tsenter = (slabmin - raystart) / raydir; 138 float tsexit = (slabmax - raystart) / raydir; 139 140 if (tsenter > tsexit) 141 { 142 swap(tsenter, tsexit); 143 } 144 145 if (tbenter > tsexit || tsenter > tbexit) 146 { 147 return false; 148 } 149 else 150 { 151 tbenter = max(tbenter, tsenter); 152 tbexit = min(tbexit, tsexit); 153 return true; 154 } 155 } 156 157 bool intersectsSegment( 158 Vector3f segStart, 159 Vector3f segEnd, 160 ref float intersectionTime) 161 { 162 float tenter = 0.0f, texit = 1.0f; 163 164 if (!intersectsRaySlab(pmin.x, pmax.x, segStart.x, segEnd.x, tenter, texit)) 165 return false; 166 167 if (!intersectsRaySlab(pmin.y, pmax.y, segStart.y, segEnd.y, tenter, texit)) 168 return false; 169 170 if (!intersectsRaySlab(pmin.z, pmax.z, segStart.z, segEnd.z, tenter, texit)) 171 return false; 172 173 intersectionTime = tenter; 174 175 return true; 176 } 177 } 178 179 /// Creates AABB from minimum and maximum points 180 AABB boxFromMinMaxPoints(Vector3f mi, Vector3f ma) 181 { 182 AABB box; 183 box.pmin = mi; 184 box.pmax = ma; 185 box.center = (box.pmax + box.pmin) * 0.5f; 186 box.size = box.pmax - box.center; 187 box.size.x = abs(box.size.x); 188 box.size.y = abs(box.size.y); 189 box.size.z = abs(box.size.z); 190 return box; 191 }