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  `