1 /** 2 inmath.plane 3 4 Authors: David Herberth, Inochi2D Project 5 License: MIT 6 */ 7 module inmath.plane; 8 9 private { 10 import inmath.linalg : Vector, dot, vec3; 11 import inmath.math : almostEqual; 12 13 import std.traits : isFloatingPoint; 14 } 15 16 17 /// Base template for all plane-types. 18 /// Params: 19 /// type = all values get stored as this type (must be floating point) 20 struct PlaneT(type = float) if(isFloatingPoint!type) { 21 alias pt = type; /// Holds the internal type of the plane. 22 alias vec3 = Vector!(pt, 3); /// Convenience alias to the corresponding vector type. 23 24 union { 25 struct { 26 pt a; /// normal.x 27 pt b; /// normal.y 28 pt c; /// normal.z 29 } 30 31 vec3 normal; /// Holds the planes normal. 32 } 33 34 pt d; /// Holds the planes "constant" (HNF). 35 36 /// Gets a hash of this item 37 size_t toHash() const { return typeid(this).getHash(&this); } 38 39 @safe pure nothrow: 40 41 /// Constructs the plane, from either four scalars of type $(I pt) 42 /// or from a 3-dimensional vector (= normal) and a scalar. 43 this(pt a, pt b, pt c, pt d) { 44 this.a = a; 45 this.b = b; 46 this.c = c; 47 this.d = d; 48 } 49 50 /// ditto 51 this(vec3 normal, pt d) { 52 this.normal = normal; 53 this.d = d; 54 } 55 56 unittest { 57 Plane p = Plane(0.0f, 1.0f, 2.0f, 3.0f); 58 assert(p.normal == vec3(0.0f, 1.0f, 2.0f)); 59 assert(p.d == 3.0f); 60 61 p.normal.x = 4.0f; 62 assert(p.normal == vec3(4.0f, 1.0f, 2.0f)); 63 assert(p.a == 4.0f); 64 assert(p.b == 1.0f); 65 assert(p.c == 2.0f); 66 assert(p.d == 3.0f); 67 } 68 69 /// Normalizes the plane inplace. 70 void normalize() { 71 pt det = 1.0 / normal.length; 72 normal *= det; 73 d *= det; 74 } 75 76 /// Returns a normalized copy of the plane. 77 @property PlaneT normalized() const { 78 PlaneT ret = PlaneT(a, b, c, d); 79 ret.normalize(); 80 return ret; 81 } 82 83 unittest { 84 Plane p = Plane(0.0f, 1.0f, 2.0f, 3.0f); 85 Plane pn = p.normalized(); 86 assert(pn.normal == vec3(0.0f, 1.0f, 2.0f).normalized); 87 assert(almostEqual(pn.d, 3.0f/vec3(0.0f, 1.0f, 2.0f).length)); 88 p.normalize(); 89 assert(p == pn); 90 } 91 92 /// Returns the distance from a point to the plane. 93 /// Note: the plane $(RED must) be normalized, the result can be negative. 94 pt distance(vec3 point) const { 95 return dot(point, normal) + d; 96 } 97 98 /// Returns the distance from a point to the plane. 99 /// Note: the plane does not have to be normalized, the result can be negative. 100 pt ndistance(vec3 point) const { 101 return (dot(point, normal) + d) / normal.length; 102 } 103 104 unittest { 105 Plane p = Plane(-1.0f, 4.0f, 19.0f, -10.0f); 106 assert(almostEqual(p.ndistance(vec3(5.0f, -2.0f, 0.0f)), -1.182992)); 107 assert(almostEqual(p.ndistance(vec3(5.0f, -2.0f, 0.0f)), 108 p.normalized.distance(vec3(5.0f, -2.0f, 0.0f)))); 109 } 110 111 bool opEquals(PlaneT other) const { 112 return other.normal == normal && other.d == d; 113 } 114 115 } 116 117 alias Plane = PlaneT!(float);