mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-15 20:44:52 +00:00
common shape: support pie filling from arc.
last argument pie=true makes arc to pie shape. Change-Id: I6f22d00fed77bf728a4ff6e5f1ca42f476ac1664
This commit is contained in:
parent
0be10ce140
commit
e98988da02
5 changed files with 59 additions and 69 deletions
|
@ -237,7 +237,7 @@ public:
|
||||||
//Shape
|
//Shape
|
||||||
Result appendRect(float x, float y, float w, float h, float rx, float ry) noexcept;
|
Result appendRect(float x, float y, float w, float h, float rx, float ry) noexcept;
|
||||||
Result appendCircle(float cx, float cy, float rx, float ry) noexcept;
|
Result appendCircle(float cx, float cy, float rx, float ry) noexcept;
|
||||||
Result appendArc(float x, float y, float w, float h, float startAngle, float sweep) noexcept;
|
Result appendArc(float cx, float cy, float radius, float startAngle, float sweep, bool pie) noexcept;
|
||||||
Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept;
|
Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept;
|
||||||
|
|
||||||
//Stroke
|
//Stroke
|
||||||
|
|
|
@ -139,7 +139,7 @@ TVG_EXPORT Tvg_Result tvg_shape_cubic_to(Tvg_Paint* paint, float cx1, float cy1,
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_close(Tvg_Paint* paint);
|
TVG_EXPORT Tvg_Result tvg_shape_close(Tvg_Paint* paint);
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, float w, float h, float rx, float ry);
|
TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, float w, float h, float rx, float ry);
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry);
|
TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry);
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float x, float y, float w, float h, float startAngle, float sweep);
|
TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float cx, float cy, float radius, float startAngle, float sweep, uint8_t pie);
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_append_path(Tvg_Paint* paint, const Tvg_Path_Command* cmds, uint32_t cmdCnt, const Tvg_Point* pts, uint32_t ptsCnt);
|
TVG_EXPORT Tvg_Result tvg_shape_append_path(Tvg_Paint* paint, const Tvg_Path_Command* cmds, uint32_t cmdCnt, const Tvg_Point* pts, uint32_t ptsCnt);
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_width(Tvg_Paint* paint, float width);
|
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_width(Tvg_Paint* paint, float width);
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||||
|
|
|
@ -183,9 +183,9 @@ TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y,
|
||||||
return (Tvg_Result) reinterpret_cast<Shape*>(paint)->appendRect(x, y, w, h, rx, ry);
|
return (Tvg_Result) reinterpret_cast<Shape*>(paint)->appendRect(x, y, w, h, rx, ry);
|
||||||
}
|
}
|
||||||
|
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float x, float y, float w, float h, float startAngle, float sweep)
|
TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float cx, float cy, float radius, float startAngle, float sweep, uint8_t pie)
|
||||||
{
|
{
|
||||||
return (Tvg_Result) reinterpret_cast<Shape*>(paint)->appendArc(x, y, w ,h, startAngle, sweep);
|
return (Tvg_Result) reinterpret_cast<Shape*>(paint)->appendArc(cx, cy, radius, startAngle, sweep, pie);
|
||||||
}
|
}
|
||||||
|
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry)
|
TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry)
|
||||||
|
|
|
@ -150,73 +150,69 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Shape::appendArc(float x, float y, float w, float h, float startAngle, float sweep) noexcept
|
Result Shape::appendArc(float cx, float cy, float radius, float startAngle, float sweep, bool pie) noexcept
|
||||||
{
|
{
|
||||||
const float M_PI_HALF = M_PI / 2.0;
|
const float M_PI_HALF = M_PI / 2.0;
|
||||||
const float radius = w / 2;
|
|
||||||
|
|
||||||
Point center = {x + radius, y + radius};
|
|
||||||
|
|
||||||
auto impl = pImpl.get();
|
auto impl = pImpl.get();
|
||||||
|
|
||||||
|
//just circle
|
||||||
|
if (sweep >= 360) return appendCircle(cx, cy, radius, radius);
|
||||||
|
|
||||||
startAngle = (startAngle * M_PI) / 180;
|
startAngle = (startAngle * M_PI) / 180;
|
||||||
sweep = sweep * M_PI / 180;
|
sweep = sweep * M_PI / 180;
|
||||||
|
|
||||||
auto nCurves = ceil(sweep / M_PI_HALF);
|
auto nCurves = ceil(sweep / M_PI_HALF);
|
||||||
auto fract = fmod(sweep, M_PI_HALF);
|
auto fract = fmod(sweep, M_PI_HALF);
|
||||||
fract = (fract < std::numeric_limits<float>::epsilon()) ? M_PI_HALF : fract;
|
fract = (fract < std::numeric_limits<float>::epsilon()) ? M_PI_HALF : fract;
|
||||||
|
|
||||||
|
//Start from here
|
||||||
|
Point start = {radius * cos(startAngle), radius * sin(startAngle)};
|
||||||
|
|
||||||
|
if (pie) {
|
||||||
|
impl->path->moveTo(cx, cy);
|
||||||
|
impl->path->lineTo(start.x + cx, start.y + cy);
|
||||||
|
}else {
|
||||||
|
impl->path->moveTo(start.x + cx, start.y + cy);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < nCurves; ++i) {
|
for (int i = 0; i < nCurves; ++i) {
|
||||||
//bezier parameters
|
|
||||||
Point start = {0, 0};
|
auto endAngle = startAngle + ((i != nCurves - 1) ? M_PI_HALF : fract);
|
||||||
Point end = {0, 0};
|
Point end = {radius * cos(endAngle), radius * sin(endAngle)};
|
||||||
Point bControl1 = {0, 0};
|
|
||||||
Point bControl2 = {0, 0};
|
|
||||||
|
|
||||||
//variables needed to calculate bezier control points
|
//variables needed to calculate bezier control points
|
||||||
auto ax = 0.0f, ay = 0.0f, bx = 0.0f, by = 0.0f, q1 = 0.0f, q2 = 0.0f, k2 = 0.0f;
|
|
||||||
auto endAngle = startAngle + ((i != nCurves - 1) ? M_PI_HALF : fract);
|
|
||||||
|
|
||||||
//get bezier start and end point
|
|
||||||
start.x = radius * cos(startAngle);
|
|
||||||
start.y = radius * sin(startAngle);
|
|
||||||
end.x = radius * cos(endAngle);
|
|
||||||
end.y = radius * sin(endAngle);
|
|
||||||
|
|
||||||
//get bezier control points using article:
|
//get bezier control points using article:
|
||||||
//(http://itc.ktu.lt/index.php/ITC/article/view/11812/6479)
|
//(http://itc.ktu.lt/index.php/ITC/article/view/11812/6479)
|
||||||
ax = start.x;
|
auto ax = start.x;
|
||||||
ay = start.y;
|
auto ay = start.y;
|
||||||
bx = end.x;
|
auto bx = end.x;
|
||||||
by = end.y;
|
auto by = end.y;
|
||||||
|
auto q1 = ax * ax + ay * ay;
|
||||||
|
auto q2 = ax * bx + ay * by + q1;
|
||||||
|
auto k2 = static_cast<float> (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx));
|
||||||
|
|
||||||
q1 = ax * ax + ay * ay;
|
start = end; //Next start point is the current end point
|
||||||
q2 = ax * bx + ay * by + q1;
|
|
||||||
|
|
||||||
k2 = static_cast<float> (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx));
|
end.x += cx;
|
||||||
|
end.y += cy;
|
||||||
|
|
||||||
bControl1.x = ax - k2 * ay;
|
Point ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy};
|
||||||
bControl1.y = ay + k2 * ax;
|
Point ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy};
|
||||||
bControl2.x = bx + k2 * by;
|
|
||||||
bControl2.y = by - k2 * bx;
|
|
||||||
|
|
||||||
//move points to proper arc center
|
impl->path->cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y);
|
||||||
start.x += center.x;
|
|
||||||
start.y += center.y;
|
|
||||||
end.x += center.x;
|
|
||||||
end.y += center.y;
|
|
||||||
bControl1.x += center.x;
|
|
||||||
bControl1.y += center.y;
|
|
||||||
bControl2.x += center.x;
|
|
||||||
bControl2.y += center.y;
|
|
||||||
|
|
||||||
impl->path->moveTo(start.x, start.y);
|
|
||||||
impl->path->cubicTo(bControl1.x, bControl1.y, bControl2.x, bControl2.y, end.x, end.y);
|
|
||||||
|
|
||||||
startAngle = endAngle;
|
startAngle = endAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pie) {
|
||||||
|
impl->path->moveTo(cx, cy);
|
||||||
|
impl->path->close();
|
||||||
|
}
|
||||||
|
|
||||||
IMPL->flag |= RenderUpdateFlag::Path;
|
IMPL->flag |= RenderUpdateFlag::Path;
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,35 +8,29 @@ void tvgDrawCmds(tvg::Canvas* canvas)
|
||||||
{
|
{
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
|
|
||||||
//draw reference rectangles
|
//Arc Line
|
||||||
auto shape2 = tvg::Shape::gen();
|
auto shape1 = tvg::Shape::gen();
|
||||||
shape2->appendRect(0, 0, 200, 200, 0, 0);
|
shape1->appendArc(150, 150, 100, 10, 270, false);
|
||||||
shape2->stroke(255, 0, 0, 255);
|
shape1->stroke(255, 255, 255, 255);
|
||||||
shape2->stroke(2);
|
shape1->stroke(2);
|
||||||
|
if (canvas->push(move(shape1)) != tvg::Result::Success) return;
|
||||||
|
|
||||||
|
auto shape2 = tvg::Shape::gen();
|
||||||
|
shape2->appendArc(500, 150, 125, 0, 300, true);
|
||||||
|
shape2->stroke(255, 255, 255, 255);
|
||||||
|
shape2->stroke(2);
|
||||||
|
if (canvas->push(move(shape2)) != tvg::Result::Success) return;
|
||||||
|
|
||||||
|
//Pie Fill
|
||||||
auto shape3 = tvg::Shape::gen();
|
auto shape3 = tvg::Shape::gen();
|
||||||
shape3->moveTo(0, 100);
|
shape3->appendArc(150, 500, 100, 0, 75, true);
|
||||||
shape3->lineTo(200, 100);
|
shape3->fill(255, 255, 255, 255);
|
||||||
shape3->stroke(255, 0, 0, 255);
|
if (canvas->push(move(shape3)) != tvg::Result::Success) return;
|
||||||
shape3->stroke(2);
|
|
||||||
|
|
||||||
auto shape4 = tvg::Shape::gen();
|
auto shape4 = tvg::Shape::gen();
|
||||||
shape4->moveTo(100, 0);
|
shape4->appendArc(500, 500, 150, 0, 215, true);
|
||||||
shape4->lineTo(100, 200);
|
shape4->fill(255, 255, 255, 255);
|
||||||
shape4->stroke(255, 0, 0, 255);
|
|
||||||
shape4->stroke(2);
|
|
||||||
|
|
||||||
//test arc
|
|
||||||
auto shape1 = tvg::Shape::gen();
|
|
||||||
shape1->appendArc(0, 0, 200, 200, 10, 270);
|
|
||||||
shape1->stroke(255, 255, 255, 255);
|
|
||||||
shape1->stroke(3);
|
|
||||||
|
|
||||||
//Appends Paths
|
|
||||||
if (canvas->push(move(shape2)) != tvg::Result::Success) return;
|
|
||||||
if (canvas->push(move(shape3)) != tvg::Result::Success) return;
|
|
||||||
if (canvas->push(move(shape4)) != tvg::Result::Success) return;
|
if (canvas->push(move(shape4)) != tvg::Result::Success) return;
|
||||||
if (canvas->push(move(shape1)) != tvg::Result::Success) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
Loading…
Add table
Reference in a new issue