github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/example/goban/xy.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 // 7 // This build tag means that "go install golang.org/x/exp/shiny/..." doesn't 8 // install this example program. Use "go run main.go board.go xy.go" to run it. 9 10 package main 11 12 import ( 13 "fmt" 14 "image" 15 ) 16 17 // Note that a "square" is not a drawn square on the board, but 18 // the rectangle (sic) centered on the game point. 19 type Dims struct { 20 dim int // Size of board, always square. Full size is 19. 21 percent int // Scale. 22 xInset int // From left edge to left edge of first square. 23 yInset int // From top edge to top edge of first square. 24 stoneDiam int // Diameter of stone in pixels. 25 stoneRad2 int // Stone radius squared. 26 squareWidth int // Width of square in pixels. 27 squareHeight int // Height of square in pixels. 28 lineWidth int // Width of lines. 29 } 30 31 // Initial values, in pixels. These numbers match the images that are loaded; they are resized. 32 const ( 33 // These numbers are tuned for the images in asset/. 34 xInset0 = 100 // Distance from the edge of the board image to the left side of the first stone. 35 yInset0 = 115 // Distance from the top of the board image to the top side of the first stone. 36 stoneSize0 = 256 // Size of a stone on the board. 37 stoneDiam0 = 225 // Diameter of the circular part of the stone within the square. 38 // The square is a little smaller than the stone, for crowding. 39 squareWidth0 = 215 // Width of a square on the board. 40 squareHeight0 = 218 // Height of a square on the board. 41 stoneRad2 = stoneDiam0 * stoneDiam0 / 4 42 ) 43 44 func (d *Dims) Init(dim, percent int) { 45 d.dim = dim 46 d.Resize(percent) 47 } 48 49 func (d *Dims) Resize(percent int) { 50 d.percent = percent 51 d.xInset = xInset0 * percent / 100 52 d.yInset = yInset0 * percent / 100 53 d.stoneDiam = stoneDiam0 * percent / 100 54 d.squareWidth = squareWidth0 * percent / 100 55 d.squareHeight = squareHeight0 * percent / 100 56 d.stoneRad2 = d.stoneDiam * d.stoneDiam / 4 57 d.lineWidth = 4 * percent / 100 58 if d.lineWidth < 2 { 59 d.lineWidth = 2 60 } 61 if d.lineWidth > 2 { 62 d.lineWidth = 4 63 } 64 } 65 66 // An XY represents a pixel in the board image. Y is downwards. 67 type XY struct { 68 x, y int 69 } 70 71 // An IJ represents a position on the board. It is 1-indexed and J is upwards. 72 type IJ struct { 73 i, j int 74 } 75 76 func (ij IJ) String() string { 77 return fmt.Sprintf("%c%d", 'A'+int(ij.i-1), ij.j) 78 } 79 80 // A go board is played on centers, not on squares, but we think of it internally 81 // as IJ squares (1, 1) through (19, 19), and draw the lines through the middle 82 // of those squares. That is how the arithmetic is done converting between 83 // IJ and XY. 84 85 // IJ converts a position in the board image to a Go position (IJ) on the board. 86 // The boolean is false if the point does not represent a Go position. 87 func (xy XY) IJ(d *Dims) (IJ, bool) { 88 x, y := xy.x, xy.y 89 x -= d.xInset 90 y -= d.yInset 91 i := x / d.squareWidth 92 j := y / d.squareHeight 93 // Now zero indexed. Make j goes up and switch to 1-indexed. 94 j = d.dim - 1 - j 95 i++ 96 j++ 97 if 1 <= i && i <= d.dim && 1 <= j && j <= d.dim { 98 return IJ{i, j}, true 99 } 100 return IJ{}, false 101 } 102 103 // XY converts a Go position to the upper left corner of the square for that position 104 // on the board image. 105 func (ij IJ) XY(d *Dims) XY { 106 // Change to 0-indexed. 107 ij.i-- 108 ij.j-- 109 // j goes down. 110 ij.j = (d.dim - 1) - ij.j 111 return XY{d.xInset + ij.i*d.squareWidth, d.yInset + ij.j*d.squareHeight} 112 } 113 114 // IJtoXYCenter converts a Go position to the center of the square for that position 115 // on the board image. 116 func (ij IJ) XYCenter(d *Dims) XY { 117 xy := ij.XY(d) 118 xy.x += d.squareWidth / 2 119 xy.y += d.squareHeight / 2 120 return xy 121 } 122 123 // IJtoXYStone converts a Go position to the square holding the stone for that position 124 // on the board image. 125 func (ij IJ) XYStone(d *Dims) image.Rectangle { 126 center := ij.XYCenter(d) 127 min := image.Point{center.x - d.stoneDiam/2, center.y - d.stoneDiam/2} 128 max := image.Point{center.x + d.stoneDiam/2, center.y + d.stoneDiam/2} 129 return image.Rectangle{Min: min, Max: max} 130 }