forked from g3n/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplane.go
176 lines (139 loc) · 4.91 KB
/
plane.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright 2016 The G3N Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package math32
// Plane represents a plane in 3D space by its normal vector and a constant.
// When the the normal vector is the unit vector the constant is the distance from the origin.
type Plane struct {
normal Vector3
constant float32
}
// NewPlane creates and returns a new plane from a normal vector and a constant.
func NewPlane(normal *Vector3, constant float32) *Plane {
p := new(Plane)
if normal != nil {
p.normal = *normal
}
p.constant = constant
return p
}
// Set sets this plane normal vector and constant.
// Returns pointer to this updated plane.
func (p *Plane) Set(normal *Vector3, constant float32) *Plane {
p.normal = *normal
p.constant = constant
return p
}
// SetComponents sets this plane normal vector components and constant.
// Returns pointer to this updated plane.
func (p *Plane) SetComponents(x, y, z, w float32) *Plane {
p.normal.Set(x, y, z)
p.constant = w
return p
}
// SetFromNormalAndCoplanarPoint sets this plane from a normal vector and a point on the plane.
// Returns pointer to this updated plane.
func (p *Plane) SetFromNormalAndCoplanarPoint(normal *Vector3, point *Vector3) *Plane {
p.normal = *normal
p.constant = -point.Dot(&p.normal)
return p
}
// SetFromCoplanarPoints sets this plane from three coplanar points.
// Returns pointer to this updated plane.
func (p *Plane) SetFromCoplanarPoints(a, b, c *Vector3) *Plane {
var v1 Vector3
var v2 Vector3
normal := v1.SubVectors(c, b).Cross(v2.SubVectors(a, b)).Normalize()
// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
p.SetFromNormalAndCoplanarPoint(normal, a)
return p
}
// Copy sets this plane to a copy of other.
// Returns pointer to this updated plane.
func (p *Plane) Copy(other *Plane) *Plane {
p.normal.Copy(&other.normal)
p.constant = other.constant
return p
}
// Normalize normalizes this plane normal vector and adjusts the constant.
// Note: will lead to a divide by zero if the plane is invalid.
// Returns pointer to this updated plane.
func (p *Plane) Normalize() *Plane {
inverseNormalLength := 1.0 / p.normal.Length()
p.normal.MultiplyScalar(inverseNormalLength)
p.constant *= inverseNormalLength
return p
}
// Negate negates this plane normal.
// Returns pointer to this updated plane.
func (p *Plane) Negate() *Plane {
p.constant *= -1
p.normal.Negate()
return p
}
// DistanceToPoint returns the distance of this plane from point.
func (p *Plane) DistanceToPoint(point *Vector3) float32 {
return p.normal.Dot(point) + p.constant
}
// DistanceToSphere returns the distance of this place from the sphere.
func (p *Plane) DistanceToSphere(sphere *Sphere) float32 {
return p.DistanceToPoint(&sphere.Center) - sphere.Radius
}
// IsIntersectionLine returns the line intersects this plane.
func (p *Plane) IsIntersectionLine(line *Line3) bool {
startSign := p.DistanceToPoint(&line.start)
endSign := p.DistanceToPoint(&line.end)
return (startSign < 0 && endSign > 0) || (endSign < 0 && startSign > 0)
}
// IntersectLine calculates the point in the plane which intersets the specified line.
// Sets the optionalTarget, if not nil to this point, and also returns it.
// Returns nil if the line does not intersects the plane.
func (p *Plane) IntersectLine(line *Line3, optionalTarget *Vector3) *Vector3 {
var v1 Vector3
var result *Vector3
if optionalTarget == nil {
result = NewVector3(0, 0, 0)
} else {
result = optionalTarget
}
direction := line.Delta(&v1)
denominator := p.normal.Dot(direction)
if denominator == 0 {
// line is coplanar, return origin
if p.DistanceToPoint(&line.start) == 0 {
return result.Copy(&line.start)
}
// Unsure if this is the correct method to handle this case.
return nil
}
var t = -(line.start.Dot(&p.normal) + p.constant) / denominator
if t < 0 || t > 1 {
return nil
}
return result.Copy(direction).MultiplyScalar(t).Add(&line.start)
}
// CoplanarPoint sets the optionalTarget to a point in the plane and also returns it.
// The point set and returned is the closest point from the origin.
func (p *Plane) CoplanarPoint(optionalTarget *Vector3) *Vector3 {
var result *Vector3
if optionalTarget == nil {
result = NewVector3(0, 0, 0)
} else {
result = optionalTarget
}
return result.Copy(&p.normal).MultiplyScalar(-p.constant)
}
// Translate translates this plane in the direction of its normal by offset.
// Returns pointer to this updated plane.
func (p *Plane) Translate(offset *Vector3) *Plane {
p.constant = p.constant - offset.Dot(&p.normal)
return p
}
// Equals returns if this plane is equal to other
func (p *Plane) Equals(other *Plane) bool {
return other.normal.Equals(&p.normal) && (other.constant == p.constant)
}
// Clone creates and returns a pointer to a copy of this plane.
func (p *Plane) Clone(plane *Plane) *Plane {
return NewPlane(&plane.normal, plane.constant)
}