mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +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;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the stroke miterlimit.
|
||||
*
|
||||
|
@ -1033,6 +1032,22 @@ public:
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -1072,7 +1087,6 @@ public:
|
|||
*/
|
||||
Result fill(FillRule r) noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the rendering order of the stroke and the fill.
|
||||
*
|
||||
|
@ -1084,7 +1098,6 @@ public:
|
|||
*/
|
||||
Result order(bool strokeFirst) noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the commands data of the path.
|
||||
*
|
||||
|
@ -1190,6 +1203,18 @@ public:
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -916,7 +916,7 @@ static void _updateTrimpath(TVG_UNUSED LottieGroup* parent, LottieObject** child
|
|||
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)
|
||||
{
|
||||
auto s = this->start(frameNo, exps) * 0.01f;
|
||||
auto e = this->end(frameNo, exps) * 0.01f;
|
||||
start = this->start(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 diff = fabs(s - e);
|
||||
auto diff = fabs(start - end);
|
||||
if (mathZero(diff)) {
|
||||
start = 0.0f;
|
||||
end = 0.0f;
|
||||
|
@ -137,28 +137,8 @@ void LottieTrimpath::segment(float frameNo, float& start, float& end, LottieExpr
|
|||
return;
|
||||
}
|
||||
|
||||
s += o;
|
||||
e += 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;
|
||||
}
|
||||
start += o;
|
||||
end += o;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -331,8 +331,9 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|||
break;
|
||||
}
|
||||
case PathCommand::MoveTo: {
|
||||
if (rshape->stroke->trim.individual) _dashMoveTo(dash, pts);
|
||||
else _dashMoveTo(dash, offIdx, offset, pts);
|
||||
if (rshape->stroke->trim.simultaneous) _dashMoveTo(dash, offIdx, offset, pts);
|
||||
else _dashMoveTo(dash, pts);
|
||||
|
||||
++pts;
|
||||
break;
|
||||
}
|
||||
|
@ -371,7 +372,7 @@ static float _outlineLength(const RenderShape* rshape)
|
|||
const Point* close = nullptr;
|
||||
auto length = 0.0f;
|
||||
auto slength = -1.0f;
|
||||
auto simultaneous = !rshape->stroke->trim.individual;
|
||||
auto simultaneous = rshape->stroke->trim.simultaneous;
|
||||
|
||||
//Compute the whole length
|
||||
while (cmdCnt-- > 0) {
|
||||
|
|
|
@ -140,7 +140,7 @@ struct RenderStroke
|
|||
struct {
|
||||
float begin = 0.0f;
|
||||
float end = 1.0f;
|
||||
bool individual = false;
|
||||
bool simultaneous = true;
|
||||
} trim;
|
||||
|
||||
~RenderStroke()
|
||||
|
|
|
@ -362,6 +362,7 @@ Result Shape::strokeJoin(StrokeJoin join) noexcept
|
|||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result Shape::strokeMiterlimit(float miterlimit) noexcept
|
||||
{
|
||||
// https://www.w3.org/TR/SVG2/painting.html#LineJoin
|
||||
|
@ -385,12 +386,26 @@ StrokeJoin Shape::strokeJoin() const noexcept
|
|||
return pImpl->rs.strokeJoin();
|
||||
}
|
||||
|
||||
|
||||
float Shape::strokeMiterlimit() const noexcept
|
||||
{
|
||||
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
|
||||
{
|
||||
pImpl->rs.rule = r;
|
||||
|
|
|
@ -216,21 +216,50 @@ struct Shape::Impl
|
|||
return true;
|
||||
}
|
||||
|
||||
bool strokeTrim(float begin, float end, bool individual)
|
||||
void strokeTrim(float begin, float end, bool simultaneous)
|
||||
{
|
||||
if (!rs.stroke) {
|
||||
if (begin == 0.0f && end == 1.0f) return true;
|
||||
if (begin == 0.0f && end == 1.0f) return;
|
||||
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.end = end;
|
||||
rs.stroke->trim.individual = individual;
|
||||
rs.stroke->trim.simultaneous = simultaneous;
|
||||
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)
|
||||
|
|
Loading…
Add table
Reference in a new issue