Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 6344c29

Browse files
reed-at-googleSkia Commit-Bot
authored andcommitted
some cleanups for halfplanes
Plan is to next move the clipper into utils / SkCanvas itself Change-Id: Ia79c5bc2750a3a2719f901d255890a8c43ef1b42 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/257916 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Mike Reed <reed@google.com>
1 parent 67c0dcd commit 6344c29

File tree

1 file changed

+93
-83
lines changed

1 file changed

+93
-83
lines changed

samplecode/SampleClip.cpp

Lines changed: 93 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,10 @@ DEF_SAMPLE( return new ClipView(); )
141141
struct SkHalfPlane {
142142
SkScalar fA, fB, fC;
143143

144-
SkScalar operator()(SkScalar x, SkScalar y) const {
144+
SkScalar eval(SkScalar x, SkScalar y) const {
145145
return fA * x + fB * y + fC;
146146
}
147+
SkScalar operator()(SkScalar x, SkScalar y) const { return this->eval(x, y); }
147148

148149
bool twoPts(SkPoint pts[2]) const {
149150
// normalize plane to help with the perpendicular step, below
@@ -172,11 +173,45 @@ struct SkHalfPlane {
172173
SkASSERT(SkScalarNearlyZero(this->operator()(pts[1].fX, pts[1].fY)));
173174
return true;
174175
}
176+
177+
enum Result {
178+
kAllNegative,
179+
kAllPositive,
180+
kMixed
181+
};
182+
Result test(const SkRect& bounds) const {
183+
SkPoint diagMin, diagMax;
184+
if (fA >= 0) {
185+
diagMin.fX = bounds.fLeft;
186+
diagMax.fX = bounds.fRight;
187+
} else {
188+
diagMin.fX = bounds.fRight;
189+
diagMax.fX = bounds.fLeft;
190+
}
191+
if (fB >= 0) {
192+
diagMin.fY = bounds.fTop;
193+
diagMax.fY = bounds.fBottom;
194+
} else {
195+
diagMin.fY = bounds.fBottom;
196+
diagMax.fY = bounds.fTop;
197+
}
198+
SkScalar test = this->eval(diagMin.fX, diagMin.fY);
199+
SkScalar sign = test*this->eval(diagMax.fX, diagMin.fY);
200+
if (sign > 0) {
201+
// the path is either all on one side of the half-plane or the other
202+
if (test < 0) {
203+
return kAllNegative;
204+
} else {
205+
return kAllPositive;
206+
}
207+
}
208+
return kMixed;
209+
}
175210
};
176211

177212
#include "src/core/SkEdgeClipper.h"
178213

179-
static SkPath clip(const SkPath& path, SkPoint p0, SkPoint p1) {
214+
static void clip(const SkPath& path, SkPoint p0, SkPoint p1, SkPath* clippedPath) {
180215
SkMatrix mx, inv;
181216
SkVector v = p1 - p0;
182217
mx.setAll(v.fX, -v.fY, p0.fX,
@@ -191,9 +226,9 @@ static SkPath clip(const SkPath& path, SkPoint p0, SkPoint p1) {
191226
SkRect clip = {-big, 0, big, big };
192227

193228
struct Rec {
194-
SkPath fResult;
229+
SkPath* fResult;
195230
SkPoint fPrev;
196-
} rec;
231+
} rec = { clippedPath, {0, 0} };
197232

198233
SkEdgeClipper::ClipPath(rotated, clip, false,
199234
[](SkEdgeClipper* clipper, bool newCtr, void* ctx) {
@@ -204,26 +239,26 @@ static SkPath clip(const SkPath& path, SkPoint p0, SkPoint p1) {
204239
SkPath::Verb verb;
205240
while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
206241
if (newCtr) {
207-
rec->fResult.moveTo(pts[0]);
242+
rec->fResult->moveTo(pts[0]);
208243
rec->fPrev = pts[0];
209244
newCtr = false;
210245
}
211246

212247
if (addLineTo || pts[0] != rec->fPrev) {
213-
rec->fResult.lineTo(pts[0]);
248+
rec->fResult->lineTo(pts[0]);
214249
}
215250

216251
switch (verb) {
217252
case SkPath::kLine_Verb:
218-
rec->fResult.lineTo (pts[1]);
253+
rec->fResult->lineTo(pts[1]);
219254
rec->fPrev = pts[1];
220255
break;
221256
case SkPath::kQuad_Verb:
222-
rec->fResult.quadTo(pts[1], pts[2]);
257+
rec->fResult->quadTo(pts[1], pts[2]);
223258
rec->fPrev = pts[2];
224259
break;
225260
case SkPath::kCubic_Verb:
226-
rec->fResult.cubicTo(pts[1], pts[2], pts[3]);
261+
rec->fResult->cubicTo(pts[1], pts[2], pts[3]);
227262
rec->fPrev = pts[3];
228263
break;
229264
default: break;
@@ -232,50 +267,27 @@ static SkPath clip(const SkPath& path, SkPoint p0, SkPoint p1) {
232267
}
233268
}, &rec);
234269

235-
rec.fResult.transform(mx);
236-
return rec.fResult;
270+
rec.fResult->transform(mx);
237271
}
238272

239-
static SkPath clip(const SkPath& path, const SkHalfPlane& plane) {
240-
// do a quick bounds check to see if we need to clip at all
241-
const SkRect& bounds = path.getBounds();
242-
243-
// check whether the diagonal aligned with the normal crosses the plane
244-
SkPoint diagMin, diagMax;
245-
if (plane.fA >= 0) {
246-
diagMin.fX = bounds.fLeft;
247-
diagMax.fX = bounds.fRight;
248-
} else {
249-
diagMin.fX = bounds.fRight;
250-
diagMax.fX = bounds.fLeft;
251-
}
252-
if (plane.fB >= 0) {
253-
diagMin.fY = bounds.fTop;
254-
diagMax.fY = bounds.fBottom;
255-
} else {
256-
diagMin.fY = bounds.fBottom;
257-
diagMax.fY = bounds.fTop;
258-
}
259-
SkScalar test = plane(diagMin.fX, diagMin.fY);
260-
SkScalar sign = test*plane(diagMax.fX, diagMin.fY);
261-
if (sign > 0) {
262-
// the path is either all on one side of the half-plane or the other
263-
if (test < 0) {
264-
// completely culled
265-
return SkPath();
266-
} else {
267-
// no clipping necessary
268-
return path;
269-
}
270-
}
271-
272-
// quick check failed, we have to clip
273-
SkPoint pts[2];
274-
if (plane.twoPts(pts)) {
275-
return clip(path, pts[0], pts[1]);
276-
} else {
277-
return SkPath();
273+
// true means use clippedPath.
274+
// false means there was no clipping -- use the original path
275+
static bool clip(const SkPath& path, const SkHalfPlane& plane, SkPath* clippedPath) {
276+
switch (plane.test(path.getBounds())) {
277+
case SkHalfPlane::kAllPositive:
278+
return false;
279+
case SkHalfPlane::kMixed: {
280+
SkPoint pts[2];
281+
if (plane.twoPts(pts)) {
282+
clip(path, pts[0], pts[1], clippedPath);
283+
return true;
284+
}
285+
} break;
286+
default: break; // handled outside of the switch
278287
}
288+
// clipped out (or failed)
289+
clippedPath->reset();
290+
return true;
279291
}
280292

281293
static void draw_halfplane(SkCanvas* canvas, SkPoint p0, SkPoint p1, SkColor c) {
@@ -319,7 +331,10 @@ class HalfPlaneView : public Sample {
319331
canvas->drawPath(fPath, paint);
320332

321333
paint.setColor({0, 0, 0, 1}, nullptr);
322-
canvas->drawPath(clip(fPath, fPts[0], fPts[1]), paint);
334+
335+
SkPath clippedPath;
336+
clip(fPath, fPts[0], fPts[1], &clippedPath);
337+
canvas->drawPath(clippedPath, paint);
323338

324339
draw_halfplane(canvas, fPts[0], fPts[1], SK_ColorRED);
325340
}
@@ -430,6 +445,7 @@ static SkMatrix44 inv(const SkMatrix44& m) {
430445
return inverse;
431446
}
432447

448+
#if 0 // Jim's general half-planes math
433449
static void half_planes(const SkMatrix44& m44, SkScalar W, SkScalar H, SkHalfPlane planes[6]) {
434450
float mx[16];
435451
m44.asColMajorf(mx);
@@ -450,18 +466,10 @@ static void half_planes(const SkMatrix44& m44, SkScalar W, SkScalar H, SkHalfPla
450466
planes[4] = { m - i, n - j, p - l }; // w - z
451467
planes[5] = { m + i, n + j, p + l }; // w + z
452468
}
469+
#endif
453470

454-
static SkHalfPlane half_plane_w0(const SkMatrix44& m44, SkScalar W, SkScalar H) {
455-
float mx[16];
456-
m44.asColMajorf(mx);
457-
458-
SkScalar
459-
// a = mx[0], b = mx[4], /* c = mx[ 8], */ d = mx[12],
460-
// e = mx[1], f = mx[5], /* g = mx[ 9], */ h = mx[13],
461-
// i = mx[2], j = mx[6], /* k = mx[10], */ l = mx[14],
462-
m = mx[3], n = mx[7], /* o = mx[11], */ p = mx[15];
463-
464-
return { m, n, p - 0.05f }; // w = 0.05f
471+
static SkHalfPlane half_plane_w0(const SkMatrix& m) {
472+
return { m[SkMatrix::kMPersp0], m[SkMatrix::kMPersp1], m[SkMatrix::kMPersp2] - 0.05f };
465473
}
466474

467475
class HalfPlaneView3 : public Sample {
@@ -478,6 +486,7 @@ class HalfPlaneView3 : public Sample {
478486

479487
SkPath fPath;
480488
sk_sp<SkShader> fShader;
489+
bool fShowUnclipped = false;
481490

482491
SkString name() override { return SkString("halfplane3"); }
483492

@@ -514,38 +523,37 @@ class HalfPlaneView3 : public Sample {
514523
}
515524

516525
void onDrawContent(SkCanvas* canvas) override {
517-
SkMatrix44 mx44 = this->get44();
518-
SkMatrix mx = mx44;
526+
SkMatrix mx = this->get44();
519527

520528
SkPaint paint;
521529
paint.setColor({0.75, 0.75, 0.75, 1});
522530
canvas->drawPath(fPath, paint);
523531

524532
paint.setShader(fShader);
525533

526-
canvas->save();
527-
canvas->concat(mx);
528-
paint.setAlphaf(0.33f);
529-
canvas->drawPath(fPath, paint);
530-
paint.setAlphaf(1.f);
531-
canvas->restore();
534+
if (fShowUnclipped) {
535+
canvas->save();
536+
canvas->concat(mx);
537+
paint.setAlphaf(0.33f);
538+
canvas->drawPath(fPath, paint);
539+
paint.setAlphaf(1.f);
540+
canvas->restore();
541+
}
532542

533-
SkHalfPlane planes[6];
534-
half_planes(mx44, 400, 400, planes);
535-
SkHalfPlane hpw = half_plane_w0(mx44, 400, 400);
543+
SkHalfPlane hpw = half_plane_w0(mx);
536544

537-
SkPath path = clip(fPath, hpw);//planes[4]);
545+
SkColor planeColor = SK_ColorBLUE;
546+
SkPath clippedPath, *path = &fPath;
547+
if (clip(fPath, hpw, &clippedPath)) {
548+
path = &clippedPath;
549+
planeColor = SK_ColorRED;
550+
}
538551
canvas->save();
539552
canvas->concat(mx);
540-
canvas->drawPath(path, paint);
553+
canvas->drawPath(*path, paint);
541554
canvas->restore();
542555

543-
// for (auto& p : planes) {
544-
// draw_halfplane(canvas, p, SK_ColorRED);
545-
// }
546-
draw_halfplane(canvas, planes[4], SK_ColorBLUE);
547-
// draw_halfplane(canvas, planes[5], SK_ColorGREEN);
548-
draw_halfplane(canvas, hpw, SK_ColorRED);
556+
draw_halfplane(canvas, hpw, planeColor);
549557
}
550558

551559
bool onChar(SkUnichar uni) override {
@@ -558,13 +566,15 @@ class HalfPlaneView3 : public Sample {
558566
case '-': this->rotate(0, 0, delta); return true;
559567
case '+': this->rotate(0, 0, -delta); return true;
560568

561-
case 'i': fTrans.fZ += 0.1f; SkDebugf("ez %g\n", fTrans.fZ); return true;
562-
case 'k': fTrans.fZ -= 0.1f; SkDebugf("ez %g\n", fTrans.fZ); return true;
569+
case 'i': fTrans.fZ += 0.1f; SkDebugf("z %g\n", fTrans.fZ); return true;
570+
case 'k': fTrans.fZ -= 0.1f; SkDebugf("z %g\n", fTrans.fZ); return true;
563571

564572
case 'n': fNear += 0.1f; SkDebugf("near %g\n", fNear); return true;
565573
case 'N': fNear -= 0.1f; SkDebugf("near %g\n", fNear); return true;
566574
case 'f': fFar += 0.1f; SkDebugf("far %g\n", fFar); return true;
567575
case 'F': fFar -= 0.1f; SkDebugf("far %g\n", fFar); return true;
576+
577+
case 'u': fShowUnclipped = !fShowUnclipped; return true;
568578
default: break;
569579
}
570580
return false;

0 commit comments

Comments
 (0)