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 }