No Description

linefont.go 30KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. package main
  2. import (
  3. "github.com/llgcode/draw2d"
  4. "github.com/llgcode/draw2d/draw2dimg"
  5. "fmt"
  6. "github.com/llgcode/draw2d/draw2dkit"
  7. "image"
  8. "image/color"
  9. "math"
  10. )
  11. func main() {
  12. fmt.Println("hi")
  13. w := 2500.0
  14. h := 1300.0
  15. dest := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))
  16. dc := draw2dimg.NewGraphicContext(dest)
  17. dc.SetFillColor(color.RGBA{255, 255, 255, 0xff})
  18. draw2dkit.Rectangle(dc, 0, 0, w, h)
  19. dc.Fill()
  20. dc.SetLineCap(draw2d.RoundCap)
  21. dc.SetLineJoin(draw2d.RoundJoin)
  22. dc.Translate(100, h/2)
  23. //dc.Scale(.5, .5)
  24. dc.SetStrokeColor(color.RGBA{0, 0, 0, 0xff})
  25. d := &drawer{
  26. c: dc,
  27. skew: -1 * math.Tan(radians(22.5)), //-1*math.Tan(radians(22.5))
  28. }
  29. cap := &capturer{
  30. skew: -1 * math.Tan(radians(22.5)), //-1*math.Tan(radians(22.5))
  31. paths: make(Paths,0),
  32. path: Path{points:make([]Point,0)},
  33. }
  34. fmt.Println(cap)
  35. d.InitCharTable()
  36. d.dumpCharTable()
  37. //d.skew = 0.0
  38. //
  39. // d.Translate(0, 0)
  40. //
  41. // dc.SetLineWidth(.5)
  42. //x height
  43. // d.MoveTo(-2*w, 1500)
  44. // d.LineTo(2*w, 1500)
  45. // d.Stroke()
  46. //
  47. // x height
  48. // d.MoveTo(-2*w, 1000)
  49. // d.LineTo(2*w, 1000)
  50. // d.Stroke()
  51. //
  52. // left
  53. // d.MoveTo(0, -2*h)
  54. // d.LineTo(0, 2*w)
  55. // d.Stroke()
  56. //
  57. // right lowercase
  58. // d.MoveTo(385*2, -2*h)
  59. // d.LineTo(385*2, 2*w)
  60. // d.Stroke()
  61. //
  62. // right uppercase
  63. // d.MoveTo(1170, -2*h)
  64. // d.LineTo(1170, 2*w)
  65. // d.Stroke()
  66. //
  67. // baseline
  68. // d.MoveTo(-2*w, 0)
  69. // d.LineTo(2*w, 0)
  70. // d.Stroke()
  71. //abcdefghijklmnopqrstuvwxyz
  72. kerntable := map[rune]map[rune]float64{
  73. 'A': map[rune]float64{
  74. '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,
  75. },
  76. 'E': map[rune]float64{
  77. '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,
  78. },
  79. 'F': map[rune]float64{
  80. '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,
  81. },
  82. 'K': map[rune]float64{
  83. '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,
  84. },
  85. 'L': map[rune]float64{
  86. '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,
  87. },
  88. 'P': map[rune]float64{
  89. 'a': -100.0, 'c': -100.0, 'd': -100.0, 'e': -100.0, 'g': -100.0, 'o': -100.0, 'q': -100.0, 's': -100.0,
  90. },
  91. 'R': map[rune]float64{
  92. 'a': -100.0, 'c': -100.0, 'd': -100.0, 'e': -100.0, 'g': -100.0, 'o': -100.0, 'q': -100.0, 's': -100.0,
  93. },
  94. 'T': map[rune]float64{
  95. '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,
  96. },
  97. 'V': map[rune]float64{
  98. '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,
  99. },
  100. 'W': map[rune]float64{
  101. '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,
  102. },
  103. 'X': map[rune]float64{
  104. '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,
  105. },
  106. 'Y': map[rune]float64{
  107. '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,
  108. },
  109. 'Z': map[rune]float64{
  110. '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,
  111. },
  112. 'f': map[rune]float64{
  113. 'f': -100.0,
  114. },
  115. 'i': map[rune]float64{
  116. 'i': 100.0,
  117. 'l': 100.0,
  118. 't': 100.0,
  119. },
  120. 'k': map[rune]float64{
  121. 'a': -100.0, 'c': -100.0, 'd': -100.0, 'e': -100.0, 'g': -100.0, 'o': -100.0, 'q': -100.0, 's': -100.0,
  122. },
  123. 'l': map[rune]float64{
  124. 'i': 100.0,
  125. 'l': 100.0,
  126. 't': 100.0,
  127. },
  128. }
  129. var cw float64
  130. lineWidth := 2.5
  131. dc.SetLineWidth(lineWidth)
  132. d.SetXHeight(24.0)
  133. d.skew = -1 * math.Tan(radians(22.5))
  134. //str1 := "the quick brown fox jumps over the lazy dog"
  135. // str2 := "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"
  136. // 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"
  137. // d.Translate(0, 0)
  138. //
  139. // for _, c := range str1 {
  140. // cw = d.drawChar(c)
  141. // d.AdvanceX(cw + 300 + lineWidth)
  142. // }
  143. // d.Translate(0, 2500)
  144. // for _, c := range str2 {
  145. // cw = d.drawChar(c)
  146. // d.AdvanceX(cw + 300 + lineWidth)
  147. // }
  148. // yoff := -20000.0
  149. // for _, C := range "abcdefghijklmnopqrstuvwxyz" {
  150. // d.Translate(0, yoff)
  151. // yoff += 2500
  152. // for _, c := range "abcdefghijklmnopqrstuvwxyz" {
  153. // cw = d.drawChar(C)
  154. // d.AdvanceX(cw + 300 + lineWidth + kerntable[C][c])
  155. // cw = d.drawChar(c)
  156. // d.AdvanceX(cw + 300 + lineWidth)
  157. // cw = d.drawChar(' ')
  158. // d.AdvanceX(cw + 300 + lineWidth)
  159. // }
  160. // }
  161. var last rune
  162. tx := 0.0
  163. lines := 1.0
  164. 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°#$%*" {
  165. if last != 0 {
  166. cw = d.drawChar(last)
  167. cw += kerntable[last][c]
  168. d.AdvanceX(cw + 400)
  169. tx += cw + 400
  170. if tx > 50000 {
  171. d.Translate(0, lines*2500.0)
  172. tx = 0
  173. lines++
  174. }
  175. }
  176. last = c
  177. }
  178. d.drawChar(last)
  179. dc.Stroke()
  180. draw2dimg.SaveToPngFile("ellipse.png", dest)
  181. }
  182. func (d *drawer) InitCharTable() {
  183. d.charTable = make(map[rune]func() float64)
  184. d.charTable[' '] = func() float64 {
  185. return 385
  186. }
  187. d.charTable['a'] = func() float64 {
  188. points := d.Arc(385, 520, 120, 60, 0)
  189. x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points)
  190. d.Line(x, 0, x, 1000)
  191. return x
  192. }
  193. d.charTable['b'] = func() float64 {
  194. points := d.Arc(385, 520, 300, 240, 0)
  195. d.DrawPathOriginAtCenter(-points.Left(), 500, points)
  196. d.Line(0, 0, 0, 1500)
  197. return points.Width() - 20
  198. }
  199. d.charTable['c'] = func() float64 {
  200. points := d.Arc(385, 520, 130, 50, 0)
  201. x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points)
  202. return x
  203. }
  204. d.charTable['d'] = func() float64 {
  205. points := d.Arc(385, 520, 120, 60, 0)
  206. x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points)
  207. d.Line(x, 0, x, 1500)
  208. return x
  209. }
  210. d.charTable['e'] = func() float64 {
  211. points := d.Arc(385, 520, 135, 85, 0)
  212. _, _, _, y := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points)
  213. w := points.Width()
  214. d.LineTo(w-2*points.End().X-20, y)
  215. return w - 40
  216. }
  217. d.charTable['f'] = func() float64 {
  218. d.Line(130, 0, 130, 1300)
  219. points := d.Arc(200, 200, 270, 35, 0)
  220. _, _, x, _ := d.DrawPathOriginAtStart(130, 1300, points)
  221. d.Line(-100, 1000, 400, 1000)
  222. return x - 150
  223. }
  224. d.charTable['g'] = func() float64 {
  225. points := d.Arc(385, 520, 120, 60, 0)
  226. x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points)
  227. points2 := d.Arc(300, 320, 90, 220, 0)
  228. g := points2.Height()
  229. d.Line(x, -400+g, x, 1000)
  230. d.DrawPathOriginAtStart(x, -400+g, points2)
  231. return x
  232. }
  233. d.charTable['h'] = func() float64 {
  234. d.Line(0, 1500, 0, 0)
  235. r := -25.0
  236. points := d.Arc(700/2, 550/2, 270.0-r, 90-r, r)
  237. _, _, x2, y2 := d.DrawPathOriginAtStart(0, 680, points)
  238. d.Line(x2, y2, x2, 0)
  239. return x2
  240. }
  241. d.charTable['i'] = func() float64 {
  242. d.Line(0, 1000, 0, 0)
  243. d.Line(0, 1350, 0, 1500)
  244. return 1
  245. }
  246. d.charTable['j'] = func() float64 {
  247. o := 200.0
  248. points := d.Arc(370/2, 370/2, 90, 190, 0)
  249. w := points.Width()
  250. d.DrawPathOriginAtStart(w-o, -400+points.Height(), points)
  251. d.Line(w-o, 1000, w-o, -400+points.Height())
  252. d.Line(w-o, 1350, w-o, 1500)
  253. return w
  254. }
  255. d.charTable['k'] = func() float64 {
  256. d.Line(0, 0, 0, 1500)
  257. d.Line(0, 410, 572, 616+410) // upper leg 560,1000
  258. d.Line(260, 690, 624, 0) // lower leg
  259. return 624
  260. }
  261. d.charTable['l'] = func() float64 {
  262. d.MoveTo(0, 1500)
  263. d.LineTo(0, 0)
  264. return 1
  265. }
  266. d.charTable['m'] = func() float64 {
  267. d.Line(0, 0, 0, 1000)
  268. r := -25.0
  269. points := d.Arc(700/2, 550/2, 270.0-r, 90-r, r)
  270. _, _, x, y := d.DrawPathOriginAtStart(0, 680, points)
  271. d.Line(x, 0, x, y)
  272. _, _, x, y = d.DrawPathOriginAtStart(x, 680, points)
  273. d.Line(x, 0, x, y)
  274. return x
  275. }
  276. d.charTable['n'] = func() float64 {
  277. d.Line(0, 0, 0, 1000)
  278. r := -25.0
  279. points := d.Arc(700/2, 550/2, 270.0-r, 90-r, r)
  280. _, _, x, y := d.DrawPathOriginAtStart(0, 680, points)
  281. d.Line(x, 0, x, y)
  282. return x
  283. }
  284. d.charTable['o'] = func() float64 {
  285. points := d.Arc(385, 520, 0, 360, 0)
  286. d.DrawPathOriginAtCenter(385-20, 500, points)
  287. return points.Width() - 40
  288. }
  289. d.charTable['p'] = func() float64 {
  290. points := d.Arc(385, 520, 300, 240, 0)
  291. d.DrawPathOriginAtCenter(-points.Left(), 500, points)
  292. d.Line(0, -500, 0, 1000)
  293. return points.Width() - 20
  294. }
  295. d.charTable['q'] = func() float64 {
  296. points := d.Arc(385, 520, 120, 60, 0)
  297. x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 500, points)
  298. d.Line(x, -500, x, 1000)
  299. return points.Width() - 20
  300. }
  301. d.charTable['r'] = func() float64 {
  302. r := 20.0
  303. points := d.Arc(290, 490, 270.0-r, 360.0-r, r)
  304. d.DrawPathOriginAtStart(0, 380, points)
  305. d.Line(0, 0, 0, 1000)
  306. return points.Width()
  307. }
  308. d.charTable['s'] = func() float64 {
  309. m := 10.0
  310. e := 73.0
  311. ex := 340.0
  312. ey := 270.0
  313. oy := 527.0
  314. pointsT := d.Arc(ex*.9, ey*.9, 180+m, e, 0.0)
  315. pointsB := d.Arc(ex, ey, 360+m, 180+e, 0.0)
  316. w := pointsB.Width()
  317. j := LineByAngleAndAzimuith(m+90, 140)
  318. d.DrawPathOriginAtCenter(w/2-20, oy, j)
  319. je := j.End()
  320. js := j.Start()
  321. d.DrawPathOriginAtStart(js.X+w/2-20, js.Y+oy, pointsT)
  322. d.DrawPathOriginAtStart(je.X+w/2-20, je.Y+oy, pointsB)
  323. return w - 40
  324. }
  325. d.charTable['t'] = func() float64 {
  326. d.Line(80, 0, 80, 1300)
  327. d.Line(-150, 1000, 310, 1000)
  328. return 310
  329. }
  330. d.charTable['u'] = func() float64 {
  331. r := -25.0
  332. points := d.Arc(700/2, 550/2, 90-r, 270-r, r)
  333. w := points.Width()
  334. _, _, x, y := d.DrawPathOriginAtStart(w, 320, points)
  335. d.Line(w, 0, w, 1000)
  336. d.Line(x, 1000, x, y)
  337. return w
  338. }
  339. d.charTable['v'] = func() float64 {
  340. d.MoveTo(0, 1000)
  341. d.LineTo(320, 0)
  342. d.LineTo(370, 0)
  343. d.LineTo(690, 1000)
  344. return 690
  345. }
  346. d.charTable['w'] = func() float64 {
  347. d.MoveTo(0, 1000)
  348. d.LineTo(320, 0)
  349. d.LineTo(370, 0)
  350. d.LineTo(658, 900)
  351. d.LineTo(708, 900)
  352. d.LineTo(996, 0)
  353. d.LineTo(1046, 0)
  354. d.LineTo(1366, 1000)
  355. return 1366
  356. }
  357. d.charTable['x'] = func() float64 {
  358. d.Line(0, 0, 670, 1000)
  359. d.Line(670, 0, 0, 1000)
  360. return 670
  361. }
  362. d.charTable['y'] = func() float64 {
  363. d.MoveTo(0, 1000)
  364. d.LineTo(320, 0)
  365. d.MoveTo(640, 1000)
  366. ex, ey := 320.0-32.0, -100.0
  367. d.LineTo(ex, ey)
  368. points := d.Arc(200, 200, 108.6629, 200, 0)
  369. d.DrawPathOriginAtStart(ex, ey, points)
  370. return 670
  371. }
  372. d.charTable['z'] = func() float64 {
  373. d.MoveTo(0, 1000)
  374. d.LineTo(670, 1000)
  375. d.LineTo(0, 0)
  376. d.LineTo(670, 0)
  377. return 670
  378. }
  379. d.charTable['('] = func() float64 {
  380. points := d.Arc(1500, 1500, 234, 306, 0)
  381. w := points.Width()
  382. d.DrawPathOriginAtStart(w, -180, points)
  383. return w
  384. }
  385. d.charTable[')'] = func() float64 {
  386. points := d.Arc(1500, 1500, 54, 126, 0)
  387. w := points.Width()
  388. d.DrawPathOriginAtEnd(0, -180, points)
  389. return w
  390. }
  391. d.charTable['%'] = func() float64 {
  392. cw := 550.0
  393. points := d.Arc(cw/2, cw/2, 0, 360, 0)
  394. d.DrawPathOriginAtCenter(cw/2, 1500-cw/2, points)
  395. d.DrawPathOriginAtCenter(800+cw/2, cw/2, points)
  396. d.Line(cw/2, 0, 800+cw/2, 1500)
  397. return 800 + cw
  398. }
  399. d.charTable['°'] = func() float64 {
  400. cw := 500.0
  401. points := d.Arc(cw/2, cw/2, 0, 360, 0)
  402. d.DrawPathOriginAtCenter(cw/2, 1500-cw/2, points)
  403. return cw
  404. }
  405. d.charTable['"'] = func() float64 {
  406. d.Line(0, 1500, 0, 1000)
  407. d.Line(400, 1500, 400, 1000)
  408. return 400
  409. }
  410. d.charTable['\''] = func() float64 {
  411. d.Line(0, 1500, 0, 1000)
  412. return 200
  413. }
  414. d.charTable['#'] = func() float64 {
  415. w := 1000.0
  416. h := 1500.0
  417. s := 350.0
  418. slant := 200.0
  419. scaledSlant := slant / h * s
  420. d.Line(-scaledSlant, -s/2+h/2, w-scaledSlant, -s/2+h/2)
  421. d.Line(scaledSlant, s/2+h/2, w+scaledSlant, +s/2+h/2)
  422. d.Line(-s/2+w/2-slant, 0, -s/2+w/2+slant, h)
  423. d.Line(s/2+w/2-slant, 0, s/2+w/2+slant, h)
  424. return w
  425. }
  426. d.charTable['$'] = func() float64 {
  427. m := 10.0 // angle where curves meet
  428. e := 73.0 // angle at ends of curves
  429. ey := 300.0
  430. ex := ey * 1.2593
  431. oy := 1500.0 * 1 / (1 + .9)
  432. pointsT := d.Arc(ex*.9, ey*.9, 180+m, e, 0.0)
  433. pointsB := d.Arc(ex, ey, 360+m, 180+e, 0.0)
  434. w := pointsB.Width()
  435. j := LineByAngleAndAzimuith(m+90, 140)
  436. d.DrawPathOriginAtCenter(w/2-20, oy, j)
  437. je := j.End()
  438. js := j.Start()
  439. d.DrawPathOriginAtStart(js.X+w/2-20, js.Y+oy, pointsT)
  440. d.DrawPathOriginAtStart(je.X+w/2-20, je.Y+oy, pointsB)
  441. d.Line(w/2-20, 0, w/2-20, 1500)
  442. return w - 40
  443. }
  444. d.charTable['*'] = func() float64 {
  445. hoff := 200.0
  446. dia := 700.0
  447. rad := dia / 2
  448. voff := 1500.0 - rad
  449. d.Line(hoff, voff+rad, hoff, voff-rad) // |
  450. dx := rad * .86
  451. dy := rad * .5
  452. d.Line(-dx+hoff, -dy+voff, dx+hoff, dy+voff) // -
  453. d.Line(-dx+hoff, dy+voff, dx+hoff, -dy+voff) // -
  454. return dx * 1.3
  455. }
  456. d.charTable['='] = func() float64 {
  457. d.Line(0, 570, 550, 570)
  458. d.Line(0, 570+350, 550, 570+350)
  459. return 550
  460. }
  461. d.charTable['.'] = func() float64 {
  462. points := d.Arc(50, 50, 0, 360, 0)
  463. d.DrawPathOriginAtCenter(0, 50, points)
  464. return 1
  465. }
  466. d.charTable[','] = func() float64 {
  467. a := 20.0
  468. points := d.Arc(50, 50, 0, 360, 90+a)
  469. _, _, x, y := d.DrawPathOriginAtCenter(0, 50, points)
  470. p2 := LineByAngleAndAzimuith(180+a, 300)
  471. d.DrawPathOriginAtStart(x, y, p2)
  472. return 100
  473. }
  474. d.charTable['-'] = func() float64 {
  475. d.Line(0, 750, 500, 750)
  476. return 500
  477. }
  478. d.charTable['–'] = func() float64 { // en dash
  479. d.Line(0, 750, 750, 750)
  480. return 750
  481. }
  482. d.charTable['—'] = func() float64 { // em dash
  483. d.Line(0, 750, 1500, 750)
  484. return 1500
  485. }
  486. d.charTable['0'] = func() float64 {
  487. points := d.Arc(550, 750, 0, 360, 0)
  488. d.DrawPathOriginAtCenter(550, 750, points)
  489. return points.Width()
  490. }
  491. d.charTable['1'] = func() float64 {
  492. d.MoveTo(150, 1500)
  493. d.LineTo(150, 0)
  494. return 300
  495. }
  496. d.charTable['2'] = func() float64 {
  497. a := 60.0
  498. p1 := d.Arc(470, 390, 270, 90+a, 0.0)
  499. p2 := d.Arc(500, 600, 270, 270+a, 0.0)
  500. p3 := LineByAngleAndAzimuith(a, 500)
  501. w := p1.Width() + 50
  502. d.MoveTo(w, 0)
  503. d.LineTo(0, 0)
  504. _, _, x, y := d.DrawPathOriginAtStart(0, 0, p2)
  505. _, _, x, y = d.DrawPathOriginAtStart(x, y, p3)
  506. d.DrawPathOriginAtEnd(x, y, p1)
  507. return w
  508. }
  509. d.charTable['3'] = func() float64 {
  510. a := 70.0
  511. p2 := d.Arc(2300/2, 1450/2, 95, 90+a, 0.0)
  512. p1 := d.Arc(1000/2, 960/2, 270+a, 250, 0.0)
  513. x, y, _, _ := d.DrawPathOriginAtEnd(0, 300, p1)
  514. x, y, _, _ = d.DrawPathOriginAtEnd(x, y, p2)
  515. d.MoveTo(x, y)
  516. d.LineTo(0, y)
  517. return p1.Width()
  518. }
  519. d.charTable['4'] = func() float64 {
  520. d.MoveTo(830, 0)
  521. d.LineTo(830, 1500)
  522. d.LineTo(700, 1500)
  523. d.LineTo(0, 650)
  524. d.LineTo(0, 520)
  525. d.LineTo(1110, 520)
  526. return 1110
  527. }
  528. d.charTable['5'] = func() float64 {
  529. p1 := d.Arc(1000/2, 1010/2, 305, 240, 0.0)
  530. p2 := LineByAngleAndAzimuith(7, 720)
  531. x, y, _, _ := d.DrawPathOriginAtEnd(0, 230, p1)
  532. _, _, x, y = d.DrawPathOriginAtStart(x, y, p2)
  533. d.MoveTo(x, y)
  534. d.LineTo(x+700, y)
  535. return p1.Width()
  536. }
  537. d.charTable['6'] = func() float64 {
  538. a := 90.0
  539. p1 := d.Arc(960/2, 810/2, 270, 270-a, 0.0)
  540. p2 := d.Arc(1100/2, 1500/2, 270-a, 50, 0.0)
  541. p3 := LineByAngleAndAzimuith(-a, 0)
  542. _, _, x, y := d.DrawPathOriginAtCenter(960/2+70, 810/2, p1)
  543. _, _, x, y = d.DrawPathOriginAtStart(x, y, p3)
  544. d.DrawPathOriginAtStart(x, y, p2)
  545. return 900
  546. }
  547. d.charTable['7'] = func() float64 {
  548. p1 := d.Arc(2000/2, 2860/2, 270, 337, 0.0)
  549. d.MoveTo(0, 1500)
  550. d.LineTo(1050, 1500)
  551. d.LineTo(1050, 1500-130)
  552. d.DrawPathOriginAtEnd(1050, 1500-130, p1)
  553. return 1050
  554. }
  555. d.charTable['8'] = func() float64 {
  556. ex := 500.0
  557. ey := 400.0
  558. oy := 790.0
  559. pointsT := d.Arc(ex*.9, ey*.9, 180, 180, 0.0)
  560. pointsB := d.Arc(ex, ey, 0, 0, 0.0)
  561. w := pointsB.Width()
  562. d.DrawPathOriginAtStart(w/2, oy, pointsT)
  563. d.DrawPathOriginAtStart(w/2, oy, pointsB)
  564. return w
  565. }
  566. d.charTable['9'] = func() float64 {
  567. a := 90.0
  568. p1 := d.Arc(960/2, 810/2, 270, 270-a, 180)
  569. p2 := d.Arc(1100/2, 1500/2, 270-a, 50, 180)
  570. p3 := LineByAngleAndAzimuith(-a, 0)
  571. _, _, x, y := d.DrawPathOriginAtCenter(960/2, 1100, p1)
  572. _, _, x, y = d.DrawPathOriginAtStart(x, y, p3)
  573. d.DrawPathOriginAtStart(x, y, p2)
  574. return 900 + 70
  575. }
  576. d.charTable['A'] = func() float64 {
  577. d.MoveTo(0, 0)
  578. d.LineTo(520, 1500)
  579. d.LineTo(520+130, 1500)
  580. d.LineTo(520+130+520, 0)
  581. d.MoveTo(114.411, 330)
  582. d.LineTo(1055.589, 330)
  583. return 1170
  584. }
  585. d.charTable['B'] = func() float64 {
  586. d.MoveTo(0, 0)
  587. d.LineTo(0, 1500)
  588. d.LineTo(620, 1500)
  589. t := d.Arc(350, 350, 0, 180, 0)
  590. b := d.Arc(400, 400, 0, 180, 0)
  591. _, _, x, y := d.DrawPathOriginAtStart(620, 1500, t)
  592. d.DrawPathOriginAtStart(x, y, b)
  593. d.LineTo(0, 0)
  594. d.MoveTo(x, y)
  595. d.LineTo(0, y)
  596. return x + 400
  597. }
  598. d.charTable['C'] = func() float64 {
  599. a := 25.0
  600. points := d.Arc(1140/2, 1540/2, 90+a, 90-a, 0)
  601. x, _, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 1500/2, points)
  602. return x - 20
  603. }
  604. d.charTable['D'] = func() float64 {
  605. d.MoveTo(460, 0)
  606. d.LineTo(0, 0)
  607. d.LineTo(0, 1500)
  608. d.LineTo(460, 1500)
  609. points := d.Arc(1120/2, 1500/2, 0, 180, 0)
  610. d.DrawPathOriginAtStart(460, 1500, points)
  611. return 460 + 1120/2 - 20
  612. }
  613. d.charTable['E'] = func() float64 {
  614. d.MoveTo(1000, 0)
  615. d.LineTo(0, 0)
  616. d.LineTo(0, 1500)
  617. d.LineTo(1000, 1500)
  618. d.MoveTo(0, 800)
  619. d.LineTo(670, 800)
  620. return 1000
  621. }
  622. d.charTable['F'] = func() float64 {
  623. d.MoveTo(0, 0)
  624. d.LineTo(0, 1500)
  625. d.LineTo(1000, 1500)
  626. d.MoveTo(0, 800)
  627. d.LineTo(670, 800)
  628. return 1000
  629. }
  630. d.charTable['G'] = func() float64 {
  631. a := 30.0
  632. points := d.Arc(1140/2, 1540/2, 90+a, 90-a, 0)
  633. x, y, _, _ := d.DrawPathOriginAtCenter(-points.Left()-20, 1500/2, points)
  634. d.MoveTo(x, y)
  635. d.LineTo(x, y+450)
  636. d.LineTo(x-380, y+450)
  637. return x
  638. }
  639. d.charTable['H'] = func() float64 {
  640. d.MoveTo(0, 1500)
  641. d.LineTo(0, 0)
  642. d.MoveTo(1000, 1500)
  643. d.LineTo(1000, 0)
  644. d.MoveTo(0, 800)
  645. d.LineTo(1000, 800)
  646. return 1000
  647. }
  648. d.charTable['I'] = func() float64 {
  649. d.MoveTo(0, 1500)
  650. d.LineTo(0, 0)
  651. return 1
  652. }
  653. d.charTable['J'] = func() float64 {
  654. points := d.Arc(740/2, 1000/2, 90, 270, 0)
  655. x, y, _, _ := d.DrawPathOriginAtStart(740, 480, points)
  656. d.MoveTo(x, y)
  657. d.LineTo(x, 1500)
  658. return 740
  659. }
  660. d.charTable['K'] = func() float64 {
  661. d.Line(0, 0, 0, 1500)
  662. d.Line(0, 558, 1000, 1500) // upper leg 560,1000
  663. d.Line(370, 906.54, 1000, 0) // lower leg
  664. return 1000
  665. }
  666. d.charTable['L'] = func() float64 {
  667. d.MoveTo(0, 1500)
  668. d.LineTo(0, 0)
  669. d.LineTo(1000, 0)
  670. return 1000
  671. }
  672. d.charTable['M'] = func() float64 {
  673. d.MoveTo(0, 0)
  674. d.LineTo(0, 1500)
  675. d.LineTo(100, 1500)
  676. d.LineTo(630, 0)
  677. d.LineTo(1160, 1500)
  678. d.LineTo(1260, 1500)
  679. d.LineTo(1260, 0)
  680. return 1260
  681. }
  682. d.charTable['N'] = func() float64 {
  683. d.MoveTo(0, 0)
  684. d.LineTo(0, 1500)
  685. d.LineTo(75, 1500)
  686. d.LineTo(916, 0)
  687. d.LineTo(991, 0)
  688. d.LineTo(991, 1500)
  689. return 991
  690. }
  691. d.charTable['O'] = func() float64 {
  692. points := d.Arc(1140/2, 1540/2, 0, 0, 0)
  693. d.DrawPathOriginAtCenter(1100/2, 1500/2, points)
  694. return 1100
  695. }
  696. d.charTable['P'] = func() float64 {
  697. d.MoveTo(0, 0)
  698. d.LineTo(0, 1500)
  699. d.LineTo(550, 1500)
  700. points := d.Arc(780/2, 780/2, 0, 180, 0)
  701. _, _, x, y := d.DrawPathOriginAtStart(550, 1500, points)
  702. d.MoveTo(x, y)
  703. d.LineTo(0, y)
  704. return 550 + 780/2
  705. }
  706. d.charTable['Q'] = func() float64 {
  707. points := d.Arc(1140/2, 1540/2, 150, 150, 0)
  708. _, _, x, y := d.DrawPathOriginAtCenter(-points.Left(), 1500/2, points)
  709. j := LineByAngleAndAzimuith(150, 250)
  710. sx, sy, ex, ey := d.DrawPathOriginAtCenter(x, y, j)
  711. p2 := d.Arc(300/2, 300/2, 10, 150-90, 0)
  712. d.DrawPathOriginAtEnd(sx, sy, p2)
  713. p3 := d.Arc(300/2, 300/2, 10, 150-90, 180)
  714. d.DrawPathOriginAtEnd(ex, ey, p3)
  715. return points.Width()
  716. }
  717. d.charTable['R'] = func() float64 {
  718. d.MoveTo(0, 0)
  719. d.LineTo(0, 1500)
  720. d.LineTo(670, 1500)
  721. points := d.Arc(750/2, 750/2, 0, 180, 0)
  722. _, _, x, y := d.DrawPathOriginAtStart(670, 1500, points)
  723. d.MoveTo(x, y)
  724. d.LineTo(0, y)
  725. d.MoveTo(x, y)
  726. d.LineTo(670+780/2, 0)
  727. return 670 + 780/2
  728. }
  729. d.charTable['S'] = func() float64 {
  730. m := 10.0
  731. e := 73.0
  732. ex := 500.0
  733. ey := 400.0
  734. oy := 790.0
  735. conn := 0.55 * ey
  736. pointsT := d.Arc(ex*.9, ey*.9, 180+m, e, 0.0)
  737. pointsB := d.Arc(ex, ey, 360+m, 180+e, 0.0)
  738. w := pointsB.Width()
  739. j := LineByAngleAndAzimuith(m+90, conn)
  740. d.DrawPathOriginAtCenter(w/2-20, oy, j)
  741. je := j.End()
  742. js := j.Start()
  743. d.DrawPathOriginAtStart(js.X+w/2-20, js.Y+oy, pointsT)
  744. d.DrawPathOriginAtStart(je.X+w/2-20, je.Y+oy, pointsB)
  745. return w - 40
  746. }
  747. d.charTable['T'] = func() float64 {
  748. d.MoveTo(0, 1500)
  749. d.LineTo(1200, 1500)
  750. d.MoveTo(600, 1500)
  751. d.LineTo(600, 0)
  752. return 1200
  753. }
  754. d.charTable['U'] = func() float64 {
  755. d.MoveTo(0, 1500)
  756. d.LineTo(0, 0+750/2-20)
  757. p := d.Arc(1000/2, 750/2, 90, 270, 0.0)
  758. x, y, _, _ := d.DrawPathOriginAtEnd(0, 0+750/2-20, p)
  759. d.MoveTo(x, 1500)
  760. d.LineTo(x, y)
  761. return x
  762. }
  763. d.charTable['V'] = func() float64 {
  764. d.MoveTo(0, 1500)
  765. d.LineTo(600, 0)
  766. d.LineTo(1200, 1500)
  767. return 1200
  768. }
  769. d.charTable['W'] = func() float64 {
  770. d.MoveTo(0, 1500)
  771. d.LineTo(400, 0)
  772. d.LineTo(800, 1500)
  773. d.LineTo(1200, 0)
  774. d.LineTo(1600, 1500)
  775. return 1600
  776. }
  777. d.charTable['X'] = func() float64 {
  778. d.MoveTo(0, 1500)
  779. d.LineTo(1050, 0)
  780. d.MoveTo(1050, 1500)
  781. d.LineTo(0, 0)
  782. return 1050
  783. }
  784. d.charTable['Y'] = func() float64 {
  785. d.MoveTo(0, 1500)
  786. d.LineTo(1120/2, 760)
  787. d.MoveTo(1120, 1500)
  788. d.LineTo(1120/2, 760)
  789. d.LineTo(1120/2, 0)
  790. return 1120
  791. }
  792. d.charTable['Z'] = func() float64 {
  793. d.MoveTo(0, 1500)
  794. d.LineTo(1000, 1500)
  795. d.LineTo(0, 0)
  796. d.LineTo(1000, 0)
  797. return 1000
  798. }
  799. d.charTable['&'] = func() float64 {
  800. oy := 820.0
  801. a := 15.0
  802. pointsT := d.Arc(970/2, 680/2, 180, 180, 0.0)
  803. pointsB := d.Arc(1100/2, 820/2, 90+a, 360, 0.0)
  804. pointsF1 := d.Arc(1550/2, 1650/2, 0, 90, 0.0)
  805. pointsF2 := d.Arc(1240/2, 1240/2, 270+a, 330, 0.0)
  806. w := 1100.0
  807. d.DrawPathOriginAtStart(w/2, oy, pointsT)
  808. x, y, _, _ := d.DrawPathOriginAtEnd(w/2, oy, pointsB)
  809. d.DrawPathOriginAtStart(w/2, oy, pointsF1)
  810. d.DrawPathOriginAtStart(x, y, pointsF2)
  811. return pointsF2.Width() + x
  812. }
  813. }
  814. func (d *drawer) dumpCharTable() {
  815. for r, f := range d.charTable {
  816. fmt.Printf("%s %0.2f\n",string(r),f())
  817. }
  818. }
  819. func (d *drawer) drawChar(char rune) float64 {
  820. if d.charTable[char] != nil {
  821. return d.charTable[char]()
  822. }
  823. return 0.0
  824. }
  825. func LineByAngleAndAzimuith(angle float64, l float64) Path {
  826. angle = radians(angle)
  827. return Path{
  828. points: []Point{
  829. Point{
  830. X: -math.Sin(angle) * l / 2,
  831. Y: -math.Cos(angle) * l / 2,
  832. },
  833. Point{
  834. X: math.Sin(angle) * l / 2,
  835. Y: math.Cos(angle) * l / 2,
  836. },
  837. },
  838. }
  839. }
  840. func degrees(x float64) float64 {
  841. return x / (math.Pi / 180)
  842. }
  843. func EllipseByTwoPathAndCenter(cx, cy, p1x, p1y, p2x, p2y, t float64) (float64, float64) {
  844. t = radians(t)
  845. return cx + math.Sin(t)*(p1x-cx) + math.Cos(t)*(p2x-cx), cy + math.Sin(t)*(p1y-cy) + math.Cos(t)*(p2y-cy)
  846. }
  847. func EllipseByThreePath(bx, by, cx, cy, dx, dy, t float64) (float64, float64) {
  848. t = radians(t)
  849. 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)
  850. 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)
  851. return x, y
  852. }
  853. func a(x, y float64) {
  854. }
  855. func radians(x float64) float64 {
  856. return x * math.Pi / 180
  857. }
  858. type drawer struct {
  859. skew float64
  860. c *draw2dimg.GraphicContext
  861. tx float64
  862. ty float64
  863. scale float64
  864. charTable map[rune]func() float64
  865. }
  866. func (d *drawer) SetLineWidth(w float64) {
  867. d.c.SetLineWidth(w)
  868. }
  869. func (d *drawer) SetXHeight(h float64) {
  870. d.scale = h / 1000
  871. }
  872. func (d *drawer) Line(x1, y1, x2, y2 float64) {
  873. d.MoveTo(x1, y1)
  874. d.LineTo(x2, y2)
  875. }
  876. func (d *drawer) Translate(x, y float64) {
  877. d.tx = x
  878. d.ty = y
  879. }
  880. func (d *drawer) AdvanceX(x float64) {
  881. d.tx += x
  882. }
  883. func (d *drawer) AdvanceY(y float64) {
  884. d.ty += y
  885. }
  886. func (d *drawer) transform(x, y float64) (float64, float64) {
  887. return (d.tx + x + (500-y)*d.skew) * d.scale, (d.ty + (500 - y)) * d.scale
  888. }
  889. func (d *drawer) MoveTo(x, y float64) {
  890. d.c.MoveTo(d.transform(x, y))
  891. }
  892. func (d *drawer) LineTo(x, y float64) {
  893. d.c.LineTo(d.transform(x, y))
  894. }
  895. func (d *drawer) Close() {
  896. }
  897. func (d *drawer) Stroke() {
  898. d.c.Stroke()
  899. }
  900. func (d *drawer) Mark(x, y float64) {
  901. saveX, saveY := d.c.LastPoint()
  902. s := 10.0
  903. d.MoveTo(x-s, y-s)
  904. d.LineTo(x+s, y+s)
  905. d.MoveTo(x+s, y-s)
  906. d.LineTo(x-s, y+s)
  907. d.MoveTo(saveX, saveY)
  908. }
  909. func rotate(x, y, a float64) (float64, float64) {
  910. s := math.Sin(a)
  911. c := math.Cos(a)
  912. xr := x*c - y*s
  913. yr := x*s + y*c
  914. return xr, yr
  915. }
  916. func ellipsify(θ float64, a float64, b float64) float64 {
  917. θ = math.Mod(θ, 2*math.Pi)
  918. negative := false
  919. if θ < 0.0 {
  920. negative = true
  921. θ = -θ
  922. }
  923. θo := math.Atan(a / b * math.Tan(θ))
  924. θc := θo
  925. if θ > math.Pi/2 && θ <= 1.5*math.Pi {
  926. θc = math.Pi + θo
  927. } else {
  928. θc = math.Mod(2*math.Pi+θo, 2*math.Pi)
  929. }
  930. if negative {
  931. θc = -θc
  932. }
  933. // fmt.Printf("θ %0.2f θo %0.2f θc %0.2f\n",degrees(θ),degrees(θo),degrees(θc))
  934. return θc
  935. }
  936. type Paths []Path
  937. type Point struct {
  938. X float64
  939. Y float64
  940. }
  941. type Path struct {
  942. points []Point
  943. }
  944. func line(a Point, b Point) (float64, float64) {
  945. slope := (b.Y - a.Y) / (b.X - a.X)
  946. yint := a.Y - slope*a.X
  947. return slope, yint
  948. }
  949. func intersection(l1a Point, l1b Point, l2a Point, l2b Point) (Point, error) {
  950. l1Slope, l1Yint := line(l1a, l1b)
  951. l2Slope, l2Yint := line(l2a, l2b)
  952. if l1Slope == l2Slope {
  953. return Point{}, fmt.Errorf("The lines do not intersect")
  954. }
  955. e := (l2Yint - l1Yint) / (l1Slope - l2Slope)
  956. n := l1Slope*e + l1Yint
  957. return Point{X: e, Y: n}, nil
  958. }
  959. func (p *Path) Start() Point {
  960. return Point{X: p.points[0].X, Y: p.points[0].Y}
  961. }
  962. func (p *Path) End() Point {
  963. return Point{X: p.points[len(p.points)-1].X, Y: p.points[len(p.points)-1].Y}
  964. }
  965. func (p *Path) Left() float64 {
  966. minX := p.points[0].X
  967. for i := 0; i < len(p.points); i++ {
  968. if p.points[i].X < minX {
  969. minX = p.points[i].X
  970. }
  971. }
  972. return minX
  973. }
  974. func (p *Path) Width() float64 {
  975. minX := p.points[0].X
  976. maxX := minX
  977. for i := 0; i < len(p.points); i++ {
  978. if p.points[i].X < minX {
  979. minX = p.points[i].X
  980. }
  981. if p.points[i].X > maxX {
  982. maxX = p.points[i].X
  983. }
  984. }
  985. return maxX - minX
  986. }
  987. func (p *Path) Height() float64 {
  988. minY := p.points[0].Y
  989. maxY := minY
  990. for i := 0; i < len(p.points); i++ {
  991. if p.points[i].Y < minY {
  992. minY = p.points[i].Y
  993. }
  994. if p.points[i].Y > maxY {
  995. maxY = p.points[i].Y
  996. }
  997. }
  998. return maxY - minY
  999. }
  1000. func (p *Path) Append(x, y float64) {
  1001. p.points = append(p.points, Point{X: x, Y: y})
  1002. }
  1003. func (d *drawer) DrawPathOriginAtCenter(x, y float64, points Path) (startX, startY, endX, endY float64) {
  1004. o := Point{}
  1005. for i, p := range points.points {
  1006. if i == 0 {
  1007. d.MoveTo(p.X-o.X+x, p.Y-o.Y+y)
  1008. } else {
  1009. d.LineTo(p.X-o.X+x, p.Y-o.Y+y)
  1010. }
  1011. }
  1012. start := points.points[0]
  1013. end := points.points[len(points.points)-1]
  1014. return start.X - o.X + x, start.Y - o.Y + y, end.X - o.X + x, end.Y - o.Y + y
  1015. }
  1016. func (d *drawer) DrawPathOriginAtStart(x, y float64, points Path) (startX, startY, endX, endY float64) {
  1017. o := points.points[0]
  1018. for i, p := range points.points {
  1019. if i == 0 {
  1020. d.MoveTo(p.X-o.X+x, p.Y-o.Y+y)
  1021. } else {
  1022. d.LineTo(p.X-o.X+x, p.Y-o.Y+y)
  1023. }
  1024. }
  1025. end := points.points[len(points.points)-1]
  1026. return x, y, end.X - o.X + x, end.Y - o.Y + y
  1027. }
  1028. func (d *drawer) DrawPathOriginAtEnd(x, y float64, points Path) (startX, startY, endX, endY float64) {
  1029. o := points.End()
  1030. for i := len(points.points) - 1; i >= 0; i-- {
  1031. p := points.points[i]
  1032. if i == len(points.points)-1 {
  1033. d.MoveTo(p.X-o.X+x, p.Y-o.Y+y)
  1034. } else {
  1035. d.LineTo(p.X-o.X+x, p.Y-o.Y+y)
  1036. }
  1037. }
  1038. start := points.points[0]
  1039. return start.X - o.X + x, start.Y - o.Y + y, x, y
  1040. }
  1041. // Arc computes a rotated circle or ellipse, and returns the points
  1042. // x,y = center
  1043. // a,b = ellipse semi-axes
  1044. // start = start angle, 0° = up
  1045. // end = end angle, 0° = up
  1046. // rot = rotation angle of ellipse, clockwise
  1047. // The arc is drawn between start and end. If end < start, the arc is drawn between end and start.
  1048. // start=0,end=90 draws a 90 degree arc segment between 0 and 90
  1049. // start=90,end=0 draws a 270 degree arc segment between 90 and 0
  1050. func (d *drawer) Arc(a, b, start, end, rot float64) Path {
  1051. rot = radians(rot)
  1052. if math.Mod(start, 360) == math.Mod(end, 360) {
  1053. // closed arc
  1054. start = radians(start)
  1055. end = start + 2*math.Pi
  1056. } else {
  1057. // adjust arc end angles to draw tangent angles
  1058. start = ellipsify(radians(start), a, b)
  1059. end = ellipsify(radians(end), a, b)
  1060. }
  1061. if start > end {
  1062. // drawing counter-clockwise
  1063. end = end + 2*math.Pi
  1064. }
  1065. ra := (math.Abs(a) + math.Abs(b)) / 2
  1066. da := math.Acos(ra/(ra+0.125)) * 2
  1067. angle := start
  1068. startX, startY := roticate(a, b, start, 0, 0, rot)
  1069. points := Path{points: []Point{Point{startX, startY}}}
  1070. var cua, cub float64
  1071. i := 0
  1072. for {
  1073. if angle > end-da/4 {
  1074. cua, cub = roticate(a, b, end, 0, 0, rot)
  1075. points.points = append(points.points, Point{cua, cub})
  1076. return points
  1077. }
  1078. cua, cub = roticate(a, b, angle, 0, 0, rot)
  1079. angle += da
  1080. points.points = append(points.points, Point{cua, cub})
  1081. i++
  1082. }
  1083. }
  1084. func roticate(a, b, θ, offx, offy, rot float64) (float64, float64) {
  1085. x := math.Sin(θ) * a
  1086. y := math.Cos(θ) * b
  1087. s := math.Sin(-rot)
  1088. c := math.Cos(-rot)
  1089. xr := x*c - y*s + offx
  1090. yr := x*s + y*c + offy
  1091. return xr, yr
  1092. }
  1093. type renderedGlyph struct {
  1094. path Path
  1095. width float64
  1096. }
  1097. type capturer struct {
  1098. skew float64
  1099. scale float64
  1100. glyphs map[rune]renderedGlyph
  1101. paths Paths
  1102. path Path
  1103. }
  1104. func (d *capturer) SetXHeight(h float64) {
  1105. d.scale = h / 1000
  1106. }
  1107. func (d *capturer) Line(x1, y1, x2, y2 float64) {
  1108. d.MoveTo(x1, y1)
  1109. d.LineTo(x2, y2)
  1110. }
  1111. func (d *capturer) transform(x, y float64) (float64, float64) {
  1112. return (x + (500-y)*d.skew) * d.scale, (500-y)* d.scale
  1113. }
  1114. func (d *capturer) MoveTo(x, y float64) {
  1115. if len(d.path.points)>1 {
  1116. d.paths = append(d.paths,d.path)
  1117. fmt.Println("saving path", len(d.paths))
  1118. }
  1119. d.path = Path{points:[]Point{Point{X:x, Y:y}}}
  1120. }
  1121. func (d *capturer) LineTo(x, y float64) {
  1122. d.path.Append(x,y)
  1123. }
  1124. func (d *capturer) Close() {
  1125. if len(d.path.points)>1 {
  1126. d.paths = append(d.paths,d.path)
  1127. fmt.Println("saving path", len(d.paths))
  1128. }
  1129. d.path = Path{}
  1130. }
  1131. func (d *capturer) DumpPaths() {
  1132. fmt.Println(d.paths)
  1133. d.paths=make(Paths,0)
  1134. }