package drawille //import "code.google.com/p/goncurses" import "math" var pixel_map = [4][2]int{ {0x1, 0x8}, {0x2, 0x10}, {0x4, 0x20}, {0x40, 0x80}} // Braille chars start at 0x2800 var braille_char_offset = 0x2800 func getPixel(y, x int) int { var cy, cx int if y >= 0 { cy = y % 4 } else { cy = 3 + ((y + 1) % 4) } if x >= 0 { cx = x % 2 } else { cx = 1 + ((x + 1) % 2) } return pixel_map[cy][cx] } type Canvas struct { LineEnding string chars map[int]map[int]int } // Make a new canvas func NewCanvas() Canvas { c := Canvas{LineEnding: "\n"} c.Clear() return c } func (c Canvas) MaxY() int { max := 0 for k, _ := range c.chars { if k > max { max = k } } return max * 4 } func (c Canvas) MinY() int { min := 0 for k, _ := range c.chars { if k < min { min = k } } return min * 4 } func (c Canvas) MaxX() int { max := 0 for _, v := range c.chars { for k, _ := range v { if k > max { max = k } } } return max * 2 } func (c Canvas) MinX() int { min := 0 for _, v := range c.chars { for k, _ := range v { if k < min { min = k } } } return min * 2 } // Clear all pixels func (c *Canvas) Clear() { c.chars = make(map[int]map[int]int) } // Convert x,y to cols, rows func (c Canvas) get_pos(x, y int) (int, int) { return (x / 2), (y / 4) } // Set a pixel of c func (c *Canvas) Set(x, y int) { px, py := c.get_pos(x, y) if m := c.chars[py]; m == nil { c.chars[py] = make(map[int]int) } val := c.chars[py][px] mapv := getPixel(y, x) c.chars[py][px] = val | mapv } // Unset a pixel of c func (c *Canvas) UnSet(x, y int) { px, py := c.get_pos(x, y) x, y = int(math.Abs(float64(x))), int(math.Abs(float64(y))) if m := c.chars[py]; m == nil { c.chars[py] = make(map[int]int) } c.chars[py][px] = c.chars[py][px] &^ getPixel(y, x) } // Toggle a point func (c *Canvas) Toggle(x, y int) { px, py := c.get_pos(x, y) if (c.chars[py][px] & getPixel(y, x)) != 0 { c.UnSet(x, y) } else { c.Set(x, y) } } // Set text to the given coordinates func (c *Canvas) SetText(x, y int, text string) { x, y = x/2, y/4 if m := c.chars[y]; m == nil { c.chars[y] = make(map[int]int) } for i, char := range text { c.chars[y][x+i] = int(char) - braille_char_offset } } // Get pixel at the given coordinates func (c Canvas) Get(x, y int) bool { dot_index := pixel_map[y%4][x%2] x, y = x/2, y/4 char := c.chars[y][x] return (char & dot_index) != 0 } // GetScreenCharacter gets character at the given screen coordinates func (c Canvas) GetScreenCharacter(x, y int) rune { return rune(c.chars[y][x] + braille_char_offset) } // GetCharacter gets character for the given pixel func (c Canvas) GetCharacter(x, y int) rune { return c.GetScreenCharacter(x/4, y/4) } // Rows retrieves the rows from a given view func (c Canvas) Rows(minX, minY, maxX, maxY int) []string { minrow, maxrow := minY/4, (maxY)/4 mincol, maxcol := minX/2, (maxX)/2 ret := make([]string, 0) for rownum := minrow; rownum < (maxrow + 1); rownum = rownum + 1 { row := "" for x := mincol; x < (maxcol + 1); x = x + 1 { char := c.chars[rownum][x] row += string(rune(char + braille_char_offset)) } ret = append(ret, row) } return ret } // Frame retrieves a string representation of the frame at the given parameters func (c Canvas) Frame(minX, minY, maxX, maxY int) string { var ret string for _, row := range c.Rows(minX, minY, maxX, maxY) { ret += row ret += c.LineEnding } return ret } func (c Canvas) String() string { return c.Frame(c.MinX(), c.MinY(), c.MaxX(), c.MaxY()) } type Point struct { X, Y int } // Line returns []Point where each Point is a dot in the line func Line(x1, y1, x2, y2 int) []Point { xdiff := abs(x1 - x2) ydiff := abs(y2 - y1) var xdir, ydir int if x1 <= x2 { xdir = 1 } else { xdir = -1 } if y1 <= y2 { ydir = 1 } else { ydir = -1 } r := max(xdiff, ydiff) points := make([]Point, r+1) for i := 0; i <= r; i++ { x, y := x1, y1 if ydiff != 0 { y += (i * ydiff) / (r * ydir) } if xdiff != 0 { x += (i * xdiff) / (r * xdir) } points[i] = Point{x, y} } return points } // DrawLine draws a line onto the Canvas func (c *Canvas) DrawLine(x1, y1, x2, y2 int) { for _, p := range Line(x1, y1, x2, y2) { c.Set(p.X, p.Y) } } func (c *Canvas) DrawPolygon(center_x, center_y, sides, radius float64) { degree := 360 / sides for n := 0; n < int(sides); n = n + 1 { a := float64(n) * degree b := float64(n+1) * degree x1 := int(center_x + (math.Cos(radians(a)) * (radius/2 + 1))) y1 := int(center_y + (math.Sin(radians(a)) * (radius/2 + 1))) x2 := int(center_x + (math.Cos(radians(b)) * (radius/2 + 1))) y2 := int(center_y + (math.Sin(radians(b)) * (radius/2 + 1))) c.DrawLine(x1, y1, x2, y2) } } func radians(d float64) float64 { return d * (math.Pi / 180) } func round(x float64) int { return int(x + 0.5) } func min(x, y int) int { if x < y { return x } return y } func max(x, y int) int { if x > y { return x } return y } func abs(x int) int { if x < 0 { return x * -1 } return x }