4428f2c39f
This differed from the separate versions in that it snapped to zero. It was also strictly worse than calling the two separate versions. Most clients don't need the snapping, so just call the two existing functions. For clients that need the snapping, call new variants of each that do snap. Change-Id: Ia4e09fd9651932fe15caeab1399df7f6281bdc17 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/205303 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Mike Reed <reed@google.com>
612 lines
16 KiB
C++
612 lines
16 KiB
C++
/*
|
|
* Copyright 2018 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "SkPathPriv.h"
|
|
#include "SkPolyUtils.h"
|
|
#include "ToolUtils.h"
|
|
#include "gm.h"
|
|
|
|
static void create_ngon(int n, SkPoint* pts, SkScalar w, SkScalar h, SkPath::Direction dir) {
|
|
float angleStep = 360.0f / n, angle = 0.0f;
|
|
if ((n % 2) == 1) {
|
|
angle = angleStep/2.0f;
|
|
}
|
|
if (SkPath::kCCW_Direction == dir) {
|
|
angle = -angle;
|
|
angleStep = -angleStep;
|
|
}
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
pts[i].fX = -SkScalarSin(SkDegreesToRadians(angle)) * w;
|
|
pts[i].fY = SkScalarCos(SkDegreesToRadians(angle)) * h;
|
|
angle += angleStep;
|
|
}
|
|
}
|
|
|
|
namespace PolygonOffsetData {
|
|
// narrow rect
|
|
const SkPoint gPoints0[] = {
|
|
{ -1.5f, -50.0f },
|
|
{ 1.5f, -50.0f },
|
|
{ 1.5f, 50.0f },
|
|
{ -1.5f, 50.0f }
|
|
};
|
|
// narrow rect on an angle
|
|
const SkPoint gPoints1[] = {
|
|
{ -50.0f, -49.0f },
|
|
{ -49.0f, -50.0f },
|
|
{ 50.0f, 49.0f },
|
|
{ 49.0f, 50.0f }
|
|
};
|
|
// trap - narrow on top - wide on bottom
|
|
const SkPoint gPoints2[] = {
|
|
{ -10.0f, -50.0f },
|
|
{ 10.0f, -50.0f },
|
|
{ 50.0f, 50.0f },
|
|
{ -50.0f, 50.0f }
|
|
};
|
|
// wide skewed rect
|
|
const SkPoint gPoints3[] = {
|
|
{ -50.0f, -50.0f },
|
|
{ 0.0f, -50.0f },
|
|
{ 50.0f, 50.0f },
|
|
{ 0.0f, 50.0f }
|
|
};
|
|
// thin rect with colinear-ish lines
|
|
const SkPoint gPoints4[] = {
|
|
{ -6.0f, -50.0f },
|
|
{ 4.0f, -50.0f },
|
|
{ 5.0f, -25.0f },
|
|
{ 6.0f, 0.0f },
|
|
{ 5.0f, 25.0f },
|
|
{ 4.0f, 50.0f },
|
|
{ -4.0f, 50.0f }
|
|
};
|
|
// degenerate
|
|
const SkPoint gPoints5[] = {
|
|
{ -0.025f, -0.025f },
|
|
{ 0.025f, -0.025f },
|
|
{ 0.025f, 0.025f },
|
|
{ -0.025f, 0.025f }
|
|
};
|
|
// Quad with near coincident point
|
|
const SkPoint gPoints6[] = {
|
|
{ -20.0f, -13.0f },
|
|
{ -20.0f, -13.05f },
|
|
{ 20.0f, -13.0f },
|
|
{ 20.0f, 27.0f }
|
|
};
|
|
// thin rect with colinear lines
|
|
const SkPoint gPoints7[] = {
|
|
{ -10.0f, -50.0f },
|
|
{ 10.0f, -50.0f },
|
|
{ 10.0f, -20.0f },
|
|
{ 10.0f, 0.0f },
|
|
{ 10.0f, 35.0f },
|
|
{ 10.0f, 50.0f },
|
|
{ -10.0f, 50.0f }
|
|
};
|
|
// capped teardrop
|
|
const SkPoint gPoints8[] = {
|
|
{ 50.00f, 50.00f },
|
|
{ 0.00f, 50.00f },
|
|
{ -15.45f, 47.55f },
|
|
{ -29.39f, 40.45f },
|
|
{ -40.45f, 29.39f },
|
|
{ -47.55f, 15.45f },
|
|
{ -50.00f, 0.00f },
|
|
{ -47.55f, -15.45f },
|
|
{ -40.45f, -29.39f },
|
|
{ -29.39f, -40.45f },
|
|
{ -15.45f, -47.55f },
|
|
{ 0.00f, -50.00f },
|
|
{ 50.00f, -50.00f }
|
|
};
|
|
// teardrop
|
|
const SkPoint gPoints9[] = {
|
|
{ 4.39f, 40.45f },
|
|
{ -9.55f, 47.55f },
|
|
{ -25.00f, 50.00f },
|
|
{ -40.45f, 47.55f },
|
|
{ -54.39f, 40.45f },
|
|
{ -65.45f, 29.39f },
|
|
{ -72.55f, 15.45f },
|
|
{ -75.00f, 0.00f },
|
|
{ -72.55f, -15.45f },
|
|
{ -65.45f, -29.39f },
|
|
{ -54.39f, -40.45f },
|
|
{ -40.45f, -47.55f },
|
|
{ -25.0f, -50.0f },
|
|
{ -9.55f, -47.55f },
|
|
{ 4.39f, -40.45f },
|
|
{ 75.00f, 0.00f }
|
|
};
|
|
// clipped triangle
|
|
const SkPoint gPoints10[] = {
|
|
{ -10.0f, -50.0f },
|
|
{ 10.0f, -50.0f },
|
|
{ 50.0f, 31.0f },
|
|
{ 40.0f, 50.0f },
|
|
{ -40.0f, 50.0f },
|
|
{ -50.0f, 31.0f },
|
|
};
|
|
|
|
// tab
|
|
const SkPoint gPoints11[] = {
|
|
{ -45, -25 },
|
|
{ 45, -25 },
|
|
{ 45, 25 },
|
|
{ 20, 25 },
|
|
{ 19.6157f, 25.f + 3.9018f },
|
|
{ 18.4776f, 25.f + 7.6537f },
|
|
{ 16.6294f, 25.f + 11.1114f },
|
|
{ 14.1421f, 25.f + 14.1421f },
|
|
{ 11.1114f, 25.f + 16.6294f },
|
|
{ 7.6537f, 25.f + 18.4776f },
|
|
{ 3.9018f, 25.f + 19.6157f },
|
|
{ 0, 45.f },
|
|
{ -3.9018f, 25.f + 19.6157f },
|
|
{ -7.6537f, 25.f + 18.4776f },
|
|
{ -11.1114f, 25.f + 16.6294f },
|
|
{ -14.1421f, 25.f + 14.1421f },
|
|
{ -16.6294f, 25.f + 11.1114f },
|
|
{ -18.4776f, 25.f + 7.6537f },
|
|
{ -19.6157f, 25.f + 3.9018f },
|
|
{ -20, 25 },
|
|
{ -45, 25 }
|
|
};
|
|
|
|
// star of david
|
|
const SkPoint gPoints12[] = {
|
|
{ 0.0f, -50.0f },
|
|
{ 14.43f, -25.0f },
|
|
{ 43.30f, -25.0f },
|
|
{ 28.86f, 0.0f },
|
|
{ 43.30f, 25.0f },
|
|
{ 14.43f, 25.0f },
|
|
{ 0.0f, 50.0f },
|
|
{ -14.43f, 25.0f },
|
|
{ -43.30f, 25.0f },
|
|
{ -28.86f, 0.0f },
|
|
{ -43.30f, -25.0f },
|
|
{ -14.43f, -25.0f },
|
|
};
|
|
|
|
// notch
|
|
const SkScalar kBottom = 25.f;
|
|
const SkPoint gPoints13[] = {
|
|
{ -50, kBottom - 50.f },
|
|
{ 50, kBottom - 50.f },
|
|
{ 50, kBottom },
|
|
{ 20, kBottom },
|
|
{ 19.6157f, kBottom - 3.9018f },
|
|
{ 18.4776f, kBottom - 7.6537f },
|
|
{ 16.6294f, kBottom - 11.1114f },
|
|
{ 14.1421f, kBottom - 14.1421f },
|
|
{ 11.1114f, kBottom - 16.6294f },
|
|
{ 7.6537f, kBottom - 18.4776f },
|
|
{ 3.9018f, kBottom - 19.6157f },
|
|
{ 0, kBottom - 20.f },
|
|
{ -3.9018f, kBottom - 19.6157f },
|
|
{ -7.6537f, kBottom - 18.4776f },
|
|
{ -11.1114f, kBottom - 16.6294f },
|
|
{ -14.1421f, kBottom - 14.1421f },
|
|
{ -16.6294f, kBottom - 11.1114f },
|
|
{ -18.4776f, kBottom - 7.6537f },
|
|
{ -19.6157f, kBottom - 3.9018f },
|
|
{ -20, kBottom },
|
|
{ -50, kBottom }
|
|
};
|
|
|
|
// crown
|
|
const SkPoint gPoints14[] = {
|
|
{ -40, -39 },
|
|
{ 40, -39 },
|
|
{ 40, -20 },
|
|
{ 30, 40 },
|
|
{ 20, -20 },
|
|
{ 10, 40 },
|
|
{ 0, -20 },
|
|
{ -10, 40 },
|
|
{ -20, -20 },
|
|
{ -30, 40 },
|
|
{ -40, -20 }
|
|
};
|
|
|
|
// dumbbell
|
|
const SkPoint gPoints15[] = {
|
|
{ -26, -3 },
|
|
{ -24, -6.2f },
|
|
{ -22.5f, -8 },
|
|
{ -20, -9.9f },
|
|
{ -17.5f, -10.3f },
|
|
{ -15, -10.9f },
|
|
{ -12.5f, -10.2f },
|
|
{ -10, -9.7f },
|
|
{ -7.5f, -8.1f },
|
|
{ -5, -7.7f },
|
|
{ -2.5f, -7.4f },
|
|
{ 0, -7.7f },
|
|
{ 3, -9 },
|
|
{ 6.5f, -11.5f },
|
|
{ 10.6f, -14 },
|
|
{ 14, -15.2f },
|
|
{ 17, -15.5f },
|
|
{ 20, -15.2f },
|
|
{ 23.4f, -14 },
|
|
{ 27.5f, -11.5f },
|
|
{ 30, -8 },
|
|
{ 32, -4 },
|
|
{ 32.5f, 0 },
|
|
{ 32, 4 },
|
|
{ 30, 8 },
|
|
{ 27.5f, 11.5f },
|
|
{ 23.4f, 14 },
|
|
{ 20, 15.2f },
|
|
{ 17, 15.5f },
|
|
{ 14, 15.2f },
|
|
{ 10.6f, 14 },
|
|
{ 6.5f, 11.5f },
|
|
{ 3, 9 },
|
|
{ 0, 7.7f },
|
|
{ -2.5f, 7.4f },
|
|
{ -5, 7.7f },
|
|
{ -7.5f, 8.1f },
|
|
{ -10, 9.7f },
|
|
{ -12.5f, 10.2f },
|
|
{ -15, 10.9f },
|
|
{ -17.5f, 10.3f },
|
|
{ -20, 9.9f },
|
|
{ -22.5f, 8 },
|
|
{ -24, 6.2f },
|
|
{ -26, 3 },
|
|
{ -26.5f, 0 }
|
|
};
|
|
|
|
// truncated dumbbell
|
|
// (checks winding computation in OffsetSimplePolygon)
|
|
const SkPoint gPoints16[] = {
|
|
{ -15 + 3, -9 },
|
|
{ -15 + 6.5f, -11.5f },
|
|
{ -15 + 10.6f, -14 },
|
|
{ -15 + 14, -15.2f },
|
|
{ -15 + 17, -15.5f },
|
|
{ -15 + 20, -15.2f },
|
|
{ -15 + 23.4f, -14 },
|
|
{ -15 + 27.5f, -11.5f },
|
|
{ -15 + 30, -8 },
|
|
{ -15 + 32, -4 },
|
|
{ -15 + 32.5f, 0 },
|
|
{ -15 + 32, 4 },
|
|
{ -15 + 30, 8 },
|
|
{ -15 + 27.5f, 11.5f },
|
|
{ -15 + 23.4f, 14 },
|
|
{ -15 + 20, 15.2f },
|
|
{ -15 + 17, 15.5f },
|
|
{ -15 + 14, 15.2f },
|
|
{ -15 + 10.6f, 14 },
|
|
{ -15 + 6.5f, 11.5f },
|
|
{ -15 + 3, 9 },
|
|
};
|
|
|
|
// square notch
|
|
// (to detect segment-segment intersection)
|
|
const SkPoint gPoints17[] = {
|
|
{ -50, kBottom - 50.f },
|
|
{ 50, kBottom - 50.f },
|
|
{ 50, kBottom },
|
|
{ 20, kBottom },
|
|
{ 20, kBottom - 20.f },
|
|
{ -20, kBottom - 20.f },
|
|
{ -20, kBottom },
|
|
{ -50, kBottom }
|
|
};
|
|
|
|
// box with Peano curve
|
|
const SkPoint gPoints18[] = {
|
|
{ 0, 0 },
|
|
{ 0, -12 },
|
|
{ -6, -12 },
|
|
{ -6, 0 },
|
|
{ -12, 0 },
|
|
{ -12, -12},
|
|
{ -18, -12},
|
|
{ -18, 18},
|
|
{ -12, 18},
|
|
{-12, 6},
|
|
{-6, 6},
|
|
{-6, 36},
|
|
{-12, 36},
|
|
{-12, 24},
|
|
{-18, 24},
|
|
{-18, 36},
|
|
{-24, 36},
|
|
{-24, 24},
|
|
{-30, 24},
|
|
{-30, 36},
|
|
{-36, 36},
|
|
{-36, 6},
|
|
{-30, 6},
|
|
{-30, 18},
|
|
{-24, 18},
|
|
{-24, -12},
|
|
{-30, -12},
|
|
{-30, 0},
|
|
{-36, 0},
|
|
{-36, -36},
|
|
{36, -36},
|
|
{36, 36},
|
|
{12, 36},
|
|
{12, 24},
|
|
{6, 24},
|
|
{6, 36},
|
|
{0, 36},
|
|
{0, 6},
|
|
{6, 6},
|
|
{6, 18},
|
|
{12, 18},
|
|
{12, -12},
|
|
{6, -12},
|
|
{6, 0}
|
|
};
|
|
|
|
|
|
const SkPoint* gConvexPoints[] = {
|
|
gPoints0, gPoints1, gPoints2, gPoints3, gPoints4, gPoints5, gPoints6,
|
|
gPoints7, gPoints8, gPoints9, gPoints10,
|
|
};
|
|
|
|
const size_t gConvexSizes[] = {
|
|
SK_ARRAY_COUNT(gPoints0),
|
|
SK_ARRAY_COUNT(gPoints1),
|
|
SK_ARRAY_COUNT(gPoints2),
|
|
SK_ARRAY_COUNT(gPoints3),
|
|
SK_ARRAY_COUNT(gPoints4),
|
|
SK_ARRAY_COUNT(gPoints5),
|
|
SK_ARRAY_COUNT(gPoints6),
|
|
SK_ARRAY_COUNT(gPoints7),
|
|
SK_ARRAY_COUNT(gPoints8),
|
|
SK_ARRAY_COUNT(gPoints9),
|
|
SK_ARRAY_COUNT(gPoints10),
|
|
};
|
|
static_assert(SK_ARRAY_COUNT(gConvexSizes) == SK_ARRAY_COUNT(gConvexPoints), "array_mismatch");
|
|
|
|
const SkPoint* gSimplePoints[] = {
|
|
gPoints0, gPoints1, gPoints2, gPoints4, gPoints5, gPoints7,
|
|
gPoints8, gPoints11, gPoints12, gPoints13, gPoints14, gPoints15,
|
|
gPoints16, gPoints17, gPoints18,
|
|
};
|
|
|
|
const size_t gSimpleSizes[] = {
|
|
SK_ARRAY_COUNT(gPoints0),
|
|
SK_ARRAY_COUNT(gPoints1),
|
|
SK_ARRAY_COUNT(gPoints2),
|
|
SK_ARRAY_COUNT(gPoints4),
|
|
SK_ARRAY_COUNT(gPoints5),
|
|
SK_ARRAY_COUNT(gPoints7),
|
|
SK_ARRAY_COUNT(gPoints8),
|
|
SK_ARRAY_COUNT(gPoints11),
|
|
SK_ARRAY_COUNT(gPoints12),
|
|
SK_ARRAY_COUNT(gPoints13),
|
|
SK_ARRAY_COUNT(gPoints14),
|
|
SK_ARRAY_COUNT(gPoints15),
|
|
SK_ARRAY_COUNT(gPoints16),
|
|
SK_ARRAY_COUNT(gPoints17),
|
|
SK_ARRAY_COUNT(gPoints18),
|
|
};
|
|
static_assert(SK_ARRAY_COUNT(gSimpleSizes) == SK_ARRAY_COUNT(gSimplePoints), "array_mismatch");
|
|
|
|
}
|
|
|
|
namespace skiagm {
|
|
|
|
// This GM is intended to exercise the offsetting of polygons
|
|
// When fVariableOffset is true it will skew the offset by x,
|
|
// to test perspective and other variable offset functions
|
|
class PolygonOffsetGM : public GM {
|
|
public:
|
|
PolygonOffsetGM(bool convexOnly)
|
|
: fConvexOnly(convexOnly) {
|
|
this->setBGColor(0xFFFFFFFF);
|
|
}
|
|
|
|
protected:
|
|
SkString onShortName() override {
|
|
if (fConvexOnly) {
|
|
return SkString("convex-polygon-inset");
|
|
} else {
|
|
return SkString("simple-polygon-offset");
|
|
}
|
|
}
|
|
SkISize onISize() override { return SkISize::Make(kGMWidth, kGMHeight); }
|
|
bool runAsBench() const override { return true; }
|
|
|
|
static void GetConvexPolygon(int index, SkPath::Direction dir,
|
|
std::unique_ptr<SkPoint[]>* data, int* numPts) {
|
|
if (index < (int)SK_ARRAY_COUNT(PolygonOffsetData::gConvexPoints)) {
|
|
// manually specified
|
|
*numPts = (int)PolygonOffsetData::gConvexSizes[index];
|
|
data->reset(new SkPoint[*numPts]);
|
|
if (SkPath::kCW_Direction == dir) {
|
|
for (int i = 0; i < *numPts; ++i) {
|
|
(*data)[i] = PolygonOffsetData::gConvexPoints[index][i];
|
|
}
|
|
} else {
|
|
for (int i = 0; i < *numPts; ++i) {
|
|
(*data)[i] = PolygonOffsetData::gConvexPoints[index][*numPts - i - 1];
|
|
}
|
|
}
|
|
} else {
|
|
// procedurally generated
|
|
SkScalar width = kMaxPathHeight / 2;
|
|
SkScalar height = kMaxPathHeight / 2;
|
|
int numPtsArray[] = { 3, 4, 5, 5, 6, 8, 8, 20, 100 };
|
|
|
|
size_t arrayIndex = index - SK_ARRAY_COUNT(PolygonOffsetData::gConvexPoints);
|
|
SkASSERT(arrayIndex < SK_ARRAY_COUNT(numPtsArray));
|
|
*numPts = numPtsArray[arrayIndex];
|
|
if (arrayIndex == 3 || arrayIndex == 6) {
|
|
// squashed pentagon and octagon
|
|
width = kMaxPathHeight / 5;
|
|
}
|
|
|
|
data->reset(new SkPoint[*numPts]);
|
|
|
|
create_ngon(*numPts, data->get(), width, height, dir);
|
|
}
|
|
}
|
|
|
|
static void GetSimplePolygon(int index, SkPath::Direction dir,
|
|
std::unique_ptr<SkPoint[]>* data, int* numPts) {
|
|
if (index < (int)SK_ARRAY_COUNT(PolygonOffsetData::gSimplePoints)) {
|
|
// manually specified
|
|
*numPts = (int)PolygonOffsetData::gSimpleSizes[index];
|
|
data->reset(new SkPoint[*numPts]);
|
|
if (SkPath::kCW_Direction == dir) {
|
|
for (int i = 0; i < *numPts; ++i) {
|
|
(*data)[i] = PolygonOffsetData::gSimplePoints[index][i];
|
|
}
|
|
} else {
|
|
for (int i = 0; i < *numPts; ++i) {
|
|
(*data)[i] = PolygonOffsetData::gSimplePoints[index][*numPts - i - 1];
|
|
}
|
|
}
|
|
} else {
|
|
// procedurally generated
|
|
SkScalar width = kMaxPathHeight / 2;
|
|
SkScalar height = kMaxPathHeight / 2;
|
|
int numPtsArray[] = { 5, 7, 8, 20, 100 };
|
|
|
|
size_t arrayIndex = index - SK_ARRAY_COUNT(PolygonOffsetData::gSimplePoints);
|
|
arrayIndex = SkTMin(arrayIndex, SK_ARRAY_COUNT(numPtsArray) - 1);
|
|
SkASSERT(arrayIndex < SK_ARRAY_COUNT(numPtsArray));
|
|
*numPts = numPtsArray[arrayIndex];
|
|
// squash horizontally
|
|
width = kMaxPathHeight / 5;
|
|
|
|
data->reset(new SkPoint[*numPts]);
|
|
|
|
create_ngon(*numPts, data->get(), width, height, dir);
|
|
}
|
|
}
|
|
// Draw a single polygon with insets and potentially outsets
|
|
void drawPolygon(SkCanvas* canvas, int index, SkPoint* offset) {
|
|
|
|
SkPoint center;
|
|
SkRect bounds;
|
|
{
|
|
std::unique_ptr<SkPoint[]> data(nullptr);
|
|
int numPts;
|
|
if (fConvexOnly) {
|
|
GetConvexPolygon(index, SkPath::kCW_Direction, &data, &numPts);
|
|
} else {
|
|
GetSimplePolygon(index, SkPath::kCW_Direction, &data, &numPts);
|
|
}
|
|
bounds.set(data.get(), numPts);
|
|
if (!fConvexOnly) {
|
|
bounds.outset(kMaxOutset, kMaxOutset);
|
|
}
|
|
if (offset->fX + bounds.width() > kGMWidth) {
|
|
offset->fX = 0;
|
|
offset->fY += kMaxPathHeight;
|
|
}
|
|
center = { offset->fX + SkScalarHalf(bounds.width()), offset->fY };
|
|
offset->fX += bounds.width();
|
|
}
|
|
|
|
const SkPath::Direction dirs[2] = { SkPath::kCW_Direction, SkPath::kCCW_Direction };
|
|
const float insets[] = { 5, 10, 15, 20, 25, 30, 35, 40 };
|
|
const float offsets[] = { 2, 5, 9, 14, 20, 27, 35, 44, -2, -5, -9 };
|
|
const SkColor colors[] = { 0xFF901313, 0xFF8D6214, 0xFF698B14, 0xFF1C8914,
|
|
0xFF148755, 0xFF146C84, 0xFF142482, 0xFF4A1480,
|
|
0xFF901313, 0xFF8D6214, 0xFF698B14 };
|
|
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
paint.setStrokeWidth(1);
|
|
|
|
std::unique_ptr<SkPoint[]> data(nullptr);
|
|
int numPts;
|
|
if (fConvexOnly) {
|
|
GetConvexPolygon(index, dirs[index % 2], &data, &numPts);
|
|
} else {
|
|
GetSimplePolygon(index, dirs[index % 2], &data, &numPts);
|
|
}
|
|
|
|
{
|
|
SkPath path;
|
|
path.moveTo(data.get()[0]);
|
|
for (int i = 1; i < numPts; ++i) {
|
|
path.lineTo(data.get()[i]);
|
|
}
|
|
path.close();
|
|
canvas->save();
|
|
canvas->translate(center.fX, center.fY);
|
|
canvas->drawPath(path, paint);
|
|
canvas->restore();
|
|
}
|
|
|
|
SkTDArray<SkPoint> offsetPoly;
|
|
size_t count = fConvexOnly ? SK_ARRAY_COUNT(insets) : SK_ARRAY_COUNT(offsets);
|
|
for (size_t i = 0; i < count; ++i) {
|
|
SkScalar offset = fConvexOnly ? insets[i] : offsets[i];
|
|
std::function<SkScalar(const SkPoint&)> offsetFunc;
|
|
|
|
bool result;
|
|
if (fConvexOnly) {
|
|
result = SkInsetConvexPolygon(data.get(), numPts, offset, &offsetPoly);
|
|
} else {
|
|
result = SkOffsetSimplePolygon(data.get(), numPts, offset, &offsetPoly);
|
|
}
|
|
if (result) {
|
|
SkPath path;
|
|
path.moveTo(offsetPoly[0]);
|
|
for (int i = 1; i < offsetPoly.count(); ++i) {
|
|
path.lineTo(offsetPoly[i]);
|
|
}
|
|
path.close();
|
|
|
|
paint.setColor(ToolUtils::color_to_565(colors[i]));
|
|
canvas->save();
|
|
canvas->translate(center.fX, center.fY);
|
|
canvas->drawPath(path, paint);
|
|
canvas->restore();
|
|
}
|
|
}
|
|
}
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
// the right edge of the last drawn path
|
|
SkPoint offset = { 0, SkScalarHalf(kMaxPathHeight) };
|
|
if (!fConvexOnly) {
|
|
offset.fY += kMaxOutset;
|
|
}
|
|
|
|
for (int i = 0; i < kNumPaths; ++i) {
|
|
this->drawPolygon(canvas, i, &offset);
|
|
}
|
|
}
|
|
|
|
private:
|
|
static constexpr int kNumPaths = 20;
|
|
static constexpr int kMaxPathHeight = 100;
|
|
static constexpr int kMaxOutset = 16;
|
|
static constexpr int kGMWidth = 512;
|
|
static constexpr int kGMHeight = 512;
|
|
|
|
bool fConvexOnly;
|
|
|
|
typedef GM INHERITED;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DEF_GM(return new PolygonOffsetGM(true);)
|
|
DEF_GM(return new PolygonOffsetGM(false);)
|
|
}
|