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);