1 /** 2 Plane in hessian form. 3 4 Copyright: 5 Copyright (c) 2007 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017 Godot-D contributors 8 Copyright (c) 2022 Godot-DLang contributors 9 10 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 11 12 13 */ 14 module godot.plane; 15 16 import godot.api.types; 17 import godot.vector3; 18 19 import std.math; 20 21 public import godot.globalenums : ClockDirection; 22 23 /** 24 Plane represents a normalized plane equation. Basically, “normal” is the normal of the plane (a,b,c normalized), and “d” is the distance from the origin to the plane (in the direction of “normal”). “Over” or “Above” the plane is considered the side of the plane towards where the normal is pointing. 25 */ 26 struct Plane { 27 @nogc nothrow: 28 29 Vector3 normal = Vector3(0, 0, 0); 30 real_t d = 0; 31 32 Vector3 center() const { 33 return normal * d; 34 } 35 36 Plane opUnary(string op : "-")() const { 37 return Plane(-normal, -d); 38 } 39 40 Vector3 project(in Vector3 p_point) const { 41 return p_point - normal * distanceTo(p_point); 42 } 43 44 void normalize() { 45 real_t l = normal.length(); 46 if (l == 0) { 47 this = Plane(Vector3(0, 0, 0), 0); 48 return; 49 } 50 normal /= l; 51 d /= l; 52 } 53 54 Plane normalized() const { 55 Plane p = this; 56 p.normalize(); 57 return p; 58 } 59 60 Vector3 getAnyPoint() const { 61 return normal * d; 62 } 63 64 Vector3 getAnyPerpendicularNormal() const { 65 enum Vector3 p1 = Vector3(1, 0, 0); 66 enum Vector3 p2 = Vector3(0, 1, 0); 67 Vector3 p; 68 69 if (fabs(normal.dot(p1)) > 0.99) // if too similar to p1 70 p = p2; // use p2 71 else 72 p = p1; // use p1 73 74 p -= normal * normal.dot(p); 75 p.normalize(); 76 77 return p; 78 } 79 80 /* intersections */ 81 82 bool intersect3(in Plane p_plane1, in Plane p_plane2, Vector3* r_result = null) const { 83 const Plane p_plane0 = this; 84 Vector3 normal0 = p_plane0.normal; 85 Vector3 normal1 = p_plane1.normal; 86 Vector3 normal2 = p_plane2.normal; 87 88 real_t denom = normal0.cross(normal1).dot(normal2); 89 90 if (fabs(denom) <= CMP_EPSILON) 91 return false; 92 93 if (r_result) { 94 *r_result = ((normal1.cross(normal2) * p_plane0.d) + 95 ( 96 normal2.cross(normal0) * p_plane1.d) + 97 (normal0.cross(normal1) * p_plane2.d)) / denom; 98 } 99 return true; 100 } 101 102 bool intersectsRay(in Vector3 p_from, in Vector3 p_dir, Vector3* p_intersection = null) const { 103 Vector3 segment = p_dir; 104 real_t den = normal.dot(segment); 105 106 //printf("den is %i\n",den); 107 if (fabs(den) <= CMP_EPSILON) { 108 return false; 109 } 110 111 real_t dist = (normal.dot(p_from) - d) / den; 112 //printf("dist is %i\n",dist); 113 114 if (dist > CMP_EPSILON) { //this is a ray, before the emiting pos (p_from) doesnt exist 115 return false; 116 } 117 118 dist = -dist; 119 if (p_intersection) 120 *p_intersection = p_from + segment * dist; 121 122 return true; 123 } 124 125 bool intersectsSegment(in Vector3 p_begin, in Vector3 p_end, Vector3* p_intersection) const { 126 Vector3 segment = p_begin - p_end; 127 real_t den = normal.dot(segment); 128 129 //printf("den is %i\n",den); 130 if (fabs(den) <= CMP_EPSILON) 131 return false; 132 133 real_t dist = (normal.dot(p_begin) - d) / den; 134 //printf("dist is %i\n",dist); 135 136 if (dist < -CMP_EPSILON || dist > (1.0 + CMP_EPSILON)) 137 return false; 138 139 dist = -dist; 140 if (p_intersection) 141 *p_intersection = p_begin + segment * dist; 142 143 return true; 144 } 145 146 /* misc */ 147 148 bool isAlmostLike(in Plane p_plane) const { 149 return (normal.dot(p_plane.normal) > _PLANE_EQ_DOT_EPSILON && fabs(d - p_plane.d) < _PLANE_EQ_D_EPSILON); 150 } 151 152 /+String opCast(T : String)() const 153 { 154 // return normal.operator String() + ", " + rtos(d); 155 return String(); // @Todo 156 }+/ 157 158 bool isPointOver(in Vector3 p_point) const { 159 return (normal.dot(p_point) > d); 160 } 161 162 real_t distanceTo(in Vector3 p_point) const { 163 return (normal.dot(p_point) - d); 164 } 165 166 bool hasPoint(in Vector3 p_point, real_t _epsilon = CMP_EPSILON) const { 167 real_t dist = normal.dot(p_point) - d; 168 dist = fabs(dist); 169 return (dist <= _epsilon); 170 171 } 172 173 this(in Vector3 p_normal, real_t p_d) { 174 normal = p_normal; 175 d = p_d; 176 } 177 178 this(real_t p_a, real_t p_b, real_t p_c, real_t p_d) { 179 normal = Vector3(p_a, p_b, p_c); 180 d = p_d; 181 } 182 183 this(in Vector3 p_point, in Vector3 p_normal) { 184 normal = p_normal; 185 d = p_normal.dot(p_point); 186 } 187 188 this(in Vector3 p_point1, in Vector3 p_point2, in Vector3 p_point3, ClockDirection p_dir = ClockDirection 189 .counterclockwise) { 190 if (p_dir == ClockDirection.clockwise) 191 normal = (p_point1 - p_point3).cross(p_point1 - p_point2); 192 else 193 normal = (p_point1 - p_point2).cross(p_point1 - p_point3); 194 normal.normalize(); 195 d = normal.dot(p_point1); 196 } 197 }