aboutsummaryrefslogtreecommitdiffhomepage
path: root/samplecode/SampleQuadStroker.cpp
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2016-01-19 08:07:49 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-01-19 08:07:50 -0800
commitb6474dd1a530a543ae799c3822e8bc60180761c0 (patch)
tree2e42f77ea502e31ac7473806437adb6be680bd33 /samplecode/SampleQuadStroker.cpp
parenta913275bda105fd545af471b724d7e8c1dacb9ae (diff)
fix circular dashing
Path measure cannot use the same code approach for quadratics and cubics. Subdividing cubics repeatedly does not result in subdivided t values, e.g. a quarter circle cubic divided in half twice does not have a t value equivalent to 1/4. Instead, always compute the cubic segment from a pair of t values. When finding the length of the cubic through recursive measures, it is enough to carry the point at a given t to the next subdivision. (Chrome suppression has landed already.) R=reed@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1602153002 Review URL: https://codereview.chromium.org/1602153002
Diffstat (limited to 'samplecode/SampleQuadStroker.cpp')
-rw-r--r--samplecode/SampleQuadStroker.cpp98
1 files changed, 90 insertions, 8 deletions
diff --git a/samplecode/SampleQuadStroker.cpp b/samplecode/SampleQuadStroker.cpp
index 3b029804ad..88f7dfd4ae 100644
--- a/samplecode/SampleQuadStroker.cpp
+++ b/samplecode/SampleQuadStroker.cpp
@@ -9,6 +9,7 @@
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
+#include "SkGeometry.h"
#include "SkPathMeasure.h"
#include "SkRandom.h"
#include "SkRRect.h"
@@ -122,6 +123,7 @@ class QuadStrokerView : public SampleView {
bool fAnimate;
bool fDrawRibs;
bool fDrawTangents;
+ bool fDrawTDivs;
#ifdef SK_DEBUG
#define kStrokerErrorMin 0.001f
#define kStrokerErrorMax 5
@@ -288,16 +290,84 @@ protected:
SkScalar total = meas.getLength();
SkScalar delta = 8;
- SkPaint paint;
+ SkPaint paint, labelP;
paint.setColor(color);
-
+ labelP.setColor(color & 0xff5f9f5f);
SkPoint pos, tan;
+ int index = 0;
for (SkScalar dist = 0; dist <= total; dist += delta) {
if (meas.getPosTan(dist, &pos, &tan)) {
tan.scale(radius);
tan.rotateCCW();
canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
pos.x() - tan.x(), pos.y() - tan.y(), paint);
+ if (0 == index % 10) {
+ SkString label;
+ label.appendS32(index);
+ SkRect dot = SkRect::MakeXYWH(pos.x() - 2, pos.y() - 2, 4, 4);
+ canvas->drawRect(dot, labelP);
+ canvas->drawText(label.c_str(), label.size(),
+ pos.x() - tan.x() * 1.25f, pos.y() - tan.y() * 1.25f, labelP);
+ }
+ }
+ ++index;
+ }
+ }
+
+ void draw_t_divs(SkCanvas* canvas, const SkPath& path, SkScalar width, SkColor color) {
+ const SkScalar radius = width / 2;
+ SkPaint paint;
+ paint.setColor(color);
+ SkPathMeasure meas(path, false);
+ SkScalar total = meas.getLength();
+ SkScalar delta = 8;
+ int ribs = 0;
+ for (SkScalar dist = 0; dist <= total; dist += delta) {
+ ++ribs;
+ }
+ SkPath::RawIter iter(path);
+ SkPoint pts[4];
+ if (SkPath::kMove_Verb != iter.next(pts)) {
+ SkASSERT(0);
+ return;
+ }
+ SkPath::Verb verb = iter.next(pts);
+ SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb);
+ SkPoint pos, tan;
+ for (int index = 0; index < ribs; ++index) {
+ SkScalar t = (SkScalar) index / ribs;
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ tan = pts[1] - pts[0];
+ pos = pts[0];
+ pos.fX += tan.fX * t;
+ pos.fY += tan.fY * t;
+ break;
+ case SkPath::kQuad_Verb:
+ pos = SkEvalQuadAt(pts, t);
+ tan = SkEvalQuadTangentAt(pts, t);
+ break;
+ case SkPath::kConic_Verb: {
+ SkConic conic(pts, iter.conicWeight());
+ pos = conic.evalAt(t);
+ tan = conic.evalTangentAt(t);
+ } break;
+ case SkPath::kCubic_Verb:
+ SkEvalCubicAt(pts, t, &pos, &tan, nullptr);
+ break;
+ default:
+ SkASSERT(0);
+ return;
+ }
+ tan.setLength(radius);
+ tan.rotateCCW();
+ canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
+ pos.x() - tan.x(), pos.y() - tan.y(), paint);
+ if (0 == index % 10) {
+ SkString label;
+ label.appendS32(index);
+ canvas->drawText(label.c_str(), label.size(),
+ pos.x() + tan.x() * 1.25f, pos.y() + tan.y() * 1.25f, paint);
}
}
}
@@ -343,6 +413,10 @@ protected:
draw_ribs(canvas, scaled, width, 0xFF00FF00);
}
+ if (fDrawTDivs) {
+ draw_t_divs(canvas, scaled, width, 0xFF3F3F00);
+ }
+
SkPath fill;
SkPaint p;
@@ -428,17 +502,24 @@ protected:
void setForGeometry() {
fDrawRibs = true;
fDrawTangents = true;
+ fDrawTDivs = false;
fWidthScale = 1;
}
void setForText() {
- fDrawRibs = fDrawTangents = false;
+ fDrawRibs = fDrawTangents = fDrawTDivs = false;
fWidthScale = 0.002f;
}
+ void setForSingles() {
+ setForGeometry();
+ fDrawTDivs = true;
+ }
+
void setAsNeeded() {
- if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled
- || fRRectButton.fEnabled || fCircleButton.fEnabled) {
+ if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled) {
+ setForSingles();
+ } else if (fRRectButton.fEnabled || fCircleButton.fEnabled) {
setForGeometry();
} else {
setForText();
@@ -452,14 +533,15 @@ protected:
if (fCubicButton.fEnabled) {
path.moveTo(fPts[0]);
path.cubicTo(fPts[1], fPts[2], fPts[3]);
- setForGeometry();
+ setForSingles();
draw_stroke(canvas, path, width, 950, false);
}
if (fConicButton.fEnabled) {
+ path.reset();
path.moveTo(fPts[4]);
path.conicTo(fPts[5], fPts[6], fWeight);
- setForGeometry();
+ setForSingles();
draw_stroke(canvas, path, width, 950, false);
}
@@ -467,7 +549,7 @@ protected:
path.reset();
path.moveTo(fPts[7]);
path.quadTo(fPts[8], fPts[9]);
- setForGeometry();
+ setForSingles();
draw_stroke(canvas, path, width, 950, false);
}