arc.c 2.5 KB

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