xmtop/termui/drawille-go/drawille.go
2020-02-13 10:15:52 -06:00

276 lines
5.0 KiB
Go

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
}