mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
common shape: added arc implementation
Change-Id: Ib483e24d8e358b2860ca8d46e8b88d58d12bdb62
This commit is contained in:
parent
f15aefa5dc
commit
214072babe
7 changed files with 223 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -21,3 +21,4 @@ testGradientTransform
|
|||
testSvg
|
||||
testAsync
|
||||
testCapi
|
||||
testArc
|
||||
|
|
|
@ -237,6 +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 appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept;
|
||||
|
||||
//Stroke
|
||||
|
|
|
@ -133,6 +133,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_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);
|
||||
|
|
|
@ -178,6 +178,10 @@ 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);
|
||||
}
|
||||
|
||||
TVG_EXPORT Tvg_Result tvg_shape_append_arc(Tvg_Paint* paint, float x, float y, float w, float h, float startAngle, float sweep)
|
||||
{
|
||||
return (Tvg_Result) reinterpret_cast<Shape*>(paint)->appendArc(x, y, w ,h, startAngle, sweep);
|
||||
}
|
||||
|
||||
TVG_EXPORT Tvg_Result tvg_shape_append_circle(Tvg_Paint* paint, float cx, float cy, float rx, float ry)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef _TVG_SHAPE_CPP_
|
||||
#define _TVG_SHAPE_CPP_
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "tvgShapeImpl.h"
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -148,6 +150,76 @@ 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
|
||||
{
|
||||
const float M_PI_HALF = M_PI / 2.0;
|
||||
const float radius = w / 2;
|
||||
|
||||
Point center = {x + radius, y + radius};
|
||||
|
||||
auto impl = pImpl.get();
|
||||
|
||||
startAngle = (startAngle * M_PI) / 180;
|
||||
sweep = sweep * M_PI / 180;
|
||||
|
||||
auto nCurves = ceil(sweep / M_PI_HALF);
|
||||
auto fract = fmod(sweep, M_PI_HALF);
|
||||
fract = (fract < std::numeric_limits<float>::epsilon()) ? M_PI_HALF : fract;
|
||||
|
||||
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};
|
||||
|
||||
//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;
|
||||
|
||||
q1 = ax * ax + ay * ay;
|
||||
q2 = ax * bx + ay * by + q1;
|
||||
|
||||
k2 = static_cast<float> (4.0/3.0) * ((sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx));
|
||||
|
||||
bControl1.x = ax - k2 * ay;
|
||||
bControl1.y = ay + k2 * ax;
|
||||
bControl2.x = bx + k2 * by;
|
||||
bControl2.y = by - k2 * bx;
|
||||
|
||||
//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);
|
||||
|
||||
startAngle = endAngle;
|
||||
}
|
||||
|
||||
IMPL->flag |= RenderUpdateFlag::Path;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) noexcept
|
||||
{
|
||||
|
|
|
@ -18,4 +18,5 @@ all:
|
|||
gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
|
||||
gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
|
||||
gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
|
||||
gcc -o testArc testArc.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg`
|
||||
gcc -o testCapi testCapi.c -g `pkg-config --cflags --libs elementary thorvg`
|
||||
|
|
142
test/testArc.cpp
Normal file
142
test/testArc.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
#include "testCommon.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Drawing Commands */
|
||||
/************************************************************************/
|
||||
|
||||
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);
|
||||
|
||||
auto shape3 = tvg::Shape::gen();
|
||||
shape3->moveTo(0, 100);
|
||||
shape3->lineTo(200, 100);
|
||||
shape3->stroke(255, 0, 0, 255);
|
||||
shape3->stroke(2);
|
||||
|
||||
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;
|
||||
if (canvas->push(move(shape4)) != tvg::Result::Success) return;
|
||||
if (canvas->push(move(shape1)) != tvg::Result::Success) return;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* Sw Engine Test Code */
|
||||
/************************************************************************/
|
||||
|
||||
static unique_ptr<tvg::SwCanvas> swCanvas;
|
||||
|
||||
void tvgSwTest(uint32_t* buffer)
|
||||
{
|
||||
//Create a Canvas
|
||||
swCanvas = tvg::SwCanvas::gen();
|
||||
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT);
|
||||
|
||||
/* Push the shape into the Canvas drawing list
|
||||
When this shape is into the canvas list, the shape could update & prepare
|
||||
internal data asynchronously for coming rendering.
|
||||
Canvas keeps this shape node unless user call canvas->clear() */
|
||||
tvgDrawCmds(swCanvas.get());
|
||||
}
|
||||
|
||||
void drawSwView(void* data, Eo* obj)
|
||||
{
|
||||
if (swCanvas->draw() == tvg::Result::Success) {
|
||||
swCanvas->sync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* GL Engine Test Code */
|
||||
/************************************************************************/
|
||||
|
||||
static unique_ptr<tvg::GlCanvas> glCanvas;
|
||||
|
||||
void initGLview(Evas_Object *obj)
|
||||
{
|
||||
static constexpr auto BPP = 4;
|
||||
|
||||
//Create a Canvas
|
||||
glCanvas = tvg::GlCanvas::gen();
|
||||
glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT);
|
||||
|
||||
/* Push the shape into the Canvas drawing list
|
||||
When this shape is into the canvas list, the shape could update & prepare
|
||||
internal data asynchronously for coming rendering.
|
||||
Canvas keeps this shape node unless user call canvas->clear() */
|
||||
tvgDrawCmds(glCanvas.get());
|
||||
}
|
||||
|
||||
void drawGLview(Evas_Object *obj)
|
||||
{
|
||||
auto gl = elm_glview_gl_api_get(obj);
|
||||
gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl->glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (glCanvas->draw() == tvg::Result::Success) {
|
||||
glCanvas->sync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Main Code */
|
||||
/************************************************************************/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
|
||||
|
||||
if (argc > 1) {
|
||||
if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl;
|
||||
}
|
||||
|
||||
//Initialize ThorVG Engine
|
||||
if (tvgEngine == tvg::CanvasEngine::Sw) {
|
||||
cout << "tvg engine: software" << endl;
|
||||
} else {
|
||||
cout << "tvg engine: opengl" << endl;
|
||||
}
|
||||
|
||||
//Initialize ThorVG Engine
|
||||
if (tvg::Initializer::init(tvgEngine) == tvg::Result::Success) {
|
||||
|
||||
elm_init(argc, argv);
|
||||
|
||||
if (tvgEngine == tvg::CanvasEngine::Sw) {
|
||||
createSwView();
|
||||
} else {
|
||||
createGlView();
|
||||
}
|
||||
|
||||
elm_run();
|
||||
elm_shutdown();
|
||||
|
||||
//Terminate ThorVG Engine
|
||||
tvg::Initializer::term(tvgEngine);
|
||||
|
||||
} else {
|
||||
cout << "engine is not supported" << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue