diff --git a/inc/thorvg.h b/inc/thorvg.h index 50b03fd0..d22acbb2 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -237,7 +237,7 @@ public: //Shape 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 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; //Stroke diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index b94c413f..5c0428ba 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -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_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_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_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); diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 65eedd2a..9897584e 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -183,9 +183,9 @@ TVG_EXPORT Tvg_Result tvg_shape_append_rect(Tvg_Paint* paint, float x, float y, return (Tvg_Result) reinterpret_cast(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(paint)->appendArc(x, y, w ,h, startAngle, sweep); + return (Tvg_Result) reinterpret_cast(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) diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 57c097a0..94f445e2 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -150,73 +150,69 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept 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 radius = w / 2; - - Point center = {x + radius, y + radius}; auto impl = pImpl.get(); + //just circle + if (sweep >= 360) return appendCircle(cx, cy, radius, radius); + startAngle = (startAngle * 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); fract = (fract < std::numeric_limits::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) { - //bezier parameters - Point start = {0, 0}; - Point end = {0, 0}; - Point bControl1 = {0, 0}; - Point bControl2 = {0, 0}; + + auto endAngle = startAngle + ((i != nCurves - 1) ? M_PI_HALF : fract); + Point end = {radius * cos(endAngle), radius * sin(endAngle)}; //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: //(http://itc.ktu.lt/index.php/ITC/article/view/11812/6479) - ax = start.x; - ay = start.y; - bx = end.x; - by = end.y; + auto ax = start.x; + auto ay = start.y; + auto bx = end.x; + auto by = end.y; + auto q1 = ax * ax + ay * ay; + auto q2 = ax * bx + ay * by + q1; + auto k2 = static_cast (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx)); - q1 = ax * ax + ay * ay; - q2 = ax * bx + ay * by + q1; + start = end; //Next start point is the current end point - k2 = static_cast (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx)); + end.x += cx; + end.y += cy; - bControl1.x = ax - k2 * ay; - bControl1.y = ay + k2 * ax; - bControl2.x = bx + k2 * by; - bControl2.y = by - k2 * bx; + Point ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy}; + Point ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy}; - //move points to proper arc center - 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); + impl->path->cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y); startAngle = endAngle; } + if (pie) { + impl->path->moveTo(cx, cy); + impl->path->close(); + } + IMPL->flag |= RenderUpdateFlag::Path; + return Result::Success; } diff --git a/test/testArc.cpp b/test/testArc.cpp index 3878aff8..c00f4643 100644 --- a/test/testArc.cpp +++ b/test/testArc.cpp @@ -8,35 +8,29 @@ void tvgDrawCmds(tvg::Canvas* canvas) { if (!canvas) return; - //draw reference rectangles - auto shape2 = tvg::Shape::gen(); - shape2->appendRect(0, 0, 200, 200, 0, 0); - shape2->stroke(255, 0, 0, 255); - shape2->stroke(2); + //Arc Line + auto shape1 = tvg::Shape::gen(); + shape1->appendArc(150, 150, 100, 10, 270, false); + shape1->stroke(255, 255, 255, 255); + 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(); - shape3->moveTo(0, 100); - shape3->lineTo(200, 100); - shape3->stroke(255, 0, 0, 255); - shape3->stroke(2); + shape3->appendArc(150, 500, 100, 0, 75, true); + shape3->fill(255, 255, 255, 255); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; auto shape4 = tvg::Shape::gen(); - shape4->moveTo(100, 0); - shape4->lineTo(100, 200); - 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; + shape4->appendArc(500, 500, 150, 0, 215, true); + shape4->fill(255, 255, 255, 255); if (canvas->push(move(shape4)) != tvg::Result::Success) return; - if (canvas->push(move(shape1)) != tvg::Result::Success) return; } /************************************************************************/