From ab5c1bc44180a256c6b9f02f26fcff40e7f0bf16 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 22 Jun 2020 17:06:53 +0900 Subject: [PATCH] common bezier: code refactoring. Organize bezier functions for internal share. this bezier can be used in svg loader. Change-Id: I78acd3273c0528688ca46ff7c29d78607bd729bd --- src/lib/meson.build | 2 + src/lib/sw_engine/tvgSwShape.cpp | 109 +---------------------- src/lib/tvgBezier.cpp | 144 +++++++++++++++++++++++++++++++ src/lib/tvgBezier.h | 39 +++++++++ src/lib/tvgCommon.h | 1 + src/lib/tvgRender.cpp | 2 - 6 files changed, 188 insertions(+), 109 deletions(-) create mode 100644 src/lib/tvgBezier.cpp create mode 100644 src/lib/tvgBezier.h diff --git a/src/lib/meson.build b/src/lib/meson.build index 96752064..53c9a19a 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -4,12 +4,14 @@ subdir('gl_engine') source_file = [ 'tvgCanvasImpl.h', 'tvgCommon.h', + 'tvgBezier.h', 'tvgLoader.h', 'tvgLoaderMgr.h', 'tvgRender.h', 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', + 'tvgBezier.cpp', 'tvgCanvas.cpp', 'tvgFill.cpp', 'tvgGlCanvas.cpp', diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4d3c44ec..ee599df5 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -30,15 +30,6 @@ struct Line }; -struct Bezier -{ - Point start; - Point ctrl1; - Point ctrl2; - Point end; -}; - - static float _lineLength(const Point& pt1, const Point& pt2) { /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. @@ -64,102 +55,6 @@ static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right) } -static void _bezSplit(const Bezier&cur, Bezier& left, Bezier& right) -{ - auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; - left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; - right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; - left.start.x = cur.start.x; - right.end.x = cur.end.x; - left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; - right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; - left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; - - c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; - left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; - right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; - left.start.y = cur.start.y; - right.end.y = cur.end.y; - left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; - right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; - left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; -} - - -static float _bezLength(const Bezier& cur) -{ - Bezier left, right; - auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); - auto chord = _lineLength(cur.start, cur.end); - - if (fabs(len - chord) > FLT_EPSILON) { - _bezSplit(cur, left, right); - return _bezLength(left) + _bezLength(right); - } - return len; -} - - -static void _bezSplitLeft(Bezier& cur, float at, Bezier& left) -{ - left.start = cur.start; - - left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); - left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); - - left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot - left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot - - cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); - cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); - - cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); - cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); - - left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); - left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); - - left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); - left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); -} - - -static float _bezAt(const Bezier& bz, float at) -{ - auto len = _bezLength(bz); - auto biggest = 1.0f; - - if (at >= len) return 1.0f; - - at *= 0.5f; - - while (true) { - auto right = bz; - Bezier left; - _bezSplitLeft(right, at, left); - auto len2 = _bezLength(left); - - if (fabs(len2 - len) < FLT_EPSILON) break; - - if (len2 < len) { - at += (biggest - at) * 0.5f; - } else { - biggest = at; - at -= (at * 0.5f); - } - } - return at; -} - - -static void _bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) -{ - right = cur; - auto t = _bezAt(right, at); - _bezSplitLeft(right, t, left); -} - - static void _growOutlineContour(SwOutline& outline, uint32_t n) { if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; @@ -407,7 +302,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); Bezier cur = { dash.ptCur, *ctrl1, *ctrl2, *to}; - auto len = _bezLength(cur); + auto len = bezLength(cur); if (len < dash.curLen) { dash.curLen -= len; @@ -419,7 +314,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct while (len > dash.curLen) { Bezier left, right; len -= dash.curLen; - _bezSplitAt(cur, dash.curLen, left, right); + bezSplitAt(cur, dash.curLen, left, right); dash.curIdx = (dash.curIdx + 1) % dash.cnt; if (!dash.curOpGap) { _outlineMoveTo(*dash.outline, &left.start); diff --git a/src/lib/tvgBezier.cpp b/src/lib/tvgBezier.cpp new file mode 100644 index 00000000..1aa2dab5 --- /dev/null +++ b/src/lib/tvgBezier.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_BEZIER_CPP_ +#define _TVG_BEZIER_CPP_ + +#include "tvgCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static float _lineLength(const Point& pt1, const Point& pt2) +{ + /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. + With alpha = 1, beta = 3/8, giving results with the largest error less + than 7% compared to the exact value. */ + Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; + if (diff.x < 0) diff.x = -diff.x; + if (diff.y < 0) diff.y = -diff.y; + return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f); +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +namespace tvg +{ + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right) +{ + auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; + left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; + right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; + left.start.x = cur.start.x; + right.end.x = cur.end.x; + left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; + right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; + left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; + + c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; + left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; + right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; + left.start.y = cur.start.y; + right.end.y = cur.end.y; + left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; + right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; + left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; +} + + +float bezLength(const Bezier& cur) +{ + Bezier left, right; + auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); + auto chord = _lineLength(cur.start, cur.end); + + if (fabs(len - chord) > FLT_EPSILON) { + bezSplit(cur, left, right); + return bezLength(left) + bezLength(right); + } + return len; +} + + +void bezSplitLeft(Bezier& cur, float at, Bezier& left) +{ + left.start = cur.start; + + left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); + left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); + + left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot + left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot + + cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); + cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); + + cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); + cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); + + left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); + left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); + + left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); + left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); +} + + +float bezAt(const Bezier& bz, float at) +{ + auto len = bezLength(bz); + auto biggest = 1.0f; + + if (at >= len) return 1.0f; + + at *= 0.5f; + + while (true) { + auto right = bz; + Bezier left; + bezSplitLeft(right, at, left); + auto len2 = bezLength(left); + + if (fabs(len2 - len) < FLT_EPSILON) break; + + if (len2 < len) { + at += (biggest - at) * 0.5f; + } else { + biggest = at; + at -= (at * 0.5f); + } + } + return at; +} + + +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) +{ + right = cur; + auto t = bezAt(right, at); + bezSplitLeft(right, t, left); +} + + +} + +#endif //_TVG_BEZIER_CPP_ diff --git a/src/lib/tvgBezier.h b/src/lib/tvgBezier.h new file mode 100644 index 00000000..aa7d77f0 --- /dev/null +++ b/src/lib/tvgBezier.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_BEZIER_H_ +#define _TVG_BEZIER_H_ + +namespace tvg +{ + +struct Bezier +{ + Point start; + Point ctrl1; + Point ctrl2; + Point end; +}; + +void bezSplit(const Bezier&cur, Bezier& left, Bezier& right); +float bezLength(const Bezier& cur); +void bezSplitLeft(Bezier& cur, float at, Bezier& left); +float bezAt(const Bezier& bz, float at); +void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right); + +} + +#endif //_TVG_BEZIER_H_ \ No newline at end of file diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 2b0e9c18..302f4e91 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -37,6 +37,7 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#include "tvgBezier.h" #include "tvgLoader.h" #include "tvgLoaderMgr.h" #include "tvgRender.h" diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4b4afc3b..bffbe400 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -18,8 +18,6 @@ #define _TVG_RENDER_CPP_ #include "tvgCommon.h" -#include "tvgRender.h" - /************************************************************************/ /* Internal Class Implementation */