mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-15 20:44:52 +00:00
renderer: handle edge cases for trimming with dashing
- In cases where the begin and end values of trimming did not result in trimming (end - begin > 1), trimming was ignored. However, when the stroke is also dashed, this case affects the shift of the point where the first dash becomes visible. - Trimming that passes through the curve's start point (like -0.1:0.1) requires passing through the curve twice. The points obtained from both passes must be joined - visible when dashing Cases for simultaneous = true have been handled. @Issue: https://github.com/thorvg/thorvg/issues/3192
This commit is contained in:
parent
3c25623ee9
commit
5c950b783c
3 changed files with 20 additions and 18 deletions
|
@ -236,15 +236,16 @@ void LottieTrimpath::segment(float frameNo, float& start, float& end, Tween& twe
|
||||||
end = 0.0f;
|
end = 0.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (tvg::equal(diff, 1.0f) || tvg::equal(diff, 2.0f)) {
|
|
||||||
|
//Even if the start and end values do not cause trimming, an offset > 0 can still affect dashing starting point
|
||||||
|
auto o = fmodf(this->offset(frameNo, tween, exps), 360.0f) / 360.0f; //0 ~ 1
|
||||||
|
if (tvg::zero(o) && diff >= 1.0f) {
|
||||||
start = 0.0f;
|
start = 0.0f;
|
||||||
end = 1.0f;
|
end = 1.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start > end) std::swap(start, end);
|
if (start > end) std::swap(start, end);
|
||||||
|
|
||||||
auto o = fmodf(this->offset(frameNo, tween, exps), 360.0f) / 360.0f; //0 ~ 1
|
|
||||||
start += o;
|
start += o;
|
||||||
end += o;
|
end += o;
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,10 +211,8 @@ struct Shape::Impl : Paint::Impl
|
||||||
|
|
||||||
void strokeTrim(float begin, float end, bool simultaneous)
|
void strokeTrim(float begin, float end, bool simultaneous)
|
||||||
{
|
{
|
||||||
if (fabsf(end - begin) >= 1.0f) {
|
//Even if there is no trimming effect, begin can still affect dashing starting point
|
||||||
begin = 0.0f;
|
if (fabsf(end - begin) >= 1.0f) end = begin + 1.0f;
|
||||||
end = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rs.stroke) {
|
if (!rs.stroke) {
|
||||||
if (begin == 0.0f && end == 1.0f) return;
|
if (begin == 0.0f && end == 1.0f) return;
|
||||||
|
|
|
@ -162,7 +162,7 @@ static void _add(const PathCommand* cmds, const Point* pts, const Point& moveTo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _trimPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, TVG_UNUSED uint32_t inPtsCnt, float trimStart, float trimEnd, RenderPath& out)
|
static void _trimPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, TVG_UNUSED uint32_t inPtsCnt, float trimStart, float trimEnd, RenderPath& out, bool connect = false)
|
||||||
{
|
{
|
||||||
auto cmds = const_cast<PathCommand*>(inCmds);
|
auto cmds = const_cast<PathCommand*>(inCmds);
|
||||||
auto pts = const_cast<Point*>(inPts);
|
auto pts = const_cast<Point*>(inPts);
|
||||||
|
@ -203,7 +203,7 @@ static void _trimPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point
|
||||||
++cmds;
|
++cmds;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool start = true;
|
auto start = !connect;
|
||||||
for (uint32_t i = 0; i < inCmdsCnt; ++i) {
|
for (uint32_t i = 0; i < inCmdsCnt; ++i) {
|
||||||
auto dLen = _length();
|
auto dLen = _length();
|
||||||
|
|
||||||
|
@ -234,15 +234,18 @@ static void _trimPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _trim(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, float begin, float end, RenderPath& out)
|
static void _trim(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, float begin, float end, bool connect, RenderPath& out)
|
||||||
{
|
{
|
||||||
auto totalLength = _pathLength(inCmds, inCmdsCnt, inPts, inPtsCnt);
|
auto totalLength = _pathLength(inCmds, inCmdsCnt, inPts, inPtsCnt);
|
||||||
auto trimStart = begin * totalLength;
|
auto trimStart = begin * totalLength;
|
||||||
auto trimEnd = end * totalLength;
|
auto trimEnd = end * totalLength;
|
||||||
|
|
||||||
if (trimStart > trimEnd) {
|
if (fabsf(begin - end) < EPSILON) {
|
||||||
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, trimStart, totalLength, out);
|
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, trimStart, totalLength, out);
|
||||||
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, 0.0f, trimEnd, out);
|
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, 0.0f, trimStart, out, connect);
|
||||||
|
} else if (begin > end) {
|
||||||
|
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, trimStart, totalLength, out);
|
||||||
|
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, 0.0f, trimEnd, out, connect);
|
||||||
} else {
|
} else {
|
||||||
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, trimStart, trimEnd, out);
|
_trimPath(inCmds, inCmdsCnt, inPts, inPtsCnt, trimStart, trimEnd, out);
|
||||||
}
|
}
|
||||||
|
@ -280,11 +283,11 @@ bool TrimPath::valid() const
|
||||||
|
|
||||||
bool TrimPath::trim(const RenderPath& in, RenderPath& out) const
|
bool TrimPath::trim(const RenderPath& in, RenderPath& out) const
|
||||||
{
|
{
|
||||||
|
if (in.pts.count < 2 || tvg::zero(begin - end)) return false;
|
||||||
|
|
||||||
float begin = this->begin, end = this->end;
|
float begin = this->begin, end = this->end;
|
||||||
_get(begin, end);
|
_get(begin, end);
|
||||||
|
|
||||||
if (in.pts.count < 2 || tvg::zero(begin - end)) return false;
|
|
||||||
|
|
||||||
out.cmds.reserve(in.cmds.count * 2);
|
out.cmds.reserve(in.cmds.count * 2);
|
||||||
out.pts.reserve(in.pts.count * 2);
|
out.pts.reserve(in.pts.count * 2);
|
||||||
|
|
||||||
|
@ -298,7 +301,7 @@ bool TrimPath::trim(const RenderPath& in, RenderPath& out) const
|
||||||
while (i < in.cmds.count) {
|
while (i < in.cmds.count) {
|
||||||
switch (in.cmds[i]) {
|
switch (in.cmds[i]) {
|
||||||
case PathCommand::MoveTo: {
|
case PathCommand::MoveTo: {
|
||||||
if (startCmds != cmds) _trim(startCmds, cmds - startCmds, startPts, pts - startPts, begin, end, out);
|
if (startCmds != cmds) _trim(startCmds, cmds - startCmds, startPts, pts - startPts, begin, end, *(cmds - 1) == PathCommand::Close, out);
|
||||||
startPts = pts;
|
startPts = pts;
|
||||||
startCmds = cmds;
|
startCmds = cmds;
|
||||||
++pts;
|
++pts;
|
||||||
|
@ -317,7 +320,7 @@ bool TrimPath::trim(const RenderPath& in, RenderPath& out) const
|
||||||
}
|
}
|
||||||
case PathCommand::Close: {
|
case PathCommand::Close: {
|
||||||
++cmds;
|
++cmds;
|
||||||
if (startCmds != cmds) _trim(startCmds, cmds - startCmds, startPts, pts - startPts, begin, end, out);
|
if (startCmds != cmds) _trim(startCmds, cmds - startCmds, startPts, pts - startPts, begin, end, *(cmds - 1) == PathCommand::Close, out);
|
||||||
startPts = pts;
|
startPts = pts;
|
||||||
startCmds = cmds;
|
startCmds = cmds;
|
||||||
break;
|
break;
|
||||||
|
@ -325,9 +328,9 @@ bool TrimPath::trim(const RenderPath& in, RenderPath& out) const
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (startCmds != cmds) _trim(startCmds, cmds - startCmds, startPts, pts - startPts, begin, end, out);
|
if (startCmds != cmds) _trim(startCmds, cmds - startCmds, startPts, pts - startPts, begin, end, *(cmds - 1) == PathCommand::Close, out);
|
||||||
} else {
|
} else {
|
||||||
_trim(in.cmds.data, in.cmds.count, in.pts.data, in.pts.count, begin, end, out);
|
_trim(in.cmds.data, in.cmds.count, in.pts.data, in.pts.count, begin, end, false, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out.pts.count >= 2;
|
return out.pts.count >= 2;
|
||||||
|
|
Loading…
Add table
Reference in a new issue