9fans.net/go@v0.0.5/draw/memdraw/arc.go (about)

     1  // #include <u.h>
     2  // #include <libc.h>
     3  // #include <draw.h>
     4  // #include <memdraw.h>
     5  
     6  /*
     7   * elarc(dst,c,a,b,t,src,sp,alpha,phi)
     8   *   draws the part of an ellipse between rays at angles alpha and alpha+phi
     9   *   measured counterclockwise from the positive x axis. other
    10   *   arguments are as for ellipse(dst,c,a,b,t,src,sp)
    11   */
    12  
    13  package memdraw
    14  
    15  import (
    16  	"9fans.net/go/draw"
    17  )
    18  
    19  const (
    20  	_R = iota
    21  	_T
    22  	_L
    23  	_B
    24  )
    25  
    26  /* right, top, left, bottom */
    27  
    28  var corners = [4]draw.Point{
    29  	draw.Point{1, 1},
    30  	draw.Point{-1, 1},
    31  	draw.Point{-1, -1},
    32  	draw.Point{1, -1},
    33  }
    34  
    35  var p00 draw.Point
    36  
    37  /*
    38   * make a "wedge" mask covering the desired angle and contained in
    39   * a surrounding square; draw a full ellipse; intersect that with the
    40   * wedge to make a mask through which to copy src to dst.
    41   */
    42  func Arc(dst *Image, c draw.Point, a int, b int, t int, src *Image, sp draw.Point, alpha int, phi int, op draw.Op) {
    43  	if a < 0 {
    44  		a = -a
    45  	}
    46  	if b < 0 {
    47  		b = -b
    48  	}
    49  	w := t
    50  	if w < 0 {
    51  		w = 0
    52  	}
    53  	alpha = -alpha /* compensate for upside-down coords */
    54  	phi = -phi
    55  	beta := alpha + phi
    56  	if phi < 0 {
    57  		tmp := alpha
    58  		alpha = beta
    59  		beta = tmp
    60  		phi = -phi
    61  	}
    62  	if phi >= 360 {
    63  		Ellipse(dst, c, a, b, t, src, sp, op)
    64  		return
    65  	}
    66  	for alpha < 0 {
    67  		alpha += 360
    68  	}
    69  	for beta < 0 {
    70  		beta += 360
    71  	}
    72  	c1 := alpha / 90 & 3 /* number of nearest corner */
    73  	c2 := beta / 90 & 3
    74  	/*
    75  	 * icossin returns point at radius ICOSSCALE.
    76  	 * multiplying by m1 moves it outside the ellipse
    77  	 */
    78  	rect := draw.Rect(-a-w, -b-w, a+w+1, b+w+1)
    79  	m := rect.Max.X /* inradius of bounding square */
    80  	if m < rect.Max.Y {
    81  		m = rect.Max.Y
    82  	}
    83  	m1 := (m + draw.ICOSSCALE - 1) >> 10
    84  	m = m1 << 10 /* assure m1*cossin is inside */
    85  	i := 0
    86  	var bnd [8]draw.Point
    87  	bnd[i] = draw.Pt(0, 0)
    88  	i++
    89  	var p draw.Point
    90  	p.X, p.Y = draw.IntCosSin(alpha)
    91  	bnd[i] = p.Mul(m1)
    92  	i++
    93  	for {
    94  		bnd[i] = corners[c1].Mul(m)
    95  		i++
    96  		if c1 == c2 && phi < 180 {
    97  			break
    98  		}
    99  		c1 = (c1 + 1) & 3
   100  		phi -= 90
   101  	}
   102  	p.X, p.Y = draw.IntCosSin(beta)
   103  	bnd[i] = p.Mul(m1)
   104  	i++
   105  
   106  	var figure, mask *Image
   107  	wedge, err := AllocImage(rect, draw.GREY1)
   108  	if err != nil {
   109  		goto Return
   110  	}
   111  	FillColor(wedge, draw.Transparent)
   112  	FillPoly(wedge, bnd[:i], ^0, Opaque, p00, draw.S)
   113  	figure, err = AllocImage(rect, draw.GREY1)
   114  	if err != nil {
   115  		goto Return
   116  	}
   117  	FillColor(figure, draw.Transparent)
   118  	Ellipse(figure, p00, a, b, t, Opaque, p00, draw.S)
   119  	mask, err = AllocImage(rect, draw.GREY1)
   120  	if err != nil {
   121  		goto Return
   122  	}
   123  	FillColor(mask, draw.Transparent)
   124  	mask.Draw(rect, figure, rect.Min, wedge, rect.Min, draw.S)
   125  	c = c.Sub(dst.R.Min)
   126  	Draw(dst, dst.R, src, sp.Sub(c), mask, p00.Sub(c), op)
   127  
   128  Return:
   129  	Free(wedge)
   130  	Free(figure)
   131  	Free(mask)
   132  }