github.com/sandwich-go/boost@v1.3.29/geom/internal/template2/geom_template.go (about) 1 package template2 2 3 const GeomTestTPL = `// Code generated by tools. DO NOT EDIT. 4 package geom 5 6 import ( 7 "fmt" 8 . "github.com/smartystreets/goconvey/convey" 9 "testing" 10 ) 11 12 {{- $camelCaseKey := .Key | CamelCase }} 13 {{- $pointName := print "Point" $camelCaseKey }} 14 func TestRectangle{{ $camelCaseKey }}_SnakeRange(t *testing.T) { 15 HelixRectRangeFromCenterAndMargin{{ $camelCaseKey }}(Pt{{ $camelCaseKey }}(2, 2), 2, func(p {{ $pointName }}) bool { 16 t.Log(p.X, p.Y) 17 return true 18 }) 19 20 Convey("test intersection with line", t, func() { 21 x := PtInt8(1, 0) 22 y := PtInt8(1, 4) 23 z := x.Add(y) 24 So(z.X, ShouldEqual, 2) 25 So(z.Y, ShouldEqual, 4) 26 So(z.String(), ShouldEqual, "(2,4)") 27 So(z.Sub(x).Eq(y), ShouldBeTrue) 28 q := y.Mul(3) 29 So(q.X, ShouldEqual, y.X*3) 30 So(q.Y, ShouldEqual, y.Y*3) 31 So(q.Div(3).Eq(y), ShouldBeTrue) 32 var r1, r2, r3, r4 int8 = 1, 0, 5, 5 33 r := RectInt8(r1, r2, r3, r4) 34 So(x.In(r), ShouldBeTrue) 35 So(r.String(), ShouldEqual, fmt.Sprintf("(%d,%d)-(%d,%d)", r1, r2, r3, r4)) 36 var minX, maxX, minY, maxY int8 37 var reset = func() {minX, maxX, minY, maxY = 5, 0, 5, 0} 38 var f = func(p PointInt8) bool { 39 if p.X {{ "<" | Unescaped }} minX { 40 minX = p.X 41 } 42 if p.Y {{ "<" | Unescaped }} minY { 43 minY = p.Y 44 } 45 if p.X > maxX { 46 maxX = p.X 47 } 48 if p.Y > maxY { 49 maxY = p.Y 50 } 51 return true 52 } 53 reset() 54 r.RangePoints(f) 55 So(minX, ShouldEqual, r1) 56 So(minY, ShouldEqual, r2) 57 So(maxX, ShouldEqual, r3) 58 So(maxY, ShouldEqual, r4) 59 reset() 60 r.RangePointsMinClosedMaxOpen(f) 61 So(minX, ShouldEqual, r1+1) 62 So(minY, ShouldEqual, r2+1) 63 So(maxX, ShouldEqual, r3) 64 So(maxY, ShouldEqual, r4) 65 reset() 66 r.RangePointsMinMaxClosed(f) 67 So(minX, ShouldEqual, r1+1) 68 So(minY, ShouldEqual, r2+1) 69 So(maxX, ShouldEqual, r3-1) 70 So(maxY, ShouldEqual, r4-1) 71 reset() 72 r.RangePointsMinOpenMaxClosed(f) 73 So(minX, ShouldEqual, r1) 74 So(minY, ShouldEqual, r2) 75 So(maxX, ShouldEqual, r3-1) 76 So(maxY, ShouldEqual, r4-1) 77 So(r.Dx(), ShouldEqual, r3-r1) 78 So(r.Dy(), ShouldEqual, r4-r2) 79 So(r.Size().Eq(PtInt8(r3-r1, r4-r2)), ShouldBeTrue) 80 rc := PtInt8(1,1) 81 rr := r.Add(rc) 82 So(rr.Max.X, ShouldEqual, r.Max.X+rc.X) 83 So(rr.Max.Y, ShouldEqual, r.Max.Y+rc.Y) 84 So(rr.Min.X, ShouldEqual, r.Min.X+rc.X) 85 So(rr.Min.Y, ShouldEqual, r.Min.Y+rc.Y) 86 So(rr.Sub(rc).Eq(r), ShouldBeTrue) 87 ir :=r.Inset(1) 88 So(ir.String(), ShouldEqual, fmt.Sprintf("(%d,%d)-(%d,%d)", r1+1, r2+1, r3-1, r4-1)) 89 So(r.Intersect(ir).Eq(ir), ShouldBeTrue) 90 So(r.Union(r.Inset(1)).Eq(r), ShouldBeTrue) 91 So(r.Empty(), ShouldBeFalse) 92 So(ZRInt8.Empty(), ShouldBeTrue) 93 So(r.Overlaps(ir), ShouldBeTrue) 94 So(r.Bounds().Eq(r), ShouldBeTrue) 95 So(ir.In(r), ShouldBeTrue) 96 So(ir.Expanded(rc).Eq(r), ShouldBeTrue) 97 So(ir.ExpandedByMargin(1).Eq(r), ShouldBeTrue) 98 99 rect := Rect{{ $camelCaseKey }}(0, 0, 3, 3) 100 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(1, 0), Pt{{ $camelCaseKey }}(1, 4)), ShouldBeTrue) // should be true 101 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(1, 0), Pt{{ $camelCaseKey }}(1, 3)), ShouldBeTrue) // should be true 102 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(1, 0), Pt{{ $camelCaseKey }}(1, 2)), ShouldBeTrue) // should be true 103 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(1, 0), Pt{{ $camelCaseKey }}(1, 1)), ShouldBeTrue) // should be true 104 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(2, 0), Pt{{ $camelCaseKey }}(2, 2)), ShouldBeTrue) // should be true 105 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 2), Pt{{ $camelCaseKey }}(1, 2)), ShouldBeTrue) // should be true 106 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 1), Pt{{ $camelCaseKey }}(3, 1)), ShouldBeTrue) // should be true 107 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 0), Pt{{ $camelCaseKey }}(0, 1)), ShouldBeFalse) // should be false 108 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 0), Pt{{ $camelCaseKey }}(0, 2)), ShouldBeFalse) // should be false 109 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 0), Pt{{ $camelCaseKey }}(0, 3)), ShouldBeFalse) // should be false 110 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 0), Pt{{ $camelCaseKey }}(0, 4)), ShouldBeFalse) // should be false 111 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 0), Pt{{ $camelCaseKey }}(1, 0)), ShouldBeFalse) // should be false 112 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 0), Pt{{ $camelCaseKey }}(2, 0)), ShouldBeFalse) // should be false 113 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(1, 4), Pt{{ $camelCaseKey }}(2, 4)), ShouldBeFalse) // should be false 114 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(0, 3), Pt{{ $camelCaseKey }}(3, 3)), ShouldBeFalse) // should be false 115 So(rect.IntersectionWithLine(Pt{{ $camelCaseKey }}(1, 3), Pt{{ $camelCaseKey }}(2, 4)), ShouldBeFalse) // should be false 116 }) 117 } 118 ` 119 120 const GeomTPL = `// Code generated by tools. DO NOT EDIT. 121 package geom 122 123 import "strconv" 124 125 {{- $camelCaseKey := .Key | CamelCase }} 126 {{- $pointName := print "Point" $camelCaseKey }} 127 {{- $rectangleName := print "Rectangle" $camelCaseKey }} 128 // {{ $pointName }} point wrapper 129 type {{ $pointName }} struct { 130 X, Y {{ .Key }} 131 } 132 133 // String returns a string representation of p like "(3,4)". 134 func (p {{ $pointName }}) String() string { 135 return "(" + strconv.FormatInt(int64(p.X), 10) + "," + strconv.FormatInt(int64(p.Y), 10) + ")" 136 } 137 138 // Add returns the vector p+q. 139 func (p {{ $pointName }}) Add(q {{ $pointName }}) {{ $pointName }} { 140 return {{ $pointName }}{p.X + q.X, p.Y + q.Y} 141 } 142 143 // Sub returns the vector p-q. 144 func (p {{ $pointName }}) Sub(q {{ $pointName }}) {{ $pointName }} { 145 return {{ $pointName }}{p.X - q.X, p.Y - q.Y} 146 } 147 148 // Mul returns the vector p*k. 149 func (p {{ $pointName }}) Mul(k {{ .Key }}) {{ $pointName }} { 150 return {{ $pointName }}{p.X * k, p.Y * k} 151 } 152 153 // Div returns the vector p/k. 154 func (p {{ $pointName }}) Div(k {{ .Key }}) {{ $pointName }} { 155 return {{ $pointName }}{p.X / k, p.Y / k} 156 } 157 158 // In reports whether p is in r. 159 func (p {{ $pointName }}) In(r {{ $rectangleName }}) bool { 160 return r.Min.X {{ "<=" | Unescaped }} p.X && p.X {{ "<=" | Unescaped }} r.Max.X && r.Min.Y {{ "<=" | Unescaped }} p.Y && p.Y {{ "<=" | Unescaped }} r.Max.Y 161 } 162 163 // Eq reports whether p and q are equal. 164 func (p {{ $pointName }}) Eq(q {{ $pointName }}) bool { 165 return p == q 166 } 167 168 // ZP{{ $camelCaseKey }} is the zero {{ $pointName }}. 169 var ZP{{ $camelCaseKey }} {{ $pointName }} 170 171 // Pt{{ $camelCaseKey }} is shorthand for {{ $pointName }}.{X, Y}. 172 func Pt{{ $camelCaseKey }}(X, Y {{ .Key }}) {{ $pointName }} { 173 return {{ $pointName }}{X, Y} 174 } 175 176 // {{ $rectangleName }} rectangle wrapper, contain two point. 177 type {{ $rectangleName }} struct { 178 Min, Max {{ $pointName }} 179 } 180 181 // String returns a string representation of r like "(3,4)-(6,5)". 182 func (r {{ $rectangleName }}) String() string { 183 return r.Min.String() + "-" + r.Max.String() 184 } 185 186 // RangePoints range all points in rectangle. 187 // if with return false, aborted range. 188 func (r {{ $rectangleName }}) RangePoints(with func(p {{ $pointName }}) bool) { 189 if with == nil || r == ZR{{ $camelCaseKey }} { 190 return 191 } 192 for x := r.Min.X; x {{ "<=" | Unescaped }} r.Max.X; x++ { 193 for y := r.Min.Y; y {{ "<=" | Unescaped }} r.Max.Y; y++ { 194 if !with(Pt{{ $camelCaseKey }}(x, y)) { 195 return 196 } 197 } 198 } 199 } 200 201 // RangePointsMinClosedMaxOpen range all points in rectangle except min x, y. 202 // if with return false, aborted range. 203 func (r {{ $rectangleName }}) RangePointsMinClosedMaxOpen(with func(p {{ $pointName }}) bool) { 204 if with == nil || r == ZR{{ $camelCaseKey }} { 205 return 206 } 207 for x := r.Min.X + 1; x {{ "<=" | Unescaped }} r.Max.X; x++ { 208 for y := r.Min.Y + 1; y {{ "<=" | Unescaped }} r.Max.Y; y++ { 209 if !with(Pt{{ $camelCaseKey }}(x, y)) { 210 return 211 } 212 } 213 } 214 } 215 216 // IntersectionWithLine check line intersection, if intersection, return true 217 func (r {{ $rectangleName }}) IntersectionWithLine(s {{ $pointName }}, e {{ $pointName }}) bool { 218 if s.X {{ "<=" | Unescaped }} r.Min.X && e.X {{ "<=" | Unescaped }} r.Min.X || s.X >= r.Max.X && e.X >= r.Max.X || s.Y {{ "<=" | Unescaped }} r.Min.Y && e.Y {{ "<=" | Unescaped }} r.Min.Y || s.Y >= r.Max.Y && e.Y >= r.Max.Y { 219 return false 220 } 221 a := s.Y - e.Y 222 b := e.X - s.X 223 c := e.Y*s.X - e.X*s.Y 224 if ((a*r.Min.X+b*r.Min.Y+c)*(a*r.Max.X+b*r.Max.Y+c)) {{ "<=" | Unescaped }} 0 || ((a*r.Max.X+b*r.Min.Y+c)*(a*r.Min.X+b*r.Max.Y+c)) {{ "<=" | Unescaped }} 0 { 225 return true 226 } 227 return false 228 } 229 230 // RangePointsMinMaxClosed range all points in rectangle except min/max x, y. 231 // if with return false, aborted range. 232 func (r {{ $rectangleName }}) RangePointsMinMaxClosed(with func(p {{ $pointName }}) bool) { 233 if with == nil || r == ZR{{ $camelCaseKey }} { 234 return 235 } 236 for x := r.Min.X + 1; x {{ "<" | Unescaped }} r.Max.X; x++ { 237 for y := r.Min.Y + 1; y {{ "<" | Unescaped }} r.Max.Y; y++ { 238 if !with(Pt{{ $camelCaseKey }}(x, y)) { 239 return 240 } 241 } 242 } 243 } 244 245 // RangePointsMinOpenMaxClosed range all points in rectangle except max x, y. 246 // if with return false, aborted range. 247 func (r {{ $rectangleName }}) RangePointsMinOpenMaxClosed(with func(p {{ $pointName }}) bool) { 248 if with == nil || r == ZR{{ $camelCaseKey }} { 249 return 250 } 251 for x := r.Min.X; x {{ "<" | Unescaped }} r.Max.X; x++ { 252 for y := r.Min.Y; y {{ "<" | Unescaped }} r.Max.Y; y++ { 253 if !with(Pt{{ $camelCaseKey }}(x, y)) { 254 return 255 } 256 } 257 } 258 } 259 260 // Dx returns r's width. 261 func (r {{ $rectangleName }}) Dx() {{ .Key }} { 262 return r.Max.X - r.Min.X 263 } 264 265 // Dy returns r's height. 266 func (r {{ $rectangleName }}) Dy() {{ .Key }} { 267 return r.Max.Y - r.Min.Y 268 } 269 270 // Size returns r's width and height. 271 func (r {{ $rectangleName }}) Size() {{ $pointName }} { 272 return {{ $pointName }}{ 273 r.Max.X - r.Min.X, 274 r.Max.Y - r.Min.Y, 275 } 276 } 277 278 // Add returns the rectangle r translated by p. 279 func (r {{ $rectangleName }}) Add(p {{ $pointName }}) {{ $rectangleName }} { 280 return {{ $rectangleName }}{ 281 {{ $pointName }}{r.Min.X + p.X, r.Min.Y + p.Y}, 282 {{ $pointName }}{r.Max.X + p.X, r.Max.Y + p.Y}, 283 } 284 } 285 286 // Sub returns the rectangle r translated by -p. 287 func (r {{ $rectangleName }}) Sub(p {{ $pointName }}) {{ $rectangleName }} { 288 return {{ $rectangleName }}{ 289 {{ $pointName }}{r.Min.X - p.X, r.Min.Y - p.Y}, 290 {{ $pointName }}{r.Max.X - p.X, r.Max.Y - p.Y}, 291 } 292 } 293 294 // Inset returns the rectangle r inset by n, which may be negative. If either 295 // of r's dimensions is less than 2*n then an empty rectangle near the center 296 // of r will be returned. 297 func (r {{ $rectangleName }}) Inset(n {{ .Key }}) {{ $rectangleName }} { 298 if r.Dx() {{ "<" | Unescaped }} 2*n { 299 r.Min.X = (r.Min.X + r.Max.X) / 2 300 r.Max.X = r.Min.X 301 } else { 302 r.Min.X += n 303 r.Max.X -= n 304 } 305 if r.Dy() {{ "<" | Unescaped }} 2*n { 306 r.Min.Y = (r.Min.Y + r.Max.Y) / 2 307 r.Max.Y = r.Min.Y 308 } else { 309 r.Min.Y += n 310 r.Max.Y -= n 311 } 312 return r 313 } 314 315 // Intersect returns the largest rectangle contained by both r and s. If the 316 // two rectangles do not overlap then the zero rectangle will be returned. 317 func (r {{ $rectangleName }}) Intersect(s {{ $rectangleName }}) {{ $rectangleName }} { 318 if r.Min.X {{ "<" | Unescaped }} s.Min.X { 319 r.Min.X = s.Min.X 320 } 321 if r.Min.Y {{ "<" | Unescaped }} s.Min.Y { 322 r.Min.Y = s.Min.Y 323 } 324 if r.Max.X > s.Max.X { 325 r.Max.X = s.Max.X 326 } 327 if r.Max.Y > s.Max.Y { 328 r.Max.Y = s.Max.Y 329 } 330 // Letting r0 and s0 be the values of r and s at the time that the method 331 // is called, this next line is equivalent to: 332 // 333 // if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc } 334 if r.Empty() { 335 return ZR{{ $camelCaseKey }} 336 } 337 return r 338 } 339 340 // Union returns the smallest rectangle that contains both r and s. 341 func (r {{ $rectangleName }}) Union(s {{ $rectangleName }}) {{ $rectangleName }} { 342 if r.Empty() { 343 return s 344 } 345 if s.Empty() { 346 return r 347 } 348 if r.Min.X > s.Min.X { 349 r.Min.X = s.Min.X 350 } 351 if r.Min.Y > s.Min.Y { 352 r.Min.Y = s.Min.Y 353 } 354 if r.Max.X {{ "<" | Unescaped }} s.Max.X { 355 r.Max.X = s.Max.X 356 } 357 if r.Max.Y {{ "<" | Unescaped }} s.Max.Y { 358 r.Max.Y = s.Max.Y 359 } 360 return r 361 } 362 363 // Empty reports whether the rectangle contains no points. 364 func (r {{ $rectangleName }}) Empty() bool { 365 return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y 366 } 367 368 // Eq reports whether r and s contain the same set of points. All empty 369 // rectangles are considered equal. 370 func (r {{ $rectangleName }}) Eq(s {{ $rectangleName }}) bool { 371 return r == s || r.Empty() && s.Empty() 372 } 373 374 // Overlaps reports whether r and s have a non-empty intersection. 375 func (r {{ $rectangleName }}) Overlaps(s {{ $rectangleName }}) bool { 376 return !r.Empty() && !s.Empty() && 377 r.Min.X {{ "<" | Unescaped }} s.Max.X && s.Min.X {{ "<" | Unescaped }} r.Max.X && 378 r.Min.Y {{ "<" | Unescaped }} s.Max.Y && s.Min.Y {{ "<" | Unescaped }} r.Max.Y 379 } 380 381 // In reports whether every point in r is in s. 382 func (r {{ $rectangleName }}) In(s {{ $rectangleName }}) bool { 383 if r.Empty() { 384 return true 385 } 386 // Note that r.Max is an exclusive bound for r, so that r.In(s) 387 // does not require that r.Max.In(s). 388 return s.Min.X {{ "<=" | Unescaped }} r.Min.X && r.Max.X {{ "<=" | Unescaped }} s.Max.X && 389 s.Min.Y {{ "<=" | Unescaped }} r.Min.Y && r.Max.Y {{ "<=" | Unescaped }} s.Max.Y 390 } 391 392 // Bounds returns a rectangle bounds 393 func (r {{ $rectangleName }}) Bounds() {{ $rectangleName }} { 394 return r 395 } 396 397 // Expanded returns a rectangle that has been expanded in the x-direction 398 // by margin.X, and in y-direction by margin.Y. The resulting rectangle may be empty. 399 func (r {{ $rectangleName }}) Expanded(margin {{ $pointName }}) {{ $rectangleName }} { 400 return {{ $rectangleName }}{ 401 {{ $pointName }}{r.Min.X - margin.X, r.Min.Y - margin.Y}, 402 {{ $pointName }}{r.Max.X + margin.X, r.Max.Y + margin.Y}, 403 } 404 } 405 406 // ExpandedByMargin returns a rectangle that has been expanded in the x-direction 407 // by margin, and in y-direction by margin. The resulting rectangle may be empty. 408 func (r {{ $rectangleName }}) ExpandedByMargin(margin {{ .Key }}) {{ $rectangleName }} { 409 return r.Expanded(Pt{{ $camelCaseKey }}(margin, margin)) 410 } 411 412 // ZR{{ $camelCaseKey }} is the zero {{ $rectangleName }}. 413 var ZR{{ $camelCaseKey }} {{ $rectangleName }} 414 415 // Rect{{ $camelCaseKey }} is shorthand for {{ $rectangleName }}{Pt(x0, y0), Pt(x1, y1)}. The returned 416 // rectangle has minimum and maximum coordinates swapped if necessary so that 417 // it is well-formed. 418 func Rect{{ $camelCaseKey }}(x0, y0, x1, y1 {{ .Key }}) {{ $rectangleName }} { 419 if x0 > x1 { 420 x0, x1 = x1, x0 421 } 422 if y0 > y1 { 423 y0, y1 = y1, y0 424 } 425 return {{ $rectangleName }}{{ "{" | Unescaped }}{{ $pointName }}{x0, y0}, {{ $pointName }}{x1, y1}} 426 } 427 428 // Rect{{ $camelCaseKey }}FromCenterSize constructs a rectangle with the given center and size. 429 // Both dimensions of size must be non-negative. 430 func Rect{{ $camelCaseKey }}FromCenterSize(center, size {{ $pointName }}) {{ $rectangleName }} { 431 return Rect{{ $camelCaseKey }}(center.X-size.X, center.Y-center.Y, center.X+size.X, center.Y+size.Y) 432 } 433 434 // HelixRectRangeFromCenterAndMargin{{ $camelCaseKey }} 由center节点逆时针螺旋由内向外访问margin区域内的所有节点 435 // 25 24 23 22 21 436 // 10 9 8 7 20 437 // 11 2 1 6 19 438 // 12 3 4 5 18 439 // 13 14 15 16 17 440 func HelixRectRangeFromCenterAndMargin{{ $camelCaseKey }}(center {{ $pointName }}, margin {{ .Key }}, with func(p {{ $pointName }}) bool) { 441 var x, y, xNow, yNow {{ .Key }} 442 xLen, yLen := {{ .Key }}(1), {{ .Key }}(1) 443 rectXYLen := margin*2 + 1 444 m, max := {{ .Key }}(0), rectXYLen*rectXYLen 445 startX, startY := center.X, center.Y 446 447 for m {{ "<=" | Unescaped }} max { 448 for x = startX; x >= startX-xLen; x-- { 449 m++ 450 if m > max || !with(Pt{{ $camelCaseKey }}(x, startY)) { 451 return 452 } 453 } 454 for y = startY - 1; y >= startY-yLen; y-- { 455 m++ 456 if m > max || !with(Pt{{ $camelCaseKey }}(x+1, y)) { 457 return 458 } 459 } 460 xLen++ 461 yLen++ 462 for xNow = x + 2; xNow {{ "<=" | Unescaped }} x+xLen; xNow++ { 463 m++ 464 if m > max || !with(Pt{{ $camelCaseKey }}(xNow, y+1)) { 465 return 466 } 467 } 468 for yNow = y + 1; yNow {{ "<=" | Unescaped }} y+yLen; yNow++ { 469 m++ 470 if m > max || !with(Pt{{ $camelCaseKey }}(xNow, yNow)) { 471 return 472 } 473 } 474 xLen++ 475 yLen++ 476 startX = xNow 477 startY = yNow 478 } 479 } 480 `