github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/charting/draw_line.go (about) 1 package charting 2 3 import ( 4 "image" 5 "image/color" 6 7 8 "math" 9 "log" 10 11 "github.com/pbberlin/tools/util" 12 13 ) 14 15 16 // Blend a new pixel over an old pixel - heeding their alpha chan values 17 // 18 // algorithm NOT according to http://en.wikipedia.org/wiki/Alpha_compositing 19 // but by my own trial and error 20 func blendPixelOverPixel(ic_old,ic_new uint8, al_new float64)(c_res uint8) { 21 22 al_old := float64(1); _=al_old 23 c_old := float64(ic_old) 24 c_new := float64(ic_new) 25 26 algo1 := c_old*(1-al_new) + c_new*al_new 27 c_res = uint8( util.Min( util.Round(algo1),255) ) 28 //log.Printf("\t\t %3.1f + %3.1f = %3.1f", c_old*(1-al_new),c_new*al_new, algo1) 29 30 return 31 } 32 33 34 35 func funcSetPixler(col color.RGBA, img *image.RGBA )( func( addr int,dist float64) ){ 36 37 // 4*400*300 38 r := img.Rect 39 p0 := r.Min 40 p1 := r.Max 41 dx := p1.X - p0.X 42 dy := p1.Y - p0.Y 43 maxPix := dx * dy * 4 44 log.Printf("\tfuncSetPixler BxH: %vx%v Size:%v (%v)",dx,dy,maxPix,len(img.Pix) ) 45 46 return func(addr int,dist float64){ 47 48 //log.Printf("\t%v<%v",addr,maxPix ) 49 if addr > (maxPix-4) || addr < 0 { 50 log.Printf("\t%v<%v ! OVERFLOW! ",addr,maxPix ) 51 return 52 } 53 54 // dist ranges from 0 to 1.5 55 if dist < 0.0 { 56 dist = 0 57 } 58 59 sharpness := 0.9 // < 1 => more blurred ; otherwise more pixely 60 ba := math.Pow( 1 - (dist * 2/3), sharpness ) 61 62 //log.Printf("\tbef: %3d %3d %3d",img.Pix[addr+0],img.Pix[addr+1],img.Pix[addr+2]) 63 //log.Printf("\tcol: %3d %3d %3d | %1.3f => %1.3f",col.R,col.G,col.B,dist,ba) 64 65 img.Pix[addr+0] = blendPixelOverPixel(img.Pix[addr+0],col.R, ba) 66 img.Pix[addr+1] = blendPixelOverPixel(img.Pix[addr+1],col.G, ba) 67 img.Pix[addr+2] = blendPixelOverPixel(img.Pix[addr+2],col.B, ba) 68 69 //log.Printf("\taft: %3d %3d %3d\n\n",img.Pix[addr+0],img.Pix[addr+1],img.Pix[addr+2]) 70 71 } 72 73 } 74 75 76 77 78 79 80 81 // https://courses.engr.illinois.edu/ece390/archive/archive-f2000/mp/mp4/anti.html 82 func FuncDrawLiner(lCol color.RGBA, img *image.RGBA )( func( P_next image.Point, lCol color.RGBA, img *image.RGBA ) ){ 83 84 var P_last image.Point = image.Point{-1111,-1111} 85 86 r := img.Rect 87 p0 := r.Min 88 p1 := r.Max 89 imgWidth := p1.X - p0.X 90 91 92 return func (P_next image.Point, lCol color.RGBA, img *image.RGBA ){ 93 94 var P0, P1 image.Point 95 96 if P_last.X == -1111 && P_last.Y == -1111{ 97 P_last = P_next 98 return 99 } else { 100 P0 = P_last 101 P1 = P_next 102 P_last = P_next 103 } 104 105 106 log.Printf("draw_line_start---------------------------------") 107 108 x0, y0 := P0.X, P0.Y 109 x1, y1 := P1.X, P1.Y 110 111 112 bpp := 4 // bytes per pixel 113 114 addr := (y0*imgWidth+x0)*bpp 115 dx := x1-x0 116 dy := y1-y0 117 118 119 var du, dv,u ,v int 120 var uincr int = bpp 121 var vincr int = imgWidth*bpp 122 123 124 // switching to (u,v) to combine all eight octants 125 if util.Abs(dx) > util.Abs(dy) { 126 du = util.Abs(dx) 127 dv = util.Abs(dy) 128 u = x1 129 v = y1 130 uincr = bpp 131 vincr = imgWidth*bpp 132 if dx < 0 {uincr = -uincr} 133 if dy < 0 {vincr = -vincr} 134 } else { 135 du = util.Abs(dy) 136 dv = util.Abs(dx) 137 u = y1 138 v = x1 139 uincr = imgWidth*bpp 140 vincr = bpp 141 if dy < 0 {uincr = -uincr} 142 if dx < 0 {vincr = -vincr} 143 } 144 log.Printf("draw_line\tu %v - v %v - du %v - dv %v - uinc %v - vinc %v ", u, v, du, dv, uincr, vincr) 145 146 // uend := u + 2 * du 147 // d := (2 * dv) - du // Initial value as in Bresenham's 148 // incrS := 2 * dv // Δd for straight increments 149 // incrD := 2 * (dv - du) // Δd for diagonal increments 150 // twovdu := 0 // Numerator of distance starts at 0 151 152 153 // I have NO idea why - but unless I use -1- 154 // instead of the orginal -2- as factor, 155 // all lines are drawn DOUBLE the intended size 156 // THIS is how it works for me: 157 uend := u + 1 * du 158 d := (1 * dv) - du // Initial value as in Bresenham's 159 incrS := 1 * dv // Δd for straight increments 160 incrD := 1 * (dv - du) // Δd for diagonal increments 161 twovdu := 0 // Numerator of distance starts at 0 162 163 164 165 log.Printf("draw_line\tuend %v - d %v - incrS %v - incrD %v - twovdu %v", uend, d, incrS, incrD, twovdu) 166 167 168 tmp := float64(du*du + dv*dv) 169 invD := 1.0 / (2.0*math.Sqrt( tmp )) /* Precomputed inverse denominator */ 170 invD2du := 2.0 * ( float64(du)*invD) /* Precomputed constant */ 171 172 log.Printf("draw_line\tinvD %v - invD2du %v", invD, invD2du) 173 174 cntr := -1 175 176 setPix := funcSetPixler(lCol,img) 177 178 for{ 179 cntr++ 180 //log.Printf("==lp%v ", cntr ) 181 182 // Ensure that addr is valid 183 ftwovdu:= float64(twovdu) 184 setPix(addr - vincr, invD2du + ftwovdu*invD) 185 setPix(addr , ftwovdu*invD) 186 setPix(addr + vincr, invD2du - ftwovdu*invD) 187 188 189 if (d < 0){ 190 /* choose straight (u direction) */ 191 twovdu = d + du 192 d = d + incrS 193 } else { 194 /* choose diagonal (u+v direction) */ 195 twovdu = d - du 196 d = d + incrD 197 v = v+1 198 addr = addr + vincr 199 } 200 u = u+1 201 addr = addr+uincr 202 203 if u > uend {break} 204 } 205 206 log.Printf("draw_line_end---------------------------------") 207 208 } 209 } 210 211 212 213 214