addarc.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * Copyright 2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "gm/gm.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkColor.h"
  10. #include "include/core/SkPaint.h"
  11. #include "include/core/SkPath.h"
  12. #include "include/core/SkPathMeasure.h"
  13. #include "include/core/SkPoint.h"
  14. #include "include/core/SkRect.h"
  15. #include "include/core/SkScalar.h"
  16. #include "include/core/SkSize.h"
  17. #include "include/core/SkString.h"
  18. #include "include/core/SkTypes.h"
  19. #include "include/private/SkFloatingPoint.h"
  20. #include "include/utils/SkRandom.h"
  21. #include "tools/ToolUtils.h"
  22. #include "tools/timer/TimeUtils.h"
  23. class AddArcGM : public skiagm::GM {
  24. public:
  25. AddArcGM() : fRotate(0) {}
  26. protected:
  27. SkString onShortName() override { return SkString("addarc"); }
  28. SkISize onISize() override { return SkISize::Make(1040, 1040); }
  29. void onDraw(SkCanvas* canvas) override {
  30. canvas->translate(20, 20);
  31. SkRect r = SkRect::MakeWH(1000, 1000);
  32. SkPaint paint;
  33. paint.setAntiAlias(true);
  34. paint.setStyle(SkPaint::kStroke_Style);
  35. paint.setStrokeWidth(15);
  36. const SkScalar inset = paint.getStrokeWidth() + 4;
  37. const SkScalar sweepAngle = 345;
  38. SkRandom rand;
  39. SkScalar sign = 1;
  40. while (r.width() > paint.getStrokeWidth() * 3) {
  41. paint.setColor(ToolUtils::color_to_565(rand.nextU() | (0xFF << 24)));
  42. SkScalar startAngle = rand.nextUScalar1() * 360;
  43. SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
  44. startAngle += fRotate * 360 * speed * sign;
  45. SkPath path;
  46. path.addArc(r, startAngle, sweepAngle);
  47. canvas->drawPath(path, paint);
  48. r.inset(inset, inset);
  49. sign = -sign;
  50. }
  51. }
  52. bool onAnimate(double nanos) override {
  53. fRotate = TimeUtils::Scaled(1e-9 * nanos, 1, 360);
  54. return true;
  55. }
  56. private:
  57. SkScalar fRotate;
  58. typedef skiagm::GM INHERITED;
  59. };
  60. DEF_GM( return new AddArcGM; )
  61. ///////////////////////////////////////////////////
  62. #define R 400
  63. DEF_SIMPLE_GM(addarc_meas, canvas, 2*R + 40, 2*R + 40) {
  64. canvas->translate(R + 20, R + 20);
  65. SkPaint paint;
  66. paint.setAntiAlias(true);
  67. paint.setStyle(SkPaint::kStroke_Style);
  68. SkPaint measPaint;
  69. measPaint.setAntiAlias(true);
  70. measPaint.setColor(SK_ColorRED);
  71. const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
  72. canvas->drawOval(oval, paint);
  73. for (SkScalar deg = 0; deg < 360; deg += 10) {
  74. const SkScalar rad = SkDegreesToRadians(deg);
  75. SkScalar rx = SkScalarCos(rad) * R;
  76. SkScalar ry = SkScalarSin(rad) * R;
  77. canvas->drawLine(0, 0, rx, ry, paint);
  78. SkPath path;
  79. path.addArc(oval, 0, deg);
  80. SkPathMeasure meas(path, false);
  81. SkScalar arcLen = rad * R;
  82. SkPoint pos;
  83. if (meas.getPosTan(arcLen, &pos, nullptr)) {
  84. canvas->drawLine({0, 0}, pos, measPaint);
  85. }
  86. }
  87. }
  88. ///////////////////////////////////////////////////
  89. // Emphasize drawing a stroked oval (containing conics) and then scaling the results up,
  90. // to ensure that we compute the stroke taking the CTM into account
  91. //
  92. class StrokeCircleGM : public skiagm::GM {
  93. public:
  94. StrokeCircleGM() : fRotate(0) {}
  95. protected:
  96. SkString onShortName() override { return SkString("strokecircle"); }
  97. SkISize onISize() override { return SkISize::Make(520, 520); }
  98. void onDraw(SkCanvas* canvas) override {
  99. canvas->scale(20, 20);
  100. canvas->translate(13, 13);
  101. SkPaint paint;
  102. paint.setAntiAlias(true);
  103. paint.setStyle(SkPaint::kStroke_Style);
  104. paint.setStrokeWidth(SK_Scalar1 / 2);
  105. const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
  106. SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
  107. SkRandom rand;
  108. SkScalar sign = 1;
  109. while (r.width() > paint.getStrokeWidth() * 2) {
  110. SkAutoCanvasRestore acr(canvas, true);
  111. canvas->rotate(fRotate * sign);
  112. paint.setColor(ToolUtils::color_to_565(rand.nextU() | (0xFF << 24)));
  113. canvas->drawOval(r, paint);
  114. r.inset(delta, delta);
  115. sign = -sign;
  116. }
  117. }
  118. bool onAnimate(double nanos) override {
  119. fRotate = TimeUtils::Scaled(1e-9 * nanos, 60, 360);
  120. return true;
  121. }
  122. private:
  123. SkScalar fRotate;
  124. typedef skiagm::GM INHERITED;
  125. };
  126. DEF_GM( return new StrokeCircleGM; )
  127. //////////////////////
  128. // Fill circles and rotate them to test our Analytic Anti-Aliasing.
  129. // This test is based on StrokeCircleGM.
  130. class FillCircleGM : public skiagm::GM {
  131. public:
  132. FillCircleGM() : fRotate(0) {}
  133. protected:
  134. SkString onShortName() override { return SkString("fillcircle"); }
  135. SkISize onISize() override { return SkISize::Make(520, 520); }
  136. void onDraw(SkCanvas* canvas) override {
  137. canvas->scale(20, 20);
  138. canvas->translate(13, 13);
  139. SkPaint paint;
  140. paint.setAntiAlias(true);
  141. paint.setStyle(SkPaint::kStroke_Style);
  142. paint.setStrokeWidth(SK_Scalar1 / 2);
  143. const SkScalar strokeWidth = paint.getStrokeWidth();
  144. const SkScalar delta = strokeWidth * 3 / 2;
  145. SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
  146. SkRandom rand;
  147. // Reset style to fill. We only need stroke stype for producing delta and strokeWidth
  148. paint.setStyle(SkPaint::kFill_Style);
  149. SkScalar sign = 1;
  150. while (r.width() > strokeWidth * 2) {
  151. SkAutoCanvasRestore acr(canvas, true);
  152. canvas->rotate(fRotate * sign);
  153. paint.setColor(ToolUtils::color_to_565(rand.nextU() | (0xFF << 24)));
  154. canvas->drawOval(r, paint);
  155. r.inset(delta, delta);
  156. sign = -sign;
  157. }
  158. }
  159. bool onAnimate(double nanos) override {
  160. fRotate = TimeUtils::Scaled(1e-9 * nanos, 60, 360);
  161. return true;
  162. }
  163. private:
  164. SkScalar fRotate;
  165. typedef skiagm::GM INHERITED;
  166. };
  167. DEF_GM( return new FillCircleGM; )
  168. //////////////////////
  169. static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
  170. SkScalar end, bool ccw, bool callArcTo) {
  171. SkRect bounds = { x - r, y - r, x + r, y + r };
  172. SkScalar sweep = ccw ? end - start : start - end;
  173. if (callArcTo)
  174. path->arcTo(bounds, start, sweep, false);
  175. else
  176. path->addArc(bounds, start, sweep);
  177. }
  178. // Lifted from canvas-arc-circumference-fill-diffs.html
  179. DEF_SIMPLE_GM(manyarcs, canvas, 620, 330) {
  180. SkPaint paint;
  181. paint.setAntiAlias(true);
  182. paint.setStyle(SkPaint::kStroke_Style);
  183. canvas->translate(10, 10);
  184. // 20 angles.
  185. SkScalar sweepAngles[] = {
  186. -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
  187. 1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
  188. };
  189. for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
  190. sweepAngles[i] *= 180;
  191. }
  192. SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
  193. for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
  194. startAngles[i] *= 180;
  195. }
  196. bool anticlockwise = false;
  197. SkScalar sign = 1;
  198. for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
  199. if (i == SK_ARRAY_COUNT(startAngles)) {
  200. anticlockwise = true;
  201. sign = -1;
  202. }
  203. SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
  204. canvas->save();
  205. for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
  206. SkPath path;
  207. path.moveTo(0, 2);
  208. html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
  209. anticlockwise, true);
  210. path.lineTo(0, 28);
  211. canvas->drawPath(path, paint);
  212. canvas->translate(30, 0);
  213. }
  214. canvas->restore();
  215. canvas->translate(0, 40);
  216. }
  217. }
  218. // Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
  219. DEF_SIMPLE_GM(tinyanglearcs, canvas, 620, 330) {
  220. SkPaint paint;
  221. paint.setAntiAlias(true);
  222. paint.setStyle(SkPaint::kStroke_Style);
  223. canvas->translate(50, 50);
  224. SkScalar outerRadius = 100000.0f;
  225. SkScalar innerRadius = outerRadius - 20.0f;
  226. SkScalar centerX = 50;
  227. SkScalar centerY = outerRadius;
  228. SkScalar startAngles[] = { 1.5f * SK_ScalarPI , 1.501f * SK_ScalarPI };
  229. SkScalar sweepAngle = 10.0f / outerRadius;
  230. for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
  231. SkPath path;
  232. SkScalar endAngle = startAngles[i] + sweepAngle;
  233. path.moveTo(centerX + innerRadius * sk_float_cos(startAngles[i]),
  234. centerY + innerRadius * sk_float_sin(startAngles[i]));
  235. path.lineTo(centerX + outerRadius * sk_float_cos(startAngles[i]),
  236. centerY + outerRadius * sk_float_sin(startAngles[i]));
  237. // A combination of tiny sweepAngle + large radius, we should draw a line.
  238. html_canvas_arc(&path, centerX, outerRadius, outerRadius,
  239. startAngles[i] * 180 / SK_ScalarPI, endAngle * 180 / SK_ScalarPI,
  240. true, true);
  241. path.lineTo(centerX + innerRadius * sk_float_cos(endAngle),
  242. centerY + innerRadius * sk_float_sin(endAngle));
  243. html_canvas_arc(&path, centerX, outerRadius, innerRadius,
  244. endAngle * 180 / SK_ScalarPI, startAngles[i] * 180 / SK_ScalarPI,
  245. true, false);
  246. canvas->drawPath(path, paint);
  247. canvas->translate(20, 0);
  248. }
  249. }