/*
* Copyright 2025 Google LLC
*
* Use of this source code is governed by a BSD - style license that can be
* found in the LICENSE file .
*/
#include "include/core/SkPath.h"
#include "include/core/SkSpan.h"
#include <optional>
#include <vector>
namespace {
template <typename T> bool span_equal(SkSpan<T> a, SkSpan<T> b) {
if (a.size() != b.size()) {
return false ;
}
if (a.empty()) {
return true;
}
return (a.data() == b.data()) || std::equal(a.begin(), a.end(), b.begin());
}
SkPoint operator *(float s, SkPoint p) {
return {
p.fX * s,
p.fY * s
};
}
SkPoint lerp(SkPoint from, SkPoint to, float t) {
return from + t * (to - from);
}
// These can be copy/pasted into Chrome / Android
// - CanInterpolate()
// - Interpolate()
//
// That would allow us to remove the associated SkPath methods.
//
// Note: they require no private access to SkPath internals, and are not used/called by
// anthing in Skia.
/**
* Returns true if the two paths can be interpolated .
*
* Returns true iff the paths have the same verbs and conicWeights ,
* and the same number of points .
*/
bool CanInterpolate(const SkPath& from, const SkPath& to) {
return from.points().size() == to.points().size() &&
span_equal(from.verbs(), to.verbs()) &&
span_equal(from.conicWeights(), to.conicWeights());
}
/**
* Return a path whose points are lineraly interpolated between from and to ,
* using t ( typically between 0 and 1 ) .
*
* ( logically ) newPoint = ( 1 - t ) * fromPoint + t * toPoint
*
* The result has the same fillType as the ' from ' path .
*
* If the two paths are not interpolatable , this returns { } .
*/
std::optional<SkPath> Interpolate(const SkPath& from, const SkPath& to, float t) {
if (!CanInterpolate(from, to)) {
return {};
}
// note, if from and to have different fill-types, that's up to the client to deal with.
const SkPathFillType fillType = from.getFillType();
const SkSpan<const SkPoint> fromPts = from.points(),
toPts = to.points();
std::vector<SkPoint> dst(fromPts.size());
for (size_t i = 0 ; i < fromPts.size(); ++i) {
dst[i] = lerp(fromPts[i], toPts[i], t);
}
return SkPath::Raw({dst.data(), dst.size()}, from.verbs(), from.conicWeights(), fillType);
}
} // namespace
///////////////////////////////////////////////////////////////////////////////////////////////
bool SkPath::isInterpolatable(const SkPath& compare) const {
return CanInterpolate(*this, compare);
}
SkPath SkPath::makeInterpolate(const SkPath& ending, SkScalar weight) const {
return Interpolate(*this, ending, 1 - weight).value_or(SkPath());
}
bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const {
if (auto result = Interpolate(*this, ending, 1 - weight)) {
*out = *result;
return true;
}
return false ;
}
Messung V0.5 in Prozent C=99 H=100 G=99
¤ Dauer der Verarbeitung: 0.5 Sekunden
¤
*© Formatika GbR, Deutschland