1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package r2
16
17 import (
18 "fmt"
19 "math"
20
21 "github.com/golang/geo/r1"
22 )
23
24
25 type Point struct {
26 X, Y float64
27 }
28
29
30 func (p Point) Add(op Point) Point { return Point{p.X + op.X, p.Y + op.Y} }
31
32
33 func (p Point) Sub(op Point) Point { return Point{p.X - op.X, p.Y - op.Y} }
34
35
36 func (p Point) Mul(m float64) Point { return Point{m * p.X, m * p.Y} }
37
38
39 func (p Point) Ortho() Point { return Point{-p.Y, p.X} }
40
41
42 func (p Point) Dot(op Point) float64 { return p.X*op.X + p.Y*op.Y }
43
44
45 func (p Point) Cross(op Point) float64 { return p.X*op.Y - p.Y*op.X }
46
47
48 func (p Point) Norm() float64 { return math.Hypot(p.X, p.Y) }
49
50
51 func (p Point) Normalize() Point {
52 if p.X == 0 && p.Y == 0 {
53 return p
54 }
55 return p.Mul(1 / p.Norm())
56 }
57
58 func (p Point) String() string { return fmt.Sprintf("(%.12f, %.12f)", p.X, p.Y) }
59
60
61 type Rect struct {
62 X, Y r1.Interval
63 }
64
65
66 func RectFromPoints(pts ...Point) Rect {
67
68
69
70
71
72 if len(pts) == 0 {
73 return Rect{}
74 }
75
76 r := Rect{
77 X: r1.Interval{Lo: pts[0].X, Hi: pts[0].X},
78 Y: r1.Interval{Lo: pts[0].Y, Hi: pts[0].Y},
79 }
80
81 for _, p := range pts[1:] {
82 r = r.AddPoint(p)
83 }
84 return r
85 }
86
87
88
89 func RectFromCenterSize(center, size Point) Rect {
90 return Rect{
91 r1.Interval{Lo: center.X - size.X/2, Hi: center.X + size.X/2},
92 r1.Interval{Lo: center.Y - size.Y/2, Hi: center.Y + size.Y/2},
93 }
94 }
95
96
97
98
99 func EmptyRect() Rect {
100 return Rect{r1.EmptyInterval(), r1.EmptyInterval()}
101 }
102
103
104
105 func (r Rect) IsValid() bool {
106 return r.X.IsEmpty() == r.Y.IsEmpty()
107 }
108
109
110 func (r Rect) IsEmpty() bool {
111 return r.X.IsEmpty()
112 }
113
114
115
116 func (r Rect) Vertices() [4]Point {
117 return [4]Point{
118 {r.X.Lo, r.Y.Lo},
119 {r.X.Hi, r.Y.Lo},
120 {r.X.Hi, r.Y.Hi},
121 {r.X.Lo, r.Y.Hi},
122 }
123 }
124
125
126
127 func (r Rect) VertexIJ(i, j int) Point {
128 x := r.X.Lo
129 if i == 1 {
130 x = r.X.Hi
131 }
132 y := r.Y.Lo
133 if j == 1 {
134 y = r.Y.Hi
135 }
136 return Point{x, y}
137 }
138
139
140 func (r Rect) Lo() Point {
141 return Point{r.X.Lo, r.Y.Lo}
142 }
143
144
145 func (r Rect) Hi() Point {
146 return Point{r.X.Hi, r.Y.Hi}
147 }
148
149
150 func (r Rect) Center() Point {
151 return Point{r.X.Center(), r.Y.Center()}
152 }
153
154
155
156 func (r Rect) Size() Point {
157 return Point{r.X.Length(), r.Y.Length()}
158 }
159
160
161
162 func (r Rect) ContainsPoint(p Point) bool {
163 return r.X.Contains(p.X) && r.Y.Contains(p.Y)
164 }
165
166
167
168 func (r Rect) InteriorContainsPoint(p Point) bool {
169 return r.X.InteriorContains(p.X) && r.Y.InteriorContains(p.Y)
170 }
171
172
173 func (r Rect) Contains(other Rect) bool {
174 return r.X.ContainsInterval(other.X) && r.Y.ContainsInterval(other.Y)
175 }
176
177
178
179 func (r Rect) InteriorContains(other Rect) bool {
180 return r.X.InteriorContainsInterval(other.X) && r.Y.InteriorContainsInterval(other.Y)
181 }
182
183
184 func (r Rect) Intersects(other Rect) bool {
185 return r.X.Intersects(other.X) && r.Y.Intersects(other.Y)
186 }
187
188
189
190 func (r Rect) InteriorIntersects(other Rect) bool {
191 return r.X.InteriorIntersects(other.X) && r.Y.InteriorIntersects(other.Y)
192 }
193
194
195
196 func (r Rect) AddPoint(p Point) Rect {
197 return Rect{r.X.AddPoint(p.X), r.Y.AddPoint(p.Y)}
198 }
199
200
201
202
203 func (r Rect) AddRect(other Rect) Rect {
204 return Rect{r.X.Union(other.X), r.Y.Union(other.Y)}
205 }
206
207
208
209 func (r Rect) ClampPoint(p Point) Point {
210 return Point{r.X.ClampPoint(p.X), r.Y.ClampPoint(p.Y)}
211 }
212
213
214
215
216
217 func (r Rect) Expanded(margin Point) Rect {
218 xx := r.X.Expanded(margin.X)
219 yy := r.Y.Expanded(margin.Y)
220 if xx.IsEmpty() || yy.IsEmpty() {
221 return EmptyRect()
222 }
223 return Rect{xx, yy}
224 }
225
226
227 func (r Rect) ExpandedByMargin(margin float64) Rect {
228 return r.Expanded(Point{margin, margin})
229 }
230
231
232
233 func (r Rect) Union(other Rect) Rect {
234 return Rect{r.X.Union(other.X), r.Y.Union(other.Y)}
235 }
236
237
238
239 func (r Rect) Intersection(other Rect) Rect {
240 xx := r.X.Intersection(other.X)
241 yy := r.Y.Intersection(other.Y)
242 if xx.IsEmpty() || yy.IsEmpty() {
243 return EmptyRect()
244 }
245
246 return Rect{xx, yy}
247 }
248
249
250
251 func (r Rect) ApproxEqual(r2 Rect) bool {
252 return r.X.ApproxEqual(r2.X) && r.Y.ApproxEqual(r2.Y)
253 }
254
255 func (r Rect) String() string { return fmt.Sprintf("[Lo%s, Hi%s]", r.Lo(), r.Hi()) }
256
View as plain text