arc.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <memdraw.h>
  5. #include <memlayer.h>
  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. enum
  13. {
  14. R, T, L, B /* right, top, left, bottom */
  15. };
  16. static
  17. Point corners[] = {
  18. {1,1},
  19. {-1,1},
  20. {-1,-1},
  21. {1,-1}
  22. };
  23. static
  24. Point p00;
  25. /*
  26. * make a "wedge" mask covering the desired angle and contained in
  27. * a surrounding square; draw a full ellipse; intersect that with the
  28. * wedge to make a mask through which to copy src to dst.
  29. */
  30. void
  31. memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op)
  32. {
  33. int i, w, beta, tmp, c1, c2, m, m1;
  34. Rectangle rect;
  35. Point p, bnd[8];
  36. Memimage *wedge, *figure, *mask;
  37. if(a < 0)
  38. a = -a;
  39. if(b < 0)
  40. b = -b;
  41. w = t;
  42. if(w < 0)
  43. w = 0;
  44. alpha = -alpha; /* compensate for upside-down coords */
  45. phi = -phi;
  46. beta = alpha + phi;
  47. if(phi < 0){
  48. tmp = alpha;
  49. alpha = beta;
  50. beta = tmp;
  51. phi = -phi;
  52. }
  53. if(phi >= 360){
  54. memellipse(dst, c, a, b, t, src, sp, op);
  55. return;
  56. }
  57. while(alpha < 0)
  58. alpha += 360;
  59. while(beta < 0)
  60. beta += 360;
  61. c1 = alpha/90 & 3; /* number of nearest corner */
  62. c2 = beta/90 & 3;
  63. /*
  64. * icossin returns point at radius ICOSSCALE.
  65. * multiplying by m1 moves it outside the ellipse
  66. */
  67. rect = Rect(-a-w, -b-w, a+w+1, b+w+1);
  68. m = rect.max.x; /* inradius of bounding square */
  69. if(m < rect.max.y)
  70. m = rect.max.y;
  71. m1 = (m+ICOSSCALE-1) >> 10;
  72. m = m1 << 10; /* assure m1*cossin is inside */
  73. i = 0;
  74. bnd[i++] = Pt(0,0);
  75. icossin(alpha, &p.x, &p.y);
  76. bnd[i++] = mulpt(p, m1);
  77. for(;;) {
  78. bnd[i++] = mulpt(corners[c1], m);
  79. if(c1==c2 && phi<180)
  80. break;
  81. c1 = (c1+1) & 3;
  82. phi -= 90;
  83. }
  84. icossin(beta, &p.x, &p.y);
  85. bnd[i++] = mulpt(p, m1);
  86. figure = nil;
  87. mask = nil;
  88. wedge = allocmemimage(rect, GREY1);
  89. if(wedge == nil)
  90. goto Return;
  91. memfillcolor(wedge, DTransparent);
  92. memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S);
  93. figure = allocmemimage(rect, GREY1);
  94. if(figure == nil)
  95. goto Return;
  96. memfillcolor(figure, DTransparent);
  97. memellipse(figure, p00, a, b, t, memopaque, p00, S);
  98. mask = allocmemimage(rect, GREY1);
  99. if(mask == nil)
  100. goto Return;
  101. memfillcolor(mask, DTransparent);
  102. memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S);
  103. c = subpt(c, dst->r.min);
  104. memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op);
  105. Return:
  106. freememimage(wedge);
  107. freememimage(figure);
  108. freememimage(mask);
  109. }