experimental alternative isconvex

Bug: skia:
Change-Id: I55175a95d37aad9a656cd211fc6c7238bdb7d674
Reviewed-on: https://skia-review.googlesource.com/c/173361
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2018-11-30 15:55:15 -05:00 committed by Skia Commit-Bot
parent 9e55daa7ec
commit 64284e1482
3 changed files with 150 additions and 0 deletions

View File

@ -1691,3 +1691,116 @@ bool SkTriangulateSimplePolygon(const SkPoint* polygonVerts, uint16_t* indexMap,
return true;
}
///////////
static double crs(SkVector a, SkVector b) {
return a.fX * b.fY - a.fY * b.fX;
}
static int sign(SkScalar v) {
return v < 0 ? -1 : (v > 0);
}
struct SignTracker {
int fSign;
int fSignChanges;
void reset() {
fSign = 0;
fSignChanges = 0;
}
void init(int s) {
SkASSERT(fSignChanges == 0);
SkASSERT(s == 1 || s == -1 || s == 0);
fSign = s;
fSignChanges = 1;
}
void update(int s) {
if (s) {
if (fSign != s) {
fSignChanges += 1;
fSign = s;
}
}
}
};
struct ConvexTracker {
SkVector fFirst, fPrev;
SignTracker fDSign, fCSign;
int fVecCounter;
bool fIsConcave;
ConvexTracker() { this->reset(); }
void reset() {
fPrev = {0, 0};
fDSign.reset();
fCSign.reset();
fVecCounter = 0;
fIsConcave = false;
}
void addVec(SkPoint p1, SkPoint p0) {
this->addVec(p1 - p0);
}
void addVec(SkVector v) {
if (v.fX == 0 && v.fY == 0) {
return;
}
fVecCounter += 1;
if (fVecCounter == 1) {
fFirst = fPrev = v;
fDSign.update(sign(v.fX));
return;
}
SkScalar d = v.fX;
SkScalar c = crs(fPrev, v);
int sign_c;
if (c) {
sign_c = sign(c);
} else {
if (d >= 0) {
sign_c = fCSign.fSign;
} else {
sign_c = -fCSign.fSign;
}
}
fDSign.update(sign(d));
fCSign.update(sign_c);
fPrev = v;
if (fDSign.fSignChanges > 3 || fCSign.fSignChanges > 1) {
fIsConcave = true;
}
}
void finalCross() {
this->addVec(fFirst);
}
};
bool SkIsPolyConvex_experimental(const SkPoint pts[], int count) {
if (count <= 3) {
return true;
}
ConvexTracker tracker;
for (int i = 0; i < count - 1; ++i) {
tracker.addVec(pts[i + 1], pts[i]);
if (tracker.fIsConcave) {
return false;
}
}
tracker.addVec(pts[0], pts[count - 1]);
tracker.finalCross();
return !tracker.fIsConcave;
}

View File

@ -103,4 +103,7 @@ bool SkIsConvexPolygon(const SkPoint* polygonVerts, int polygonSize);
bool SkTriangulateSimplePolygon(const SkPoint* polygonVerts, uint16_t* indexMap, int polygonSize,
SkTDArray<uint16_t>* triangleIndices);
// Experiment: doesn't handle really big floats (returns false), always returns true for count <= 3
bool SkIsPolyConvex_experimental(const SkPoint[], int count);
#endif

View File

@ -255,3 +255,37 @@ DEF_TEST(PolyUtils, reporter) {
REPORTER_ASSERT(reporter, !SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
&triangleIndices));
}
struct PtSet {
const SkPoint* fPts;
int fN;
};
DEF_TEST(IsPolyConvex_experimental, r) {
#define PTSET(array) {array, SK_ARRAY_COUNT(array)}
const SkPoint g0[] = { {0, 0}, {10, 0}, {10, 10}, {0, 10} };
const PtSet convex[] = { PTSET(g0) };
for (auto& set : convex) {
REPORTER_ASSERT(r, SkIsPolyConvex_experimental(set.fPts, set.fN));
}
const SkPoint b0[] = { {0, 0}, {10, 0}, {0, 10}, {10, 10} };
const SkPoint b1[] = {
{24.8219f, 8.05052f},
{26.0616f, 24.4895f}, {8.49582f, 16.815f},
{27.3047f, 7.75211f},
{21.927f, 27.2051f},
};
const SkPoint b2[] = {
{20, 20}, {20, 50}, {80, 50}, {20, 50}, {20, 80},
};
const PtSet concave[] = { PTSET(b0), PTSET(b1), PTSET(b2) };
for (auto& set : concave) {
if (SkIsPolyConvex_experimental(set.fPts, set.fN)) {
REPORTER_ASSERT(r, !SkIsPolyConvex_experimental(set.fPts, set.fN));
}
}
}