mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 21:53:41 +00:00
common: strokeTrim api introduced
New api sets/gets the trim of the stroke along the defined path segment, allowing control over which part of the stroke is visible. @issue: https://github.com/thorvg/thorvg/issues/2190
This commit is contained in:
parent
ca92d4a53b
commit
33f5ea34c0
7 changed files with 88 additions and 38 deletions
31
inc/thorvg.h
31
inc/thorvg.h
|
@ -1021,7 +1021,6 @@ public:
|
||||||
*/
|
*/
|
||||||
Result strokeJoin(StrokeJoin join) noexcept;
|
Result strokeJoin(StrokeJoin join) noexcept;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the stroke miterlimit.
|
* @brief Sets the stroke miterlimit.
|
||||||
*
|
*
|
||||||
|
@ -1033,6 +1032,22 @@ public:
|
||||||
*/
|
*/
|
||||||
Result strokeMiterlimit(float miterlimit) noexcept;
|
Result strokeMiterlimit(float miterlimit) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the trim of the stroke along the defined path segment, allowing control over which part of the stroke is visible.
|
||||||
|
*
|
||||||
|
* The values of the arguments @p begin, @p end, and @p offset are in the range of 0.0 to 1.0, representing the beginning of the path and the end, respectively.
|
||||||
|
*
|
||||||
|
* @param[in] begin Specifies the start of the segment to display along the path.
|
||||||
|
* @param[in] end Specifies the end of the segment to display along the path.
|
||||||
|
* @param[in] simultaneous Determines how to trim multiple paths within a single shape. If set to @c true (default), trimming is applied simultaneously to all paths;
|
||||||
|
* Otherwise, all paths are treated as a single entity with a combined length equal to the sum of their individual lengths and are trimmed as such.
|
||||||
|
*
|
||||||
|
* @retval Result::Success when succeed.
|
||||||
|
*
|
||||||
|
* @note Experimental API
|
||||||
|
*/
|
||||||
|
Result strokeTrim(float begin, float end, bool simultaneous = true) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the solid color for all of the figures from the path.
|
* @brief Sets the solid color for all of the figures from the path.
|
||||||
*
|
*
|
||||||
|
@ -1072,7 +1087,6 @@ public:
|
||||||
*/
|
*/
|
||||||
Result fill(FillRule r) noexcept;
|
Result fill(FillRule r) noexcept;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the rendering order of the stroke and the fill.
|
* @brief Sets the rendering order of the stroke and the fill.
|
||||||
*
|
*
|
||||||
|
@ -1084,7 +1098,6 @@ public:
|
||||||
*/
|
*/
|
||||||
Result order(bool strokeFirst) noexcept;
|
Result order(bool strokeFirst) noexcept;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the commands data of the path.
|
* @brief Gets the commands data of the path.
|
||||||
*
|
*
|
||||||
|
@ -1190,6 +1203,18 @@ public:
|
||||||
*/
|
*/
|
||||||
float strokeMiterlimit() const noexcept;
|
float strokeMiterlimit() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the trim of the stroke along the defined path segment.
|
||||||
|
*
|
||||||
|
* @param[out] begin The starting point of the segment to display along the path.
|
||||||
|
* @param[out] end Specifies the end of the segment to display along the path.
|
||||||
|
*
|
||||||
|
* @retval @c true if trimming is applied simultaneously to all paths of the shape, @c false otherwise.
|
||||||
|
*
|
||||||
|
* @note Experimental API
|
||||||
|
*/
|
||||||
|
bool strokeTrim(float* begin, float* end) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new Shape object.
|
* @brief Creates a new Shape object.
|
||||||
*
|
*
|
||||||
|
|
|
@ -916,7 +916,7 @@ static void _updateTrimpath(TVG_UNUSED LottieGroup* parent, LottieObject** child
|
||||||
end = (length * end) + pbegin;
|
end = (length * end) + pbegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
P(ctx->propagator)->strokeTrim(begin, end, trimpath->type == LottieTrimpath::Type::Individual ? true : false);
|
P(ctx->propagator)->strokeTrim(begin, end, trimpath->type == LottieTrimpath::Type::Simultaneous);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -121,11 +121,11 @@ LottieImage::~LottieImage()
|
||||||
|
|
||||||
void LottieTrimpath::segment(float frameNo, float& start, float& end, LottieExpressions* exps)
|
void LottieTrimpath::segment(float frameNo, float& start, float& end, LottieExpressions* exps)
|
||||||
{
|
{
|
||||||
auto s = this->start(frameNo, exps) * 0.01f;
|
start = this->start(frameNo, exps) * 0.01f;
|
||||||
auto e = this->end(frameNo, exps) * 0.01f;
|
end = this->end(frameNo, exps) * 0.01f;
|
||||||
auto o = fmodf(this->offset(frameNo, exps), 360.0f) / 360.0f; //0 ~ 1
|
auto o = fmodf(this->offset(frameNo, exps), 360.0f) / 360.0f; //0 ~ 1
|
||||||
|
|
||||||
auto diff = fabs(s - e);
|
auto diff = fabs(start - end);
|
||||||
if (mathZero(diff)) {
|
if (mathZero(diff)) {
|
||||||
start = 0.0f;
|
start = 0.0f;
|
||||||
end = 0.0f;
|
end = 0.0f;
|
||||||
|
@ -137,28 +137,8 @@ void LottieTrimpath::segment(float frameNo, float& start, float& end, LottieExpr
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s += o;
|
start += o;
|
||||||
e += o;
|
end += o;
|
||||||
|
|
||||||
auto loop = true;
|
|
||||||
|
|
||||||
//no loop
|
|
||||||
if (s > 1.0f && e > 1.0f) loop = false;
|
|
||||||
if (s < 0.0f && e < 0.0f) loop = false;
|
|
||||||
if (s >= 0.0f && s <= 1.0f && e >= 0.0f && e <= 1.0f) loop = false;
|
|
||||||
|
|
||||||
if (s > 1.0f) s -= 1.0f;
|
|
||||||
if (s < 0.0f) s += 1.0f;
|
|
||||||
if (e > 1.0f) e -= 1.0f;
|
|
||||||
if (e < 0.0f) e += 1.0f;
|
|
||||||
|
|
||||||
if (loop) {
|
|
||||||
start = s > e ? s : e;
|
|
||||||
end = s < e ? s : e;
|
|
||||||
} else {
|
|
||||||
start = s < e ? s : e;
|
|
||||||
end = s > e ? s : e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -331,8 +331,9 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PathCommand::MoveTo: {
|
case PathCommand::MoveTo: {
|
||||||
if (rshape->stroke->trim.individual) _dashMoveTo(dash, pts);
|
if (rshape->stroke->trim.simultaneous) _dashMoveTo(dash, offIdx, offset, pts);
|
||||||
else _dashMoveTo(dash, offIdx, offset, pts);
|
else _dashMoveTo(dash, pts);
|
||||||
|
|
||||||
++pts;
|
++pts;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -371,7 +372,7 @@ static float _outlineLength(const RenderShape* rshape)
|
||||||
const Point* close = nullptr;
|
const Point* close = nullptr;
|
||||||
auto length = 0.0f;
|
auto length = 0.0f;
|
||||||
auto slength = -1.0f;
|
auto slength = -1.0f;
|
||||||
auto simultaneous = !rshape->stroke->trim.individual;
|
auto simultaneous = rshape->stroke->trim.simultaneous;
|
||||||
|
|
||||||
//Compute the whole length
|
//Compute the whole length
|
||||||
while (cmdCnt-- > 0) {
|
while (cmdCnt-- > 0) {
|
||||||
|
|
|
@ -140,7 +140,7 @@ struct RenderStroke
|
||||||
struct {
|
struct {
|
||||||
float begin = 0.0f;
|
float begin = 0.0f;
|
||||||
float end = 1.0f;
|
float end = 1.0f;
|
||||||
bool individual = false;
|
bool simultaneous = true;
|
||||||
} trim;
|
} trim;
|
||||||
|
|
||||||
~RenderStroke()
|
~RenderStroke()
|
||||||
|
|
|
@ -362,6 +362,7 @@ Result Shape::strokeJoin(StrokeJoin join) noexcept
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Shape::strokeMiterlimit(float miterlimit) noexcept
|
Result Shape::strokeMiterlimit(float miterlimit) noexcept
|
||||||
{
|
{
|
||||||
// https://www.w3.org/TR/SVG2/painting.html#LineJoin
|
// https://www.w3.org/TR/SVG2/painting.html#LineJoin
|
||||||
|
@ -385,12 +386,26 @@ StrokeJoin Shape::strokeJoin() const noexcept
|
||||||
return pImpl->rs.strokeJoin();
|
return pImpl->rs.strokeJoin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float Shape::strokeMiterlimit() const noexcept
|
float Shape::strokeMiterlimit() const noexcept
|
||||||
{
|
{
|
||||||
return pImpl->rs.strokeMiterlimit();
|
return pImpl->rs.strokeMiterlimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Result Shape::strokeTrim(float begin, float end, bool simultaneous) noexcept
|
||||||
|
{
|
||||||
|
pImpl->strokeTrim(begin, end, simultaneous);
|
||||||
|
return Result::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Shape::strokeTrim(float* begin, float* end) const noexcept
|
||||||
|
{
|
||||||
|
return pImpl->strokeTrim(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Shape::fill(FillRule r) noexcept
|
Result Shape::fill(FillRule r) noexcept
|
||||||
{
|
{
|
||||||
pImpl->rs.rule = r;
|
pImpl->rs.rule = r;
|
||||||
|
|
|
@ -216,21 +216,50 @@ struct Shape::Impl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool strokeTrim(float begin, float end, bool individual)
|
void strokeTrim(float begin, float end, bool simultaneous)
|
||||||
{
|
{
|
||||||
if (!rs.stroke) {
|
if (!rs.stroke) {
|
||||||
if (begin == 0.0f && end == 1.0f) return true;
|
if (begin == 0.0f && end == 1.0f) return;
|
||||||
rs.stroke = new RenderStroke();
|
rs.stroke = new RenderStroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mathEqual(rs.stroke->trim.begin, begin) && mathEqual(rs.stroke->trim.end, end)) return true;
|
if (mathEqual(rs.stroke->trim.begin, begin) && mathEqual(rs.stroke->trim.end, end) &&
|
||||||
|
rs.stroke->trim.simultaneous == simultaneous) return;
|
||||||
|
|
||||||
|
auto loop = true;
|
||||||
|
|
||||||
|
if (begin > 1.0f && end > 1.0f) loop = false;
|
||||||
|
if (begin < 0.0f && end < 0.0f) loop = false;
|
||||||
|
if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f && end <= 1.0f) loop = false;
|
||||||
|
|
||||||
|
if (begin > 1.0f) begin -= 1.0f;
|
||||||
|
if (begin < 0.0f) begin += 1.0f;
|
||||||
|
if (end > 1.0f) end -= 1.0f;
|
||||||
|
if (end < 0.0f) end += 1.0f;
|
||||||
|
|
||||||
|
if ((loop && begin < end) || (!loop && begin > end)) {
|
||||||
|
auto tmp = begin;
|
||||||
|
begin = end;
|
||||||
|
end = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
rs.stroke->trim.begin = begin;
|
rs.stroke->trim.begin = begin;
|
||||||
rs.stroke->trim.end = end;
|
rs.stroke->trim.end = end;
|
||||||
rs.stroke->trim.individual = individual;
|
rs.stroke->trim.simultaneous = simultaneous;
|
||||||
flag |= RenderUpdateFlag::Stroke;
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
bool strokeTrim(float* begin, float* end)
|
||||||
|
{
|
||||||
|
if (rs.stroke) {
|
||||||
|
if (begin) *begin = rs.stroke->trim.begin;
|
||||||
|
if (end) *end = rs.stroke->trim.end;
|
||||||
|
return rs.stroke->trim.simultaneous;
|
||||||
|
} else {
|
||||||
|
if (begin) *begin = 0.0f;
|
||||||
|
if (end) *end = 1.0f;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool strokeCap(StrokeCap cap)
|
bool strokeCap(StrokeCap cap)
|
||||||
|
|
Loading…
Add table
Reference in a new issue