package main import ( "github.com/llgcode/draw2d" "github.com/llgcode/draw2d/draw2dimg" "fmt" "github.com/llgcode/draw2d/draw2dkit" "image" "image/color" "math" ) func main() { fmt.Println("hi") w := 2500.0 h := 1300.0 dest := image.NewRGBA(image.Rect(0, 0, int(w), int(h))) dc := draw2dimg.NewGraphicContext(dest) dc.SetFillColor(color.RGBA{255, 255, 255, 0xff}) draw2dkit.Rectangle(dc, 0, 0, w, h) dc.Fill() dc.SetLineCap(draw2d.RoundCap) dc.SetLineJoin(draw2d.RoundJoin) dc.Translate(100, h/2) //dc.Scale(.5, .5) dc.SetStrokeColor(color.RGBA{0, 0, 0, 0xff}) d := &drawer{ c: dc, skew: -1 * math.Tan(radians(22.5)), //-1*math.Tan(radians(22.5)) } cap := &capturer{ skew: -1 * math.Tan(radians(22.5)), //-1*math.Tan(radians(22.5)) paths: make(Paths,0), path: Path{points:make([]Point,0)}, } fmt.Println(cap) d.InitCharTable() d.dumpCharTable() //d.skew = 0.0 // // d.Translate(0, 0) // // dc.SetLineWidth(.5) //x height // d.MoveTo(-2*w, 1500) // d.LineTo(2*w, 1500) // d.Stroke() // // x height // d.MoveTo(-2*w, 1000) // d.LineTo(2*w, 1000) // d.Stroke() // // left // d.MoveTo(0, -2*h) // d.LineTo(0, 2*w) // d.Stroke() // // right lowercase // d.MoveTo(385*2, -2*h) // d.LineTo(385*2, 2*w) // d.Stroke() // // right uppercase // d.MoveTo(1170, -2*h) // d.LineTo(1170, 2*w) // d.Stroke() // // baseline // d.MoveTo(-2*w, 0) // d.LineTo(2*w, 0) // d.Stroke() //abcdefghijklmnopqrstuvwxyz kerntable := map[rune]map[rune]float64{ 'A': map[rune]float64{ 'a': -100.0, 'c': -100.0, 'd': -100.0, 'e': -100.0, 'g': -100.0, 'o': -100.0, 'q': -100.0, 's': -100.0, 'u': -100.0, 'v': -300.0, 'w': -300.0, 'y': -250.0, }, 'E': map[rune]float64{ 'a': -200.0, 'c': -200.0, 'd': -200.0, 'e': -200.0, 'g': -200.0, 'o': -200.0, 'q': -200.0, 's': -100.0, 'u': -100.0, 'v': -300.0, 'w': -300.0, 'y': -200.0, }, 'F': map[rune]float64{ 'a': -300.0, 'c': -300.0, 'd': -300.0, 'e': -300.0, 'g': -300.0, 'm': -300.0, 'n': -300.0, 'o': -300.0, 'p': -300.0, 'q': -300.0, 'r': -300.0, 's': -300.0, 'u': -300.0, 'v': -300.0, 'w': -300.0, 'x': -300.0, 'y': -300.0, 'z': -300.0, }, 'K': map[rune]float64{ 'a': -200.0, 'c': -200.0, 'd': -200.0, 'e': -200.0, 'g': -200.0, 'o': -200.0, 'q': -200.0, 's': -100.0, 'u': -100.0, 'v': -300.0, 'w': -300.0, 'y': -200.0, }, 'L': map[rune]float64{ 'a': -200.0, 'c': -200.0, 'd': -200.0, 'e': -200.0, 'g': -200.0, 'o': -200.0, 'q': -200.0, 's': -100.0, 'u': -100.0, 'v': -300.0, 'w': -300.0, 'y': -200.0, }, 'P': map[rune]float64{ 'a': -100.0, 'c': -100.0, 'd': -100.0, 'e': -100.0, 'g': -100.0, 'o': -100.0, 'q': -100.0, 's': -100.0, }, 'R': map[rune]float64{ 'a': -100.0, 'c': -100.0, 'd': -100.0, 'e': -100.0, 'g': -100.0, 'o': -100.0, 'q': -100.0, 's': -100.0, }, 'T': map[rune]float64{ 'a': -300.0, 'c': -300.0, 'd': -300.0, 'e': -300.0, 'g': -300.0, 'm': -300.0, 'n': -300.0, 'o': -300.0, 'p': -300.0, 'q': -300.0, 'r': -300.0, 's': -300.0, 'u': -300.0, 'v': -300.0, 'w': -300.0, 'x': -300.0, 'y': -300.0, 'z': -300.0, }, 'V': map[rune]float64{ 'a': -200.0, 'c': -200.0, 'd': -200.0, 'e': -200.0, 'g': -200.0, 'm': -100.0, 'n': -100.0, 'o': -200.0, 'p': -100.0, 'q': -200.0, 'r': -100.0, 's': -200.0, 'u': -100.0, 'v': -100.0, 'w': -100.0, 'x': -100.0, 'y': -100.0, 'z': -100.0, }, 'W': map[rune]float64{ 'a': -200.0, 'c': -200.0, 'd': -200.0, 'e': -200.0, 'g': -200.0, 'm': -100.0, 'n': -100.0, 'o': -200.0, 'p': -100.0, 'q': -200.0, 'r': -100.0, 's': -200.0, 'u': -100.0, 'v': -100.0, 'w': -100.0, 'x': -100.0, 'y': -100.0, 'z': -100.0, }, 'X': map[rune]float64{ 'a': -200.0, 'c': -200.0, 'd': -200.0, 'e': -200.0, 'g': -200.0, 'o': -200.0, 'q': -200.0, 's': -100.0, 'u': -100.0, 'v': -300.0, 'w': -300.0, 'y': -200.0, }, 'Y': map[rune]float64{ 'a': -300.0, 'c': -300.0, 'd': -300.0, 'e': -300.0, 'g': -300.0, 'm': -300.0, 'n': -300.0, 'o': -300.0, 'p': -300.0, 'q': -300.0, 'r': -300.0, 's': -300.0, 'u': -300.0, 'v': -300.0, 'w': -300.0, 'x': -300.0, 'y': -300.0, 'z': -300.0, }, 'Z': map[rune]float64{ 'a': -200.0, 'c': -200.0, 'd': -200.0, 'e': -200.0, 'g': -200.0, 'o': -200.0, 'q': -200.0, 's': -100.0, 'u': -100.0, 'v': -300.0, 'w': -300.0, 'y': -200.0, }, 'f': map[rune]float64{ 'f': -100.0, }, 'i': map[rune]float64{ 'i': 100.0, 'l': 100.0, 't': 100.0, }, 'k': map[rune]float64{ 'a': -100.0, 'c': -100.0, 'd': -100.0, 'e': -100.0, 'g': -100.0, 'o': -100.0, 'q': -100.0, 's': -100.0, }, 'l': map[rune]float64{ 'i': 100.0, 'l': 100.0, 't': 100.0, }, } var cw float64 lineWidth := 2.5 dc.SetLineWidth(lineWidth) d.SetXHeight(24.0) d.skew = -1 * math.Tan(radians(22.5)) //str1 := "the quick brown fox jumps over the lazy dog" // str2 := "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG" // str3 := "Fa Fb Fc Fd Fe Ff Fh Fi Fj Fk Fl Fm Fn Fo Fp Fq Fr Fs Ft Fu Fv Fw Fx Fy Fz" // d.Translate(0, 0) // // for _, c := range str1 { // cw = d.drawChar(c) // d.AdvanceX(cw + 300 + lineWidth) // } // d.Translate(0, 2500) // for _, c := range str2 { // cw = d.drawChar(c) // d.AdvanceX(cw + 300 + lineWidth) // } // yoff := -20000.0 // for _, C := range "abcdefghijklmnopqrstuvwxyz" { // d.Translate(0, yoff) // yoff += 2500 // for _, c := range "abcdefghijklmnopqrstuvwxyz" { // cw = d.drawChar(C) // d.AdvanceX(cw + 300 + lineWidth + kerntable[C][c]) // cw = d.drawChar(c) // d.AdvanceX(cw + 300 + lineWidth) // cw = d.drawChar(' ') // d.AdvanceX(cw + 300 + lineWidth) // } // } var last rune tx := 0.0 lines := 1.0 for _, c := range "Hello, there. This is a block of \"text\" that I am using to test the basic wrapping capabilities of this hideous block of code that I've created to render text using mixed dimensional spaces. abcdefghijklmnopABCDEFGHIJKLMNOP012,345.6789°#$%*" { if last != 0 { cw = d.drawChar(last) cw += kerntable[last][c] d.AdvanceX(cw + 400) tx += cw + 400 if tx > 50000 { d.Translate(0, lines*2500.0) tx = 0 lines++ } } last = c } d.drawChar(last) dc.Stroke() draw2dimg.SaveToPngFile("ellipse.png", dest) } func (d *drawer) InitCharTable() { d.charTable = make(map[rune]func() float64) d.charTable[' '] = func() float64 { return 385 } d.charTable['a'] = func() float64 { points := d.Arc(385, 520, 120, 60, 0) x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points) d.Line(x, 0, x, 1000) return x } d.charTable['b'] = func() float64 { points := d.Arc(385, 520, 300, 240, 0) d.DrawPathOriginAtCenter(-points.Left(), 500, points) d.Line(0, 0, 0, 1500) return points.Width() - 20 } d.charTable['c'] = func() float64 { points := d.Arc(385, 520, 130, 50, 0) x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points) return x } d.charTable['d'] = func() float64 { points := d.Arc(385, 520, 120, 60, 0) x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points) d.Line(x, 0, x, 1500) return x } d.charTable['e'] = func() float64 { points := d.Arc(385, 520, 135, 85, 0) _, _, _, y := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points) w := points.Width() d.LineTo(w-2*points.End().X-20, y) return w - 40 } d.charTable['f'] = func() float64 { d.Line(130, 0, 130, 1300) points := d.Arc(200, 200, 270, 35, 0) _, _, x, _ := d.DrawPathOriginAtStart(130, 1300, points) d.Line(-100, 1000, 400, 1000) return x - 150 } d.charTable['g'] = func() float64 { points := d.Arc(385, 520, 120, 60, 0) x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points) points2 := d.Arc(300, 320, 90, 220, 0) g := points2.Height() d.Line(x, -400+g, x, 1000) d.DrawPathOriginAtStart(x, -400+g, points2) return x } d.charTable['h'] = func() float64 { d.Line(0, 1500, 0, 0) r := -25.0 points := d.Arc(700/2, 550/2, 270.0-r, 90-r, r) _, _, x2, y2 := d.DrawPathOriginAtStart(0, 680, points) d.Line(x2, y2, x2, 0) return x2 } d.charTable['i'] = func() float64 { d.Line(0, 1000, 0, 0) d.Line(0, 1350, 0, 1500) return 1 } d.charTable['j'] = func() float64 { o := 200.0 points := d.Arc(370/2, 370/2, 90, 190, 0) w := points.Width() d.DrawPathOriginAtStart(w-o, -400+points.Height(), points) d.Line(w-o, 1000, w-o, -400+points.Height()) d.Line(w-o, 1350, w-o, 1500) return w } d.charTable['k'] = func() float64 { d.Line(0, 0, 0, 1500) d.Line(0, 410, 572, 616+410) // upper leg 560,1000 d.Line(260, 690, 624, 0) // lower leg return 624 } d.charTable['l'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(0, 0) return 1 } d.charTable['m'] = func() float64 { d.Line(0, 0, 0, 1000) r := -25.0 points := d.Arc(700/2, 550/2, 270.0-r, 90-r, r) _, _, x, y := d.DrawPathOriginAtStart(0, 680, points) d.Line(x, 0, x, y) _, _, x, y = d.DrawPathOriginAtStart(x, 680, points) d.Line(x, 0, x, y) return x } d.charTable['n'] = func() float64 { d.Line(0, 0, 0, 1000) r := -25.0 points := d.Arc(700/2, 550/2, 270.0-r, 90-r, r) _, _, x, y := d.DrawPathOriginAtStart(0, 680, points) d.Line(x, 0, x, y) return x } d.charTable['o'] = func() float64 { points := d.Arc(385, 520, 0, 360, 0) d.DrawPathOriginAtCenter(385-20, 500, points) return points.Width() - 40 } d.charTable['p'] = func() float64 { points := d.Arc(385, 520, 300, 240, 0) d.DrawPathOriginAtCenter(-points.Left(), 500, points) d.Line(0, -500, 0, 1000) return points.Width() - 20 } d.charTable['q'] = func() float64 { points := d.Arc(385, 520, 120, 60, 0) x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points) d.Line(x, -500, x, 1000) return points.Width() - 20 } d.charTable['r'] = func() float64 { r := 20.0 points := d.Arc(290, 490, 270.0-r, 360.0-r, r) d.DrawPathOriginAtStart(0, 380, points) d.Line(0, 0, 0, 1000) return points.Width() } d.charTable['s'] = func() float64 { m := 10.0 e := 73.0 ex := 340.0 ey := 270.0 oy := 527.0 pointsT := d.Arc(ex*.9, ey*.9, 180+m, e, 0.0) pointsB := d.Arc(ex, ey, 360+m, 180+e, 0.0) w := pointsB.Width() j := LineByAngleAndAzimuith(m+90, 140) d.DrawPathOriginAtCenter(w/2-20, oy, j) je := j.End() js := j.Start() d.DrawPathOriginAtStart(js.X+w/2-20, js.Y+oy, pointsT) d.DrawPathOriginAtStart(je.X+w/2-20, je.Y+oy, pointsB) return w - 40 } d.charTable['t'] = func() float64 { d.Line(80, 0, 80, 1300) d.Line(-150, 1000, 310, 1000) return 310 } d.charTable['u'] = func() float64 { r := -25.0 points := d.Arc(700/2, 550/2, 90-r, 270-r, r) w := points.Width() _, _, x, y := d.DrawPathOriginAtStart(w, 320, points) d.Line(w, 0, w, 1000) d.Line(x, 1000, x, y) return w } d.charTable['v'] = func() float64 { d.MoveTo(0, 1000) d.LineTo(320, 0) d.LineTo(370, 0) d.LineTo(690, 1000) return 690 } d.charTable['w'] = func() float64 { d.MoveTo(0, 1000) d.LineTo(320, 0) d.LineTo(370, 0) d.LineTo(658, 900) d.LineTo(708, 900) d.LineTo(996, 0) d.LineTo(1046, 0) d.LineTo(1366, 1000) return 1366 } d.charTable['x'] = func() float64 { d.Line(0, 0, 670, 1000) d.Line(670, 0, 0, 1000) return 670 } d.charTable['y'] = func() float64 { d.MoveTo(0, 1000) d.LineTo(320, 0) d.MoveTo(640, 1000) ex, ey := 320.0-32.0, -100.0 d.LineTo(ex, ey) points := d.Arc(200, 200, 108.6629, 200, 0) d.DrawPathOriginAtStart(ex, ey, points) return 670 } d.charTable['z'] = func() float64 { d.MoveTo(0, 1000) d.LineTo(670, 1000) d.LineTo(0, 0) d.LineTo(670, 0) return 670 } d.charTable['('] = func() float64 { points := d.Arc(1500, 1500, 234, 306, 0) w := points.Width() d.DrawPathOriginAtStart(w, -180, points) return w } d.charTable[')'] = func() float64 { points := d.Arc(1500, 1500, 54, 126, 0) w := points.Width() d.DrawPathOriginAtEnd(0, -180, points) return w } d.charTable['%'] = func() float64 { cw := 550.0 points := d.Arc(cw/2, cw/2, 0, 360, 0) d.DrawPathOriginAtCenter(cw/2, 1500-cw/2, points) d.DrawPathOriginAtCenter(800+cw/2, cw/2, points) d.Line(cw/2, 0, 800+cw/2, 1500) return 800 + cw } d.charTable['°'] = func() float64 { cw := 500.0 points := d.Arc(cw/2, cw/2, 0, 360, 0) d.DrawPathOriginAtCenter(cw/2, 1500-cw/2, points) return cw } d.charTable['"'] = func() float64 { d.Line(0, 1500, 0, 1000) d.Line(400, 1500, 400, 1000) return 400 } d.charTable['\''] = func() float64 { d.Line(0, 1500, 0, 1000) return 200 } d.charTable['#'] = func() float64 { w := 1000.0 h := 1500.0 s := 350.0 slant := 200.0 scaledSlant := slant / h * s d.Line(-scaledSlant, -s/2+h/2, w-scaledSlant, -s/2+h/2) d.Line(scaledSlant, s/2+h/2, w+scaledSlant, +s/2+h/2) d.Line(-s/2+w/2-slant, 0, -s/2+w/2+slant, h) d.Line(s/2+w/2-slant, 0, s/2+w/2+slant, h) return w } d.charTable['$'] = func() float64 { m := 10.0 // angle where curves meet e := 73.0 // angle at ends of curves ey := 300.0 ex := ey * 1.2593 oy := 1500.0 * 1 / (1 + .9) pointsT := d.Arc(ex*.9, ey*.9, 180+m, e, 0.0) pointsB := d.Arc(ex, ey, 360+m, 180+e, 0.0) w := pointsB.Width() j := LineByAngleAndAzimuith(m+90, 140) d.DrawPathOriginAtCenter(w/2-20, oy, j) je := j.End() js := j.Start() d.DrawPathOriginAtStart(js.X+w/2-20, js.Y+oy, pointsT) d.DrawPathOriginAtStart(je.X+w/2-20, je.Y+oy, pointsB) d.Line(w/2-20, 0, w/2-20, 1500) return w - 40 } d.charTable['*'] = func() float64 { hoff := 200.0 dia := 700.0 rad := dia / 2 voff := 1500.0 - rad d.Line(hoff, voff+rad, hoff, voff-rad) // | dx := rad * .86 dy := rad * .5 d.Line(-dx+hoff, -dy+voff, dx+hoff, dy+voff) // - d.Line(-dx+hoff, dy+voff, dx+hoff, -dy+voff) // - return dx * 1.3 } d.charTable['='] = func() float64 { d.Line(0, 570, 550, 570) d.Line(0, 570+350, 550, 570+350) return 550 } d.charTable['.'] = func() float64 { points := d.Arc(50, 50, 0, 360, 0) d.DrawPathOriginAtCenter(0, 50, points) return 1 } d.charTable[','] = func() float64 { a := 20.0 points := d.Arc(50, 50, 0, 360, 90+a) _, _, x, y := d.DrawPathOriginAtCenter(0, 50, points) p2 := LineByAngleAndAzimuith(180+a, 300) d.DrawPathOriginAtStart(x, y, p2) return 100 } d.charTable['-'] = func() float64 { d.Line(0, 750, 500, 750) return 500 } d.charTable['–'] = func() float64 { // en dash d.Line(0, 750, 750, 750) return 750 } d.charTable['—'] = func() float64 { // em dash d.Line(0, 750, 1500, 750) return 1500 } d.charTable['0'] = func() float64 { points := d.Arc(550, 750, 0, 360, 0) d.DrawPathOriginAtCenter(550, 750, points) return points.Width() } d.charTable['1'] = func() float64 { d.MoveTo(150, 1500) d.LineTo(150, 0) return 300 } d.charTable['2'] = func() float64 { a := 60.0 p1 := d.Arc(470, 390, 270, 90+a, 0.0) p2 := d.Arc(500, 600, 270, 270+a, 0.0) p3 := LineByAngleAndAzimuith(a, 500) w := p1.Width() + 50 d.MoveTo(w, 0) d.LineTo(0, 0) _, _, x, y := d.DrawPathOriginAtStart(0, 0, p2) _, _, x, y = d.DrawPathOriginAtStart(x, y, p3) d.DrawPathOriginAtEnd(x, y, p1) return w } d.charTable['3'] = func() float64 { a := 70.0 p2 := d.Arc(2300/2, 1450/2, 95, 90+a, 0.0) p1 := d.Arc(1000/2, 960/2, 270+a, 250, 0.0) x, y, _, _ := d.DrawPathOriginAtEnd(0, 300, p1) x, y, _, _ = d.DrawPathOriginAtEnd(x, y, p2) d.MoveTo(x, y) d.LineTo(0, y) return p1.Width() } d.charTable['4'] = func() float64 { d.MoveTo(830, 0) d.LineTo(830, 1500) d.LineTo(700, 1500) d.LineTo(0, 650) d.LineTo(0, 520) d.LineTo(1110, 520) return 1110 } d.charTable['5'] = func() float64 { p1 := d.Arc(1000/2, 1010/2, 305, 240, 0.0) p2 := LineByAngleAndAzimuith(7, 720) x, y, _, _ := d.DrawPathOriginAtEnd(0, 230, p1) _, _, x, y = d.DrawPathOriginAtStart(x, y, p2) d.MoveTo(x, y) d.LineTo(x+700, y) return p1.Width() } d.charTable['6'] = func() float64 { a := 90.0 p1 := d.Arc(960/2, 810/2, 270, 270-a, 0.0) p2 := d.Arc(1100/2, 1500/2, 270-a, 50, 0.0) p3 := LineByAngleAndAzimuith(-a, 0) _, _, x, y := d.DrawPathOriginAtCenter(960/2+70, 810/2, p1) _, _, x, y = d.DrawPathOriginAtStart(x, y, p3) d.DrawPathOriginAtStart(x, y, p2) return 900 } d.charTable['7'] = func() float64 { p1 := d.Arc(2000/2, 2860/2, 270, 337, 0.0) d.MoveTo(0, 1500) d.LineTo(1050, 1500) d.LineTo(1050, 1500-130) d.DrawPathOriginAtEnd(1050, 1500-130, p1) return 1050 } d.charTable['8'] = func() float64 { ex := 500.0 ey := 400.0 oy := 790.0 pointsT := d.Arc(ex*.9, ey*.9, 180, 180, 0.0) pointsB := d.Arc(ex, ey, 0, 0, 0.0) w := pointsB.Width() d.DrawPathOriginAtStart(w/2, oy, pointsT) d.DrawPathOriginAtStart(w/2, oy, pointsB) return w } d.charTable['9'] = func() float64 { a := 90.0 p1 := d.Arc(960/2, 810/2, 270, 270-a, 180) p2 := d.Arc(1100/2, 1500/2, 270-a, 50, 180) p3 := LineByAngleAndAzimuith(-a, 0) _, _, x, y := d.DrawPathOriginAtCenter(960/2, 1100, p1) _, _, x, y = d.DrawPathOriginAtStart(x, y, p3) d.DrawPathOriginAtStart(x, y, p2) return 900 + 70 } d.charTable['A'] = func() float64 { d.MoveTo(0, 0) d.LineTo(520, 1500) d.LineTo(520+130, 1500) d.LineTo(520+130+520, 0) d.MoveTo(114.411, 330) d.LineTo(1055.589, 330) return 1170 } d.charTable['B'] = func() float64 { d.MoveTo(0, 0) d.LineTo(0, 1500) d.LineTo(620, 1500) t := d.Arc(350, 350, 0, 180, 0) b := d.Arc(400, 400, 0, 180, 0) _, _, x, y := d.DrawPathOriginAtStart(620, 1500, t) d.DrawPathOriginAtStart(x, y, b) d.LineTo(0, 0) d.MoveTo(x, y) d.LineTo(0, y) return x + 400 } d.charTable['C'] = func() float64 { a := 25.0 points := d.Arc(1140/2, 1540/2, 90+a, 90-a, 0) x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 1500/2, points) return x - 20 } d.charTable['D'] = func() float64 { d.MoveTo(460, 0) d.LineTo(0, 0) d.LineTo(0, 1500) d.LineTo(460, 1500) points := d.Arc(1120/2, 1500/2, 0, 180, 0) d.DrawPathOriginAtStart(460, 1500, points) return 460 + 1120/2 - 20 } d.charTable['E'] = func() float64 { d.MoveTo(1000, 0) d.LineTo(0, 0) d.LineTo(0, 1500) d.LineTo(1000, 1500) d.MoveTo(0, 800) d.LineTo(670, 800) return 1000 } d.charTable['F'] = func() float64 { d.MoveTo(0, 0) d.LineTo(0, 1500) d.LineTo(1000, 1500) d.MoveTo(0, 800) d.LineTo(670, 800) return 1000 } d.charTable['G'] = func() float64 { a := 30.0 points := d.Arc(1140/2, 1540/2, 90+a, 90-a, 0) x, y, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 1500/2, points) d.MoveTo(x, y) d.LineTo(x, y+450) d.LineTo(x-380, y+450) return x } d.charTable['H'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(0, 0) d.MoveTo(1000, 1500) d.LineTo(1000, 0) d.MoveTo(0, 800) d.LineTo(1000, 800) return 1000 } d.charTable['I'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(0, 0) return 1 } d.charTable['J'] = func() float64 { points := d.Arc(740/2, 1000/2, 90, 270, 0) x, y, _, _ := d.DrawPathOriginAtStart(740, 480, points) d.MoveTo(x, y) d.LineTo(x, 1500) return 740 } d.charTable['K'] = func() float64 { d.Line(0, 0, 0, 1500) d.Line(0, 558, 1000, 1500) // upper leg 560,1000 d.Line(370, 906.54, 1000, 0) // lower leg return 1000 } d.charTable['L'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(0, 0) d.LineTo(1000, 0) return 1000 } d.charTable['M'] = func() float64 { d.MoveTo(0, 0) d.LineTo(0, 1500) d.LineTo(100, 1500) d.LineTo(630, 0) d.LineTo(1160, 1500) d.LineTo(1260, 1500) d.LineTo(1260, 0) return 1260 } d.charTable['N'] = func() float64 { d.MoveTo(0, 0) d.LineTo(0, 1500) d.LineTo(75, 1500) d.LineTo(916, 0) d.LineTo(991, 0) d.LineTo(991, 1500) return 991 } d.charTable['O'] = func() float64 { points := d.Arc(1140/2, 1540/2, 0, 0, 0) d.DrawPathOriginAtCenter(1100/2, 1500/2, points) return 1100 } d.charTable['P'] = func() float64 { d.MoveTo(0, 0) d.LineTo(0, 1500) d.LineTo(550, 1500) points := d.Arc(780/2, 780/2, 0, 180, 0) _, _, x, y := d.DrawPathOriginAtStart(550, 1500, points) d.MoveTo(x, y) d.LineTo(0, y) return 550 + 780/2 } d.charTable['Q'] = func() float64 { points := d.Arc(1140/2, 1540/2, 150, 150, 0) _, _, x, y := d.DrawPathOriginAtCenter(-points.Left(), 1500/2, points) j := LineByAngleAndAzimuith(150, 250) sx, sy, ex, ey := d.DrawPathOriginAtCenter(x, y, j) p2 := d.Arc(300/2, 300/2, 10, 150-90, 0) d.DrawPathOriginAtEnd(sx, sy, p2) p3 := d.Arc(300/2, 300/2, 10, 150-90, 180) d.DrawPathOriginAtEnd(ex, ey, p3) return points.Width() } d.charTable['R'] = func() float64 { d.MoveTo(0, 0) d.LineTo(0, 1500) d.LineTo(670, 1500) points := d.Arc(750/2, 750/2, 0, 180, 0) _, _, x, y := d.DrawPathOriginAtStart(670, 1500, points) d.MoveTo(x, y) d.LineTo(0, y) d.MoveTo(x, y) d.LineTo(670+780/2, 0) return 670 + 780/2 } d.charTable['S'] = func() float64 { m := 10.0 e := 73.0 ex := 500.0 ey := 400.0 oy := 790.0 conn := 0.55 * ey pointsT := d.Arc(ex*.9, ey*.9, 180+m, e, 0.0) pointsB := d.Arc(ex, ey, 360+m, 180+e, 0.0) w := pointsB.Width() j := LineByAngleAndAzimuith(m+90, conn) d.DrawPathOriginAtCenter(w/2-20, oy, j) je := j.End() js := j.Start() d.DrawPathOriginAtStart(js.X+w/2-20, js.Y+oy, pointsT) d.DrawPathOriginAtStart(je.X+w/2-20, je.Y+oy, pointsB) return w - 40 } d.charTable['T'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(1200, 1500) d.MoveTo(600, 1500) d.LineTo(600, 0) return 1200 } d.charTable['U'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(0, 0+750/2-20) p := d.Arc(1000/2, 750/2, 90, 270, 0.0) x, y, _, _ := d.DrawPathOriginAtEnd(0, 0+750/2-20, p) d.MoveTo(x, 1500) d.LineTo(x, y) return x } d.charTable['V'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(600, 0) d.LineTo(1200, 1500) return 1200 } d.charTable['W'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(400, 0) d.LineTo(800, 1500) d.LineTo(1200, 0) d.LineTo(1600, 1500) return 1600 } d.charTable['X'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(1050, 0) d.MoveTo(1050, 1500) d.LineTo(0, 0) return 1050 } d.charTable['Y'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(1120/2, 760) d.MoveTo(1120, 1500) d.LineTo(1120/2, 760) d.LineTo(1120/2, 0) return 1120 } d.charTable['Z'] = func() float64 { d.MoveTo(0, 1500) d.LineTo(1000, 1500) d.LineTo(0, 0) d.LineTo(1000, 0) return 1000 } d.charTable['&'] = func() float64 { oy := 820.0 a := 15.0 pointsT := d.Arc(970/2, 680/2, 180, 180, 0.0) pointsB := d.Arc(1100/2, 820/2, 90+a, 360, 0.0) pointsF1 := d.Arc(1550/2, 1650/2, 0, 90, 0.0) pointsF2 := d.Arc(1240/2, 1240/2, 270+a, 330, 0.0) w := 1100.0 d.DrawPathOriginAtStart(w/2, oy, pointsT) x, y, _, _ := d.DrawPathOriginAtEnd(w/2, oy, pointsB) d.DrawPathOriginAtStart(w/2, oy, pointsF1) d.DrawPathOriginAtStart(x, y, pointsF2) return pointsF2.Width() + x } } func (d *drawer) dumpCharTable() { for r, f := range d.charTable { fmt.Printf("%s %0.2f\n",string(r),f()) } } func (d *drawer) drawChar(char rune) float64 { if d.charTable[char] != nil { return d.charTable[char]() } return 0.0 } func LineByAngleAndAzimuith(angle float64, l float64) Path { angle = radians(angle) return Path{ points: []Point{ Point{ X: -math.Sin(angle) * l / 2, Y: -math.Cos(angle) * l / 2, }, Point{ X: math.Sin(angle) * l / 2, Y: math.Cos(angle) * l / 2, }, }, } } func degrees(x float64) float64 { return x / (math.Pi / 180) } func EllipseByTwoPathAndCenter(cx, cy, p1x, p1y, p2x, p2y, t float64) (float64, float64) { t = radians(t) return cx + math.Sin(t)*(p1x-cx) + math.Cos(t)*(p2x-cx), cy + math.Sin(t)*(p1y-cy) + math.Cos(t)*(p2y-cy) } func EllipseByThreePath(bx, by, cx, cy, dx, dy, t float64) (float64, float64) { t = radians(t) x := 0.5*dx + 0.5*bx + math.Sin(t)*(0.5*bx-0.5*dx) + math.Cos(t)*(cx-0.5*dx-0.5*bx) y := 0.5*dy + 0.5*by + math.Sin(t)*(0.5*by-0.5*dy) + math.Cos(t)*(cy-0.5*dy-0.5*by) return x, y } func a(x, y float64) { } func radians(x float64) float64 { return x * math.Pi / 180 } type drawer struct { skew float64 c *draw2dimg.GraphicContext tx float64 ty float64 scale float64 charTable map[rune]func() float64 } func (d *drawer) SetLineWidth(w float64) { d.c.SetLineWidth(w) } func (d *drawer) SetXHeight(h float64) { d.scale = h / 1000 } func (d *drawer) Line(x1, y1, x2, y2 float64) { d.MoveTo(x1, y1) d.LineTo(x2, y2) } func (d *drawer) Translate(x, y float64) { d.tx = x d.ty = y } func (d *drawer) AdvanceX(x float64) { d.tx += x } func (d *drawer) AdvanceY(y float64) { d.ty += y } func (d *drawer) transform(x, y float64) (float64, float64) { return (d.tx + x + (500-y)*d.skew) * d.scale, (d.ty + (500 - y)) * d.scale } func (d *drawer) MoveTo(x, y float64) { d.c.MoveTo(d.transform(x, y)) } func (d *drawer) LineTo(x, y float64) { d.c.LineTo(d.transform(x, y)) } func (d *drawer) Close() { } func (d *drawer) Stroke() { d.c.Stroke() } func (d *drawer) Mark(x, y float64) { saveX, saveY := d.c.LastPoint() s := 10.0 d.MoveTo(x-s, y-s) d.LineTo(x+s, y+s) d.MoveTo(x+s, y-s) d.LineTo(x-s, y+s) d.MoveTo(saveX, saveY) } func rotate(x, y, a float64) (float64, float64) { s := math.Sin(a) c := math.Cos(a) xr := x*c - y*s yr := x*s + y*c return xr, yr } func ellipsify(θ float64, a float64, b float64) float64 { θ = math.Mod(θ, 2*math.Pi) negative := false if θ < 0.0 { negative = true θ = -θ } θo := math.Atan(a / b * math.Tan(θ)) θc := θo if θ > math.Pi/2 && θ <= 1.5*math.Pi { θc = math.Pi + θo } else { θc = math.Mod(2*math.Pi+θo, 2*math.Pi) } if negative { θc = -θc } // fmt.Printf("θ %0.2f θo %0.2f θc %0.2f\n",degrees(θ),degrees(θo),degrees(θc)) return θc } type Paths []Path type Point struct { X float64 Y float64 } type Path struct { points []Point } func line(a Point, b Point) (float64, float64) { slope := (b.Y - a.Y) / (b.X - a.X) yint := a.Y - slope*a.X return slope, yint } func intersection(l1a Point, l1b Point, l2a Point, l2b Point) (Point, error) { l1Slope, l1Yint := line(l1a, l1b) l2Slope, l2Yint := line(l2a, l2b) if l1Slope == l2Slope { return Point{}, fmt.Errorf("The lines do not intersect") } e := (l2Yint - l1Yint) / (l1Slope - l2Slope) n := l1Slope*e + l1Yint return Point{X: e, Y: n}, nil } func (p *Path) Start() Point { return Point{X: p.points[0].X, Y: p.points[0].Y} } func (p *Path) End() Point { return Point{X: p.points[len(p.points)-1].X, Y: p.points[len(p.points)-1].Y} } func (p *Path) Left() float64 { minX := p.points[0].X for i := 0; i < len(p.points); i++ { if p.points[i].X < minX { minX = p.points[i].X } } return minX } func (p *Path) Width() float64 { minX := p.points[0].X maxX := minX for i := 0; i < len(p.points); i++ { if p.points[i].X < minX { minX = p.points[i].X } if p.points[i].X > maxX { maxX = p.points[i].X } } return maxX - minX } func (p *Path) Height() float64 { minY := p.points[0].Y maxY := minY for i := 0; i < len(p.points); i++ { if p.points[i].Y < minY { minY = p.points[i].Y } if p.points[i].Y > maxY { maxY = p.points[i].Y } } return maxY - minY } func (p *Path) Append(x, y float64) { p.points = append(p.points, Point{X: x, Y: y}) } func (d *drawer) DrawPathOriginAtCenter(x, y float64, points Path) (startX, startY, endX, endY float64) { o := Point{} for i, p := range points.points { if i == 0 { d.MoveTo(p.X-o.X+x, p.Y-o.Y+y) } else { d.LineTo(p.X-o.X+x, p.Y-o.Y+y) } } start := points.points[0] end := points.points[len(points.points)-1] return start.X - o.X + x, start.Y - o.Y + y, end.X - o.X + x, end.Y - o.Y + y } func (d *drawer) DrawPathOriginAtStart(x, y float64, points Path) (startX, startY, endX, endY float64) { o := points.points[0] for i, p := range points.points { if i == 0 { d.MoveTo(p.X-o.X+x, p.Y-o.Y+y) } else { d.LineTo(p.X-o.X+x, p.Y-o.Y+y) } } end := points.points[len(points.points)-1] return x, y, end.X - o.X + x, end.Y - o.Y + y } func (d *drawer) DrawPathOriginAtEnd(x, y float64, points Path) (startX, startY, endX, endY float64) { o := points.End() for i := len(points.points) - 1; i >= 0; i-- { p := points.points[i] if i == len(points.points)-1 { d.MoveTo(p.X-o.X+x, p.Y-o.Y+y) } else { d.LineTo(p.X-o.X+x, p.Y-o.Y+y) } } start := points.points[0] return start.X - o.X + x, start.Y - o.Y + y, x, y } // Arc computes a rotated circle or ellipse, and returns the points // x,y = center // a,b = ellipse semi-axes // start = start angle, 0° = up // end = end angle, 0° = up // rot = rotation angle of ellipse, clockwise // The arc is drawn between start and end. If end < start, the arc is drawn between end and start. // start=0,end=90 draws a 90 degree arc segment between 0 and 90 // start=90,end=0 draws a 270 degree arc segment between 90 and 0 func (d *drawer) Arc(a, b, start, end, rot float64) Path { rot = radians(rot) if math.Mod(start, 360) == math.Mod(end, 360) { // closed arc start = radians(start) end = start + 2*math.Pi } else { // adjust arc end angles to draw tangent angles start = ellipsify(radians(start), a, b) end = ellipsify(radians(end), a, b) } if start > end { // drawing counter-clockwise end = end + 2*math.Pi } ra := (math.Abs(a) + math.Abs(b)) / 2 da := math.Acos(ra/(ra+0.125)) * 2 angle := start startX, startY := roticate(a, b, start, 0, 0, rot) points := Path{points: []Point{Point{startX, startY}}} var cua, cub float64 i := 0 for { if angle > end-da/4 { cua, cub = roticate(a, b, end, 0, 0, rot) points.points = append(points.points, Point{cua, cub}) return points } cua, cub = roticate(a, b, angle, 0, 0, rot) angle += da points.points = append(points.points, Point{cua, cub}) i++ } } func roticate(a, b, θ, offx, offy, rot float64) (float64, float64) { x := math.Sin(θ) * a y := math.Cos(θ) * b s := math.Sin(-rot) c := math.Cos(-rot) xr := x*c - y*s + offx yr := x*s + y*c + offy return xr, yr } type renderedGlyph struct { path Path width float64 } type capturer struct { skew float64 scale float64 glyphs map[rune]renderedGlyph paths Paths path Path } func (d *capturer) SetXHeight(h float64) { d.scale = h / 1000 } func (d *capturer) Line(x1, y1, x2, y2 float64) { d.MoveTo(x1, y1) d.LineTo(x2, y2) } func (d *capturer) transform(x, y float64) (float64, float64) { return (x + (500-y)*d.skew) * d.scale, (500-y)* d.scale } func (d *capturer) MoveTo(x, y float64) { if len(d.path.points)>1 { d.paths = append(d.paths,d.path) fmt.Println("saving path", len(d.paths)) } d.path = Path{points:[]Point{Point{X:x, Y:y}}} } func (d *capturer) LineTo(x, y float64) { d.path.Append(x,y) } func (d *capturer) Close() { if len(d.path.points)>1 { d.paths = append(d.paths,d.path) fmt.Println("saving path", len(d.paths)) } d.path = Path{} } func (d *capturer) DumpPaths() { fmt.Println(d.paths) d.paths=make(Paths,0) }