Skip to content

Commit

Permalink
add support for negative corner radius
Browse files Browse the repository at this point in the history
add support for negative rounded corners

https://github.com/user-attachments/assets/c72fa81d-7262-46d8-8734-92047e3777da

Diffs=
71d26ec7be add support for negative corner radius (#9012)

Co-authored-by: hernan <[email protected]>
  • Loading branch information
bodymovin and bodymovin committed Feb 13, 2025
1 parent 4a67e90 commit 84d5d06
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b8c47bea694e7d34b73470751661f721feeab14f
71d26ec7bea204c79c2e590ae2db5c61d3aa0794
8 changes: 4 additions & 4 deletions src/layout/layout_component_style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ void LayoutComponentStyle::positionBottomUnitsValueChanged()
{
markLayoutNodeDirty();
}
void LayoutComponentStyle::cornerRadiusTLChanged() { markLayoutNodeDirty(); }
void LayoutComponentStyle::cornerRadiusTRChanged() { markLayoutNodeDirty(); }
void LayoutComponentStyle::cornerRadiusBLChanged() { markLayoutNodeDirty(); }
void LayoutComponentStyle::cornerRadiusBRChanged() { markLayoutNodeDirty(); }
void LayoutComponentStyle::cornerRadiusTLChanged() { markLayoutStyleDirty(); }
void LayoutComponentStyle::cornerRadiusTRChanged() { markLayoutStyleDirty(); }
void LayoutComponentStyle::cornerRadiusBLChanged() { markLayoutStyleDirty(); }
void LayoutComponentStyle::cornerRadiusBRChanged() { markLayoutStyleDirty(); }
57 changes: 51 additions & 6 deletions src/shapes/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,40 @@ static float computeIdealControlPointDistance(const Vec2D& toPrev,
(angle < math::PI / 2 ? 1 + cos(angle) : 2.0f - sin(angle)));
}

static void rotatePoints(const Vec2D& nextPoint,
const Vec2D& prevPoint,
const Vec2D& point,
Vec2D& outPoint,
Vec2D& inPoint)
{
// Calculate angle between original pos and new positions
auto v1 = prevPoint - nextPoint;
auto v2 = point - nextPoint;
auto angle = atan2(Vec2D::cross(v1, v2), Vec2D::dot(v1, v2));
{
// Rotate outPoint around prevPoint twice the angle
auto s = sin(angle * 2);
auto c = cos(angle * 2);
outPoint.x -= prevPoint.x;
outPoint.y -= prevPoint.y;
auto xNew = outPoint.x * c - outPoint.y * s;
auto yNew = outPoint.x * s + outPoint.y * c;
outPoint.x = xNew + prevPoint.x;
outPoint.y = yNew + prevPoint.y;
}
{
// Rotate inPoint around nextPoint twice the angle
auto s = sin(-angle * 2);
auto c = cos(-angle * 2);
inPoint.x -= nextPoint.x;
inPoint.y -= nextPoint.y;
auto xNew = inPoint.x * c - inPoint.y * s;
auto yNew = inPoint.x * s + inPoint.y * c;
inPoint.x = xNew + nextPoint.x;
inPoint.y = yNew + nextPoint.y;
}
}

RenderPathDeformer* Path::deformer() const
{
if (m_Shape != nullptr)
Expand Down Expand Up @@ -123,7 +157,7 @@ void Path::buildPath(RawPath& rawPath) const
startIsCubic = prevIsCubic = false;
auto point = *firstPoint->as<StraightVertex>();
auto radius = point.radius();
if (radius > 0.0f)
if (radius != 0.0f)
{
auto prev = vertices[length - 1];

Expand All @@ -144,9 +178,9 @@ void Path::buildPath(RawPath& rawPath) const
pos;
auto toNextLength = toNext.normalizeLength();

float renderRadius =
std::min(toPrevLength / 2.0f,
std::min(toNextLength / 2.0f, radius));
float renderRadius = std::min(
toPrevLength / 2.0f,
std::min(toNextLength / 2.0f, radius > 0 ? radius : -radius));
float idealDistance =
computeIdealControlPointDistance(toPrev, toNext, renderRadius);

Expand All @@ -158,6 +192,11 @@ void Path::buildPath(RawPath& rawPath) const
Vec2D inPoint =
Vec2D::scaleAndAdd(pos, toNext, renderRadius - idealDistance);
out = Vec2D::scaleAndAdd(pos, toNext, renderRadius);

if (radius < 0)
{
rotatePoints(out, startIn, pos, outPoint, inPoint);
}
rawPath.cubic(outPoint, inPoint, out);
prevIsCubic = false;
}
Expand Down Expand Up @@ -188,7 +227,7 @@ void Path::buildPath(RawPath& rawPath) const
auto point = *vertex->as<StraightVertex>();
Vec2D pos = point.renderTranslation();
auto radius = point.radius();
if (radius > 0.0f)
if (radius != 0.0f)
{
auto prev = vertices[i - 1];
Vec2D toPrev = (prev->is<CubicVertex>()
Expand All @@ -207,7 +246,8 @@ void Path::buildPath(RawPath& rawPath) const

float renderRadius =
std::min(toPrevLength / 2.0f,
std::min(toNextLength / 2.0f, radius));
std::min(toNextLength / 2.0f,
radius > 0 ? radius : -radius));
float idealDistance =
computeIdealControlPointDistance(toPrev,
toNext,
Expand All @@ -233,6 +273,11 @@ void Path::buildPath(RawPath& rawPath) const
toNext,
renderRadius - idealDistance);
out = Vec2D::scaleAndAdd(pos, toNext, renderRadius);

if (radius < 0)
{
rotatePoints(out, translation, pos, outPoint, inPoint);
}
rawPath.cubic(outPoint, inPoint, out);
prevIsCubic = false;
}
Expand Down

0 comments on commit 84d5d06

Please sign in to comment.