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