-
Notifications
You must be signed in to change notification settings - Fork 2
/
rectangle.go
170 lines (137 loc) · 4.56 KB
/
rectangle.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
package cirno
import "fmt"
// Rectangle represents an oriented euclidian rectangle.
type Rectangle struct {
center Vector
extents Vector
xAxis Vector
yAxis Vector
angle float64
tag
data
domain
}
// TypeName returns the name of the shape type.
func (r *Rectangle) TypeName() string {
return "Rectangle"
}
// Center returns the coordinates of the center of the rectangle.
func (r *Rectangle) Center() Vector {
return r.center
}
// Move moves the rectangle in the specified direction; returns its new position.
func (r *Rectangle) Move(direction Vector) Vector {
r.center = r.center.Add(direction)
return r.center
}
// SetPosition sets the position of the rectangle to the given coordinates.
func (r *Rectangle) SetPosition(pos Vector) Vector {
r.center = pos
return r.center
}
// SetAngle sets the angle of the rectangle to the
// given value (in degrees).
func (r *Rectangle) SetAngle(angle float64) float64 {
return r.Rotate(angle - r.angle)
}
// SetAngleRadians sets the angle of the rectangle to the
// given value (in radians).
func (r *Rectangle) SetAngleRadians(angle float64) float64 {
return r.RotateRadians(angle - r.angle)
}
// ContainsPoint detects if the given point is inside the rectangle.
func (r *Rectangle) ContainsPoint(point Vector) bool {
localPoint := point.Subtract(r.center)
theta := -r.angle
localPoint = localPoint.Rotate(theta)
localRect := &aabb{
min: NewVector(-r.extents.X, -r.extents.Y),
max: NewVector(r.extents.X, r.extents.Y),
}
return localRect.containsPoint(localPoint)
}
// Width returns the width of the rectangle.
func (r *Rectangle) Width() float64 {
return r.extents.X * 2
}
// Height returns the height of the rectangle.
func (r *Rectangle) Height() float64 {
return r.extents.Y * 2
}
// Angle returns the angle of the rectangle (in degrees).
func (r *Rectangle) Angle() float64 {
return r.angle
}
// AngleRadians returns the angle of the rectangle (in radians).
func (r *Rectangle) AngleRadians() float64 {
return r.angle * DegToRad
}
// Rotate rotates the whole rectangle at the specified angle (in degrees).
//
// Returns the new angle of the rectangle (in degrees).
func (r *Rectangle) Rotate(angle float64) float64 {
r.xAxis = r.xAxis.Rotate(angle)
r.yAxis = r.yAxis.Rotate(angle)
r.angle += angle
r.angle = AdjustAngle(r.angle)
return r.angle
}
// RotateRadians rotates the whole rectangle at the specified angle (in radians).
//
// Returns the new angle of the rectangle (in radians).
func (r *Rectangle) RotateRadians(angle float64) float64 {
return r.Rotate(angle*RadToDeg) * DegToRad
}
// RotateAround rotates the rectangle around the specified base point.
func (r *Rectangle) RotateAround(angle float64, base Vector) Vector {
r.center = r.center.RotateAround(angle, base)
return r.center
}
// RotateAroundRadians rotates the rectangle around the specified base point
// at the angle in radians.
func (r *Rectangle) RotateAroundRadians(angle float64, base Vector) Vector {
r.center = r.center.RotateAroundRadians(angle, base)
return r.center
}
// Max returns the upper right point of the rectangle with no rotation.
func (r *Rectangle) Max() Vector {
return r.center.Add(r.xAxis.MultiplyByScalar(r.extents.X).
Add(r.yAxis.MultiplyByScalar(r.extents.Y)))
}
// Min returns the lower left point of the rectangle with no rotation.
func (r *Rectangle) Min() Vector {
return r.center.Subtract(r.xAxis.MultiplyByScalar(r.extents.X).
Add(r.yAxis.MultiplyByScalar(r.extents.Y)))
}
// Vertices returns the array of the rectangle vertices.
func (r *Rectangle) Vertices() [4]Vector {
// Rectangle vertices.
a := r.center.Add(r.xAxis.MultiplyByScalar(-r.extents.X).
Add(r.yAxis.MultiplyByScalar(-r.extents.Y)))
b := r.center.Add(r.xAxis.MultiplyByScalar(-r.extents.X).
Add(r.yAxis.MultiplyByScalar(r.extents.Y)))
c := r.center.Add(r.xAxis.MultiplyByScalar(r.extents.X).
Add(r.yAxis.MultiplyByScalar(r.extents.Y)))
d := r.center.Add(r.xAxis.MultiplyByScalar(r.extents.X).
Add(r.yAxis.MultiplyByScalar(-r.extents.Y)))
return [4]Vector{a, b, c, d}
}
// NewRectangle returns a new rectangle with specified parameters.
func NewRectangle(position Vector, width, height, angle float64) (*Rectangle, error) {
if width <= 0.0 {
return nil, fmt.Errorf(
"the length of the rectangle must be positive")
}
if height <= 0.0 {
return nil, fmt.Errorf(
"the height of the rectangle must be positive")
}
rect := &Rectangle{}
rect.center = position
rect.extents = NewVector(width/2.0, height/2.0)
rect.xAxis = NewVector(1, 0)
rect.yAxis = NewVector(0, 1)
rect.Rotate(angle)
rect.treeNodes = []*quadTreeNode{}
return rect, nil
}