-
Notifications
You must be signed in to change notification settings - Fork 4
/
point3d.go
78 lines (69 loc) · 1.69 KB
/
point3d.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
package primitive
import "math"
type Point3D struct{ X, Y, Z float32 }
type P3Ds []Point3D
func (c *Point3D) Scale(f float32) {
c.X *= f
c.Y *= f
c.Z *= f
}
func (p P3Ds) Scale(f float32) {
for i := range p {
p[i].Scale(f)
}
}
// rotateFn returns a function that rotates around (0,0,0).
// Supply angles in radians.
// dst must be same size or bigger than p.
func (p P3Ds) RotateTo(dst P3Ds, xAn, yAn, zAn float64) {
fn := rotateFn(xAn, yAn, zAn)
for i, v := range p {
dst[i] = fn(v)
}
}
// BehindCamera is magic
const BehindCamera = 10e21
// rotateFn returns a function that rotates around (0,0,0).
// dst must be same size or bigger than p.
func (p P3Ds) ProjectTo(dst []Point2D, w, h, zoff float32) {
halfWidth := w * 0.5
halfHeight := h * 0.5
for i, v := range p {
z := v.Z + zoff
if z <= 0 {
dst[i] = Point2D{X: BehindCamera, Y: BehindCamera}
continue
}
invZ := 1 / z
x := halfWidth * v.X * invZ
y := halfWidth * v.Y * invZ
x += halfWidth
y += halfHeight
dst[i] = Point2D{X: x, Y: y}
}
}
// rotateFn returns a function that rotates around (0,0,0).
// Supply angles in radians.
func rotateFn(xAn, yAn, zAn float64) func(c Point3D) Point3D {
var (
s1 = float32(math.Sin(zAn))
s2 = float32(math.Sin(xAn))
s3 = float32(math.Sin(yAn))
c1 = float32(math.Cos(zAn))
c2 = float32(math.Cos(xAn))
c3 = float32(math.Cos(yAn))
zero = c1*c3 + s1*s2*s3
one = c2 * s3
two = -c3*s1 + c1*s2*s3
three = c2 * s1
four = -s2
five = c2 * c1
six = -c1*s3 + c3*s1*s2
seven = c2 * c3
eight = s1*s3 + c1*c3*s2
)
return func(c Point3D) Point3D {
c.X, c.Y, c.Z = c.X*zero+c.Y*one+c.Z*two, c.X*three+c.Y*four+c.Z*five, c.X*six+c.Y*seven+c.Z*eight
return c
}
}