/
texttreedrawer.go
128 lines (116 loc) · 3.82 KB
/
texttreedrawer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package draw
import (
"bufio"
"fmt"
"io"
"log"
"math"
)
/*
TextTreeDrawer initializer. TextTreeDraws draws tree as ASCII on stdout or any file.
So far: Does not take into account branch lengths.
*/
func NewTextTreeDrawer(w io.Writer, width, height int, rightmargin int) TreeDrawer {
ttd := &textTreeDrawer{
w,
width,
rightmargin,
height,
nil,
0.0,
0.0,
0.0,
0.0,
}
//ttd.height = ntips * 2
ttd.textCanvas = make([][]rune, ttd.height)
for i := 0; i < len(ttd.textCanvas); i++ {
ttd.textCanvas[i] = make([]rune, ttd.width+ttd.rightmargin)
for j := 0; j < len(ttd.textCanvas[i]); j++ {
ttd.textCanvas[i][j] = ' '
}
}
return ttd
}
func (ttd *textTreeDrawer) SetMaxValues(maxLength, maxHeight float64, maxNameLength, maxNameHeight int) {
ttd.maxLength = maxLength
ttd.maxHeight = maxHeight
ttd.maxNameLength = maxNameLength
ttd.maxNameHeight = maxNameHeight
}
/*
Draw a tree as ASCII in any file (stdout/stderr, etc.).
*/
type textTreeDrawer struct {
outwriter io.Writer // Output file
width int // Width of the ascii canvas
rightmargin int // Right margin of the canvas (in addition to the width)
height int // Height of the ascii canvas
textCanvas [][]rune // ascii canvas
maxHeight float64 // Maximum height of object to draw (in original scale)
maxLength float64 // Maximum length of object to draw (in original scale)
maxNameLength int // Maximum length of species names / horitzontal
maxNameHeight int // Maximum length of species names / vertical
}
func (ttd *textTreeDrawer) DrawHLine(x1, x2, y float64) {
min := float64(ttd.width-ttd.maxNameLength) * x1 / ttd.maxLength
max := float64(ttd.width-ttd.maxNameLength) * x2 / ttd.maxLength
ypos := y * float64(ttd.height-ttd.maxNameHeight) / ttd.maxHeight
for i := int(min); float64(i) < max-1; i++ {
if i == int(min) {
ttd.textCanvas[int(ypos)][i] = '+'
} else {
ttd.textCanvas[int(ypos)][i] = '-'
}
}
}
func (ttd *textTreeDrawer) DrawVLine(x, y1, y2 float64) {
min := float64(ttd.height-ttd.maxNameHeight) * y1 / ttd.maxHeight
max := float64(ttd.height-ttd.maxNameHeight) * y2 / ttd.maxHeight
xpos := float64(ttd.width-ttd.maxNameLength) * x / ttd.maxLength
for i := int(min); float64(i) < max; i++ {
if i == int(min) || i == int(max) {
ttd.textCanvas[i][int(xpos)] = '+'
} else {
ttd.textCanvas[i][int(xpos)] = '|'
}
}
}
func (ttd *textTreeDrawer) DrawLine(x1, x2, y1, y2 float64) {
log.Print("Method DrawLine cannot be called on textTreeDrawer: The line will not be drawn")
}
func (ttd *textTreeDrawer) DrawCurve(centerx, centery float64, middlex, middley float64, radius float64, startAngle, endAngle float64) {
log.Print("Method DrawCurve cannot be called on textTreeDrawer: The curve will not be drawn")
}
func (ttd *textTreeDrawer) DrawCircle(x, y float64) {
ypos := float64(ttd.height-ttd.maxNameHeight) * y / ttd.maxHeight
xpos := float64(ttd.width-ttd.maxNameLength) * x / ttd.maxLength
ttd.textCanvas[int(ypos)][int(xpos)] = '*'
}
func (ttd *textTreeDrawer) DrawColoredCircle(x, y float64, r, g, b, a uint8) {
ttd.DrawCircle(x, y)
}
func (ttd *textTreeDrawer) DrawName(x, y float64, name string, angle float64) {
ypos := float64(ttd.height-ttd.maxNameHeight) * y / ttd.maxHeight
xpos := float64(ttd.width-ttd.maxNameLength) * x / ttd.maxLength
for i, c := range []rune(name) {
if int(math.Ceil(xpos))+i < len(ttd.textCanvas[int(ypos)]) {
ttd.textCanvas[int(ypos)][int(math.Ceil(xpos))+i] = c
}
}
}
func (ttd *textTreeDrawer) Write() {
// Create Buffered Writer from io.writer
b := bufio.NewWriter(ttd.outwriter)
for _, l := range ttd.textCanvas {
for _, c := range l {
b.WriteString(fmt.Sprintf("%c", c))
}
b.WriteString("\n")
}
_ = b.Flush()
}
func (ttd *textTreeDrawer) Bounds() (width, height int) {
width, height = ttd.width, ttd.height
return
}