dashcircle.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright 2016 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/SkMatrix.h"
  11. #include "include/core/SkPaint.h"
  12. #include "include/core/SkPath.h"
  13. #include "include/core/SkPathEffect.h"
  14. #include "include/core/SkRect.h"
  15. #include "include/core/SkRefCnt.h"
  16. #include "include/core/SkScalar.h"
  17. #include "include/core/SkSize.h"
  18. #include "include/core/SkString.h"
  19. #include "include/core/SkTypes.h"
  20. #include "include/effects/SkDashPathEffect.h"
  21. #include "tools/timer/TimeUtils.h"
  22. int dash1[] = { 1, 1 };
  23. int dash2[] = { 1, 3 };
  24. int dash3[] = { 1, 1, 3, 3 };
  25. int dash4[] = { 1, 3, 2, 4 };
  26. struct DashExample {
  27. int* pattern;
  28. int length;
  29. } dashExamples[] = {
  30. { dash1, SK_ARRAY_COUNT(dash1) },
  31. { dash2, SK_ARRAY_COUNT(dash2) },
  32. { dash3, SK_ARRAY_COUNT(dash3) },
  33. { dash4, SK_ARRAY_COUNT(dash4) }
  34. };
  35. class DashCircleGM : public skiagm::GM {
  36. public:
  37. DashCircleGM() : fRotation(0) { }
  38. protected:
  39. SkString onShortName() override { return SkString("dashcircle"); }
  40. SkISize onISize() override { return SkISize::Make(900, 1200); }
  41. void onDraw(SkCanvas* canvas) override {
  42. SkPaint refPaint;
  43. refPaint.setAntiAlias(true);
  44. refPaint.setColor(0xFFbf3f7f);
  45. refPaint.setStyle(SkPaint::kStroke_Style);
  46. refPaint.setStrokeWidth(1);
  47. const SkScalar radius = 125;
  48. SkRect oval = SkRect::MakeLTRB(-radius - 20, -radius - 20, radius + 20, radius + 20);
  49. SkPath circle;
  50. circle.addCircle(0, 0, radius);
  51. SkScalar circumference = radius * SK_ScalarPI * 2;
  52. int wedges[] = { 6, 12, 36 };
  53. canvas->translate(radius+20, radius+20);
  54. for (int wedge : wedges) {
  55. SkScalar arcLength = 360.f / wedge;
  56. canvas->save();
  57. for (const DashExample& dashExample : dashExamples) {
  58. SkPath refPath;
  59. int dashUnits = 0;
  60. for (int index = 0; index < dashExample.length; ++index) {
  61. dashUnits += dashExample.pattern[index];
  62. }
  63. SkScalar unitLength = arcLength / dashUnits;
  64. SkScalar angle = 0;
  65. for (int index = 0; index < wedge; ++index) {
  66. for (int i2 = 0; i2 < dashExample.length; i2 += 2) {
  67. SkScalar span = dashExample.pattern[i2] * unitLength;
  68. refPath.moveTo(0, 0);
  69. refPath.arcTo(oval, angle, span, false);
  70. refPath.close();
  71. angle += span + (dashExample.pattern[i2 + 1]) * unitLength;
  72. }
  73. }
  74. canvas->save();
  75. canvas->rotate(fRotation);
  76. canvas->drawPath(refPath, refPaint);
  77. canvas->restore();
  78. SkPaint p;
  79. p.setAntiAlias(true);
  80. p.setStyle(SkPaint::kStroke_Style);
  81. p.setStrokeWidth(10);
  82. SkScalar intervals[4];
  83. int intervalCount = dashExample.length;
  84. SkScalar dashLength = circumference / wedge / dashUnits;
  85. for (int index = 0; index < dashExample.length; ++index) {
  86. intervals[index] = dashExample.pattern[index] * dashLength;
  87. }
  88. p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, 0));
  89. canvas->save();
  90. canvas->rotate(fRotation);
  91. canvas->drawPath(circle, p);
  92. canvas->restore();
  93. canvas->translate(0, radius * 2 + 50);
  94. }
  95. canvas->restore();
  96. canvas->translate(radius * 2 + 50, 0);
  97. }
  98. }
  99. bool onAnimate(double nanos) override {
  100. constexpr SkScalar kDesiredDurationSecs = 100.0f;
  101. fRotation = TimeUtils::Scaled(1e-9 * nanos, 360.0f/kDesiredDurationSecs, 360.0f);
  102. return true;
  103. }
  104. private:
  105. SkScalar fRotation;
  106. typedef GM INHERITED;
  107. };
  108. DEF_GM(return new DashCircleGM; )
  109. class DashCircle2GM : public skiagm::GM {
  110. public:
  111. DashCircle2GM() {}
  112. protected:
  113. SkString onShortName() override { return SkString("dashcircle2"); }
  114. SkISize onISize() override { return SkISize::Make(635, 900); }
  115. void onDraw(SkCanvas* canvas) override {
  116. // These intervals are defined relative to tau.
  117. static constexpr SkScalar kIntervals[][2]{
  118. {0.333f, 0.333f},
  119. {0.015f, 0.015f},
  120. {0.01f , 0.09f },
  121. {0.097f, 0.003f},
  122. {0.02f , 0.04f },
  123. {0.1f , 0.2f },
  124. {0.25f , 0.25f },
  125. {0.6f , 0.7f }, // adds to > 1
  126. {1.2f , 0.8f }, // on is > 1
  127. {0.1f , 1.1f }, // off is > 1*/
  128. };
  129. static constexpr int kN = SK_ARRAY_COUNT(kIntervals);
  130. static constexpr SkScalar kRadius = 20.f;
  131. static constexpr SkScalar kStrokeWidth = 15.f;
  132. static constexpr SkScalar kPad = 5.f;
  133. static constexpr SkRect kCircle = {-kRadius, -kRadius, kRadius, kRadius};
  134. static constexpr SkScalar kThinRadius = kRadius * 1.5;
  135. static constexpr SkRect kThinCircle = {-kThinRadius, -kThinRadius,
  136. kThinRadius, kThinRadius};
  137. static constexpr SkScalar kThinStrokeWidth = 0.4f;
  138. sk_sp<SkPathEffect> deffects[SK_ARRAY_COUNT(kIntervals)];
  139. sk_sp<SkPathEffect> thinDEffects[SK_ARRAY_COUNT(kIntervals)];
  140. for (int i = 0; i < kN; ++i) {
  141. static constexpr SkScalar kTau = 2 * SK_ScalarPI;
  142. static constexpr SkScalar kCircumference = kRadius * kTau;
  143. SkScalar scaledIntervals[2] = {kCircumference * kIntervals[i][0],
  144. kCircumference * kIntervals[i][1]};
  145. deffects[i] = SkDashPathEffect::Make(
  146. scaledIntervals, 2, kCircumference * fPhaseDegrees * kTau / 360.f);
  147. static constexpr SkScalar kThinCircumference = kThinRadius * kTau;
  148. scaledIntervals[0] = kThinCircumference * kIntervals[i][0];
  149. scaledIntervals[1] = kThinCircumference * kIntervals[i][1];
  150. thinDEffects[i] = SkDashPathEffect::Make(
  151. scaledIntervals, 2, kThinCircumference * fPhaseDegrees * kTau / 360.f);
  152. }
  153. SkMatrix rotate;
  154. rotate.setRotate(25.f);
  155. static const SkMatrix kMatrices[]{
  156. SkMatrix::I(),
  157. SkMatrix::MakeScale(1.2f),
  158. SkMatrix::MakeAll(1, 0, 0, 0, -1, 0, 0, 0, 1), // y flipper
  159. SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), // x flipper
  160. SkMatrix::MakeScale(0.7f),
  161. rotate,
  162. SkMatrix::Concat(
  163. SkMatrix::Concat(SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), rotate),
  164. rotate)
  165. };
  166. SkPaint paint;
  167. paint.setAntiAlias(true);
  168. paint.setStrokeWidth(kStrokeWidth);
  169. paint.setStyle(SkPaint::kStroke_Style);
  170. // Compute the union of bounds of all of our test cases.
  171. SkRect bounds = SkRect::MakeEmpty();
  172. static const SkRect kBounds = kThinCircle.makeOutset(kThinStrokeWidth / 2.f,
  173. kThinStrokeWidth / 2.f);
  174. for (const auto& m : kMatrices) {
  175. SkRect devBounds;
  176. m.mapRect(&devBounds, kBounds);
  177. bounds.join(devBounds);
  178. }
  179. canvas->save();
  180. canvas->translate(-bounds.fLeft + kPad, -bounds.fTop + kPad);
  181. for (size_t i = 0; i < SK_ARRAY_COUNT(deffects); ++i) {
  182. canvas->save();
  183. for (const auto& m : kMatrices) {
  184. canvas->save();
  185. canvas->concat(m);
  186. paint.setPathEffect(deffects[i]);
  187. paint.setStrokeWidth(kStrokeWidth);
  188. canvas->drawOval(kCircle, paint);
  189. paint.setPathEffect(thinDEffects[i]);
  190. paint.setStrokeWidth(kThinStrokeWidth);
  191. canvas->drawOval(kThinCircle, paint);
  192. canvas->restore();
  193. canvas->translate(bounds.width() + kPad, 0);
  194. }
  195. canvas->restore();
  196. canvas->translate(0, bounds.height() + kPad);
  197. }
  198. canvas->restore();
  199. }
  200. protected:
  201. bool onAnimate(double nanos) override {
  202. fPhaseDegrees = 1e-9 * nanos;
  203. return true;
  204. }
  205. // Init with a non-zero phase for when run as a non-animating GM.
  206. SkScalar fPhaseDegrees = 12.f;
  207. };
  208. DEF_GM(return new DashCircle2GM;)
  209. DEF_SIMPLE_GM(maddash, canvas, 1600, 1600) {
  210. canvas->drawRect({0, 0, 1600, 1600}, SkPaint());
  211. SkPaint p;
  212. p.setColor(SK_ColorRED);
  213. p.setAntiAlias(true);
  214. p.setStyle(SkPaint::kStroke_Style);
  215. p.setStrokeWidth(380);
  216. SkScalar intvls[] = { 2.5, 10 /* 1200 */ };
  217. p.setPathEffect(SkDashPathEffect::Make(intvls, 2, 0));
  218. canvas->drawCircle(400, 400, 200, p);
  219. SkPath path;
  220. path.moveTo(800, 400);
  221. path.quadTo(1000, 400, 1000, 600);
  222. path.quadTo(1000, 800, 800, 800);
  223. path.quadTo(600, 800, 600, 600);
  224. path.quadTo(600, 400, 800, 400);
  225. path.close();
  226. canvas->translate(350, 150);
  227. p.setStrokeWidth(320);
  228. canvas->drawPath(path, p);
  229. path.reset();
  230. path.moveTo(800, 400);
  231. path.cubicTo(900, 400, 1000, 500, 1000, 600);
  232. path.cubicTo(1000, 700, 900, 800, 800, 800);
  233. path.cubicTo(700, 800, 600, 700, 600, 600);
  234. path.cubicTo(600, 500, 700, 400, 800, 400);
  235. path.close();
  236. canvas->translate(-550, 500);
  237. p.setStrokeWidth(300);
  238. canvas->drawPath(path, p);
  239. }