add interp path
Add path methods to determine if a pair of paths can be interpolated, and to interpolate them. R=reed@google.com, robertphillips@google.com BUG=skia:4549 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1703943003 Review URL: https://codereview.chromium.org/1703943003
This commit is contained in:
parent
c5eddd7d8d
commit
8e7b19d0f0
@ -37,6 +37,27 @@ public:
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/** Return true if the paths contain an equal array of verbs and weights. Paths
|
||||
* with equal verb counts can be readily interpolated. If the paths contain one
|
||||
* or more conics, the conics' weights must also match.
|
||||
*
|
||||
* @param compare The path to compare.
|
||||
*
|
||||
* @return true if the paths have the same verbs and weights.
|
||||
*/
|
||||
bool isInterpolatable(const SkPath& compare) const;
|
||||
|
||||
/** Interpolate between two paths with same-sized point arrays.
|
||||
* The out path contains the verbs and weights of this path.
|
||||
* The out points are a weighted average of this path and the ending path.
|
||||
*
|
||||
* @param ending The path to interpolate between.
|
||||
* @param weight The weight, from 0 to 1. The output points are set to
|
||||
* (this->points * weight) + ending->points * (1 - weight).
|
||||
* @return true if the paths could be interpolated.
|
||||
*/
|
||||
bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const;
|
||||
|
||||
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
|
||||
/** Returns true if the caller is the only owner of the underlying path data */
|
||||
bool unique() const { return fPathRef->unique(); }
|
||||
|
@ -271,6 +271,8 @@ public:
|
||||
*/
|
||||
uint32_t writeSize() const;
|
||||
|
||||
void interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const;
|
||||
|
||||
/**
|
||||
* Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the
|
||||
* same ID then they have the same verbs and points. However, two path refs may have the same
|
||||
|
@ -193,6 +193,33 @@ void SkPath::swap(SkPath& that) {
|
||||
}
|
||||
}
|
||||
|
||||
bool SkPath::isInterpolatable(const SkPath& compare) const {
|
||||
int count = fPathRef->countVerbs();
|
||||
if (count != compare.fPathRef->countVerbs()) {
|
||||
return false;
|
||||
}
|
||||
if (!count) {
|
||||
return true;
|
||||
}
|
||||
if (memcmp(fPathRef->verbsMemBegin(), compare.fPathRef->verbsMemBegin(),
|
||||
count)) {
|
||||
return false;
|
||||
}
|
||||
return !SkToBool(memcmp(fPathRef->conicWeights(), compare.fPathRef->conicWeights(),
|
||||
fPathRef->countWeights() * sizeof(*fPathRef->conicWeights())));
|
||||
}
|
||||
|
||||
bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const {
|
||||
int verbCount = fPathRef->countVerbs();
|
||||
if (verbCount != ending.fPathRef->countVerbs()) {
|
||||
return false;
|
||||
}
|
||||
out->reset();
|
||||
out->addPath(*this);
|
||||
fPathRef->interpolate(*ending.fPathRef, weight, out->fPathRef);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool check_edge_against_rect(const SkPoint& p0,
|
||||
const SkPoint& p1,
|
||||
const SkRect& rect,
|
||||
|
@ -299,6 +299,19 @@ void SkPathRef::copy(const SkPathRef& ref,
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
|
||||
void SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const {
|
||||
const SkScalar* inValues = &ending.getPoints()->fX;
|
||||
SkScalar* outValues = &out->getPoints()->fX;
|
||||
int count = out->countPoints() * 2;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
outValues[index] = outValues[index] * weight + inValues[index] * (1 - weight);
|
||||
}
|
||||
out->fBoundsIsDirty = true;
|
||||
out->fIsOval = false;
|
||||
out->fIsRRect = false;
|
||||
}
|
||||
|
||||
SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
|
||||
int numVbs,
|
||||
SkScalar** weights) {
|
||||
|
@ -3904,6 +3904,49 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static void test_interp(skiatest::Reporter* reporter) {
|
||||
SkPath p1, p2, out;
|
||||
REPORTER_ASSERT(reporter, p1.isInterpolatable(p2));
|
||||
REPORTER_ASSERT(reporter, p1.interpolate(p2, 0, &out));
|
||||
REPORTER_ASSERT(reporter, p1 == out);
|
||||
REPORTER_ASSERT(reporter, p1.interpolate(p2, 1, &out));
|
||||
REPORTER_ASSERT(reporter, p1 == out);
|
||||
p1.moveTo(0, 2);
|
||||
p1.lineTo(0, 4);
|
||||
REPORTER_ASSERT(reporter, !p1.isInterpolatable(p2));
|
||||
REPORTER_ASSERT(reporter, !p1.interpolate(p2, 1, &out));
|
||||
p2.moveTo(6, 0);
|
||||
p2.lineTo(8, 0);
|
||||
REPORTER_ASSERT(reporter, p1.isInterpolatable(p2));
|
||||
REPORTER_ASSERT(reporter, p1.interpolate(p2, 0, &out));
|
||||
REPORTER_ASSERT(reporter, p2 == out);
|
||||
REPORTER_ASSERT(reporter, p1.interpolate(p2, 1, &out));
|
||||
REPORTER_ASSERT(reporter, p1 == out);
|
||||
REPORTER_ASSERT(reporter, p1.interpolate(p2, 0.5f, &out));
|
||||
REPORTER_ASSERT(reporter, out.getBounds() == SkRect::MakeLTRB(3, 1, 4, 2));
|
||||
p1.reset();
|
||||
p1.moveTo(4, 4);
|
||||
p1.conicTo(5, 4, 5, 5, 1 / SkScalarSqrt(2));
|
||||
p2.reset();
|
||||
p2.moveTo(4, 2);
|
||||
p2.conicTo(7, 2, 7, 5, 1 / SkScalarSqrt(2));
|
||||
REPORTER_ASSERT(reporter, p1.isInterpolatable(p2));
|
||||
REPORTER_ASSERT(reporter, p1.interpolate(p2, 0.5f, &out));
|
||||
REPORTER_ASSERT(reporter, out.getBounds() == SkRect::MakeLTRB(4, 3, 6, 5));
|
||||
p2.reset();
|
||||
p2.moveTo(4, 2);
|
||||
p2.conicTo(6, 3, 6, 5, 1);
|
||||
REPORTER_ASSERT(reporter, !p1.isInterpolatable(p2));
|
||||
p2.reset();
|
||||
p2.moveTo(4, 4);
|
||||
p2.conicTo(5, 4, 5, 5, 0.5f);
|
||||
REPORTER_ASSERT(reporter, !p1.isInterpolatable(p2));
|
||||
}
|
||||
|
||||
DEF_TEST(PathInterp, reporter) {
|
||||
test_interp(reporter);
|
||||
}
|
||||
|
||||
DEF_TEST(PathContains, reporter) {
|
||||
test_contains(reporter);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user