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  }