1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "gfx_utils/diagram/vertexprimitive/geometry_bezier_arc.h"
17
18 namespace OHOS {
19 #if defined(GRAPHIC_ENABLE_BEZIER_ARC_FLAG) && GRAPHIC_ENABLE_BEZIER_ARC_FLAG
20 const uint16_t BEZIER_ARC_SETUP = 2;
21
22 const uint16_t BEZIER_ARC_VERTICES_SIZE_STEP = 6;
23
24 const uint16_t BEZIER_ARC_POINTS = 4;
25 /* Limit Value of Bezier Arc */
26 const float BEZIER_ARC_ANGLE_EPSILON = 0.01f;
27
28 const float BEZIER_ARC_DELTAX = 4.0f;
29
30 const float BEZIER_ARC_EQUAL_DIVISION = 3.0f;
31
32 const float BEZIER_ARC_RADIICHECK = 10.0f;
33
34 const float epsilon = 1e-6f;
35
ArcToBezier(float cx,float cy,float rx,float ry,float startAngle,float sweepAngle,float * curve)36 void ArcToBezier(float cx, float cy, float rx, float ry,
37 float startAngle, float sweepAngle,
38 float* curve)
39 {
40 float y0 = Sin((sweepAngle / FLOATNUM) * RADIAN_TO_ANGLE);
41 float x0 = Cos((sweepAngle / FLOATNUM) * RADIAN_TO_ANGLE);
42 float tx = (1.0f - x0) * BEZIER_ARC_DELTAX / BEZIER_ARC_EQUAL_DIVISION;
43 if (fabs(y0) < epsilon) {
44 y0 = y0 + VERTEX_DIST_EPSILON;
45 }
46 float ty = y0 - tx * x0 / y0;
47 float px[BEZIER_ARC_POINTS];
48 float py[BEZIER_ARC_POINTS];
49 px[0] = x0;
50 py[0] = -y0;
51 px[1] = x0 + tx;
52 py[1] = -ty;
53 px[2] = x0 + tx;
54 py[2] = ty;
55 px[3] = x0;
56 py[3] = y0;
57
58 float cosVal = Cos((startAngle + sweepAngle / FLOATNUM) * RADIAN_TO_ANGLE);
59 float sinVal = Sin((startAngle + sweepAngle / FLOATNUM) * RADIAN_TO_ANGLE);
60
61 for (uint16_t i = 0; i < BEZIER_ARC_POINTS; i++) {
62 curve[i * BEZIER_ARC_SETUP] = cx + rx * (px[i] * cosVal - py[i] * sinVal);
63 curve[i * BEZIER_ARC_SETUP + 1] = cy + ry * (px[i] * sinVal + py[i] * cosVal);
64 }
65 }
66
Init(float centerX,float centerY,float rx,float ry,float startAngle,float sweepAngle)67 void BezierArc::Init(float centerX, float centerY,
68 float rx, float ry,
69 float startAngle,
70 float sweepAngle)
71 {
72 startAngle = Fmod(startAngle, FLOATNUM * PI);
73 if (sweepAngle <= -FLOATNUM * PI) {
74 sweepAngle = -FLOATNUM * PI;
75 }
76 if (sweepAngle >= FLOATNUM * PI) {
77 sweepAngle = FLOATNUM * PI;
78 }
79 if (MATH_ABS(sweepAngle) < 1e-10) {
80 numberVertices_ = BEZIER_ARC_POINTS;
81 currentCommand_ = PATH_CMD_LINE_TO;
82 arrayVertices_[0] = centerX + rx * Cos(startAngle * RADIAN_TO_ANGLE);
83 arrayVertices_[1] = centerY + ry * Sin(startAngle * RADIAN_TO_ANGLE);
84 arrayVertices_[2] = centerX + rx * Cos((startAngle + sweepAngle) * RADIAN_TO_ANGLE);
85 arrayVertices_[3] = centerY + ry * Sin((startAngle + sweepAngle) * RADIAN_TO_ANGLE);
86 return;
87 }
88
89 float prevSweep;
90 float totalSweep = 0.0f;
91 float localSweep = 0.0f;
92 numberVertices_ = BEZIER_ARC_SETUP;
93 currentCommand_ = PATH_CMD_CURVE4;
94 bool done = false;
95 do {
96 if (sweepAngle < 0.0f) {
97 prevSweep = totalSweep;
98 totalSweep -= PI * HALFNUM;
99 localSweep = -PI * HALFNUM;
100 if (totalSweep <= sweepAngle + BEZIER_ARC_ANGLE_EPSILON) {
101 localSweep = sweepAngle - prevSweep;
102 done = true;
103 }
104 } else {
105 prevSweep = totalSweep;
106 totalSweep += PI * HALFNUM;
107 localSweep = PI * HALFNUM;
108 if (totalSweep >= sweepAngle - BEZIER_ARC_ANGLE_EPSILON) {
109 localSweep = sweepAngle - prevSweep;
110 done = true;
111 }
112 }
113
114 ArcToBezier(centerX, centerY, rx, ry, startAngle, localSweep, arrayVertices_
115 + numberVertices_ - BEZIER_ARC_SETUP);
116
117 startAngle += localSweep;
118 numberVertices_ += BEZIER_ARC_VERTICES_SIZE_STEP;
119 } while (numberVertices_ < BEZIER_ARC_VERTEX_NUM && !done);
120 }
121
Init(float x0,float y0,float rx,float ry,float angle,bool largeArcFlag,bool sweepFlag,float x2,float y2)122 void BezierArcSvg::Init(float x0, float y0,
123 float rx, float ry,
124 float angle,
125 bool largeArcFlag,
126 bool sweepFlag,
127 float x2, float y2)
128 {
129 if (ry < 0.0f) {
130 ry = -ry;
131 }
132 if (rx < 0.0f) {
133 rx = -rx;
134 }
135 isRadiusJoinPath_ = true;
136 float delatY2 = (y0 - y2) / FLOATNUM;
137 float delatX2 = (x0 - x2) / FLOATNUM;
138 float sinA = Sin(angle * RADIAN_TO_ANGLE);
139 float cosA = Cos(angle * RADIAN_TO_ANGLE);
140 float y1 = -sinA * delatX2 + cosA * delatY2;
141 float x1 = cosA * delatX2 + sinA * delatY2;
142 float prx = rx * rx;
143 float pry = ry * ry;
144 float px1 = x1 * x1;
145 float py1 = y1 * y1;
146 float radiiCheck = px1 / prx + py1 / pry;
147 if (radiiCheck > 1.0f) {
148 ry = Sqrt(radiiCheck) * ry;
149 rx = Sqrt(radiiCheck) * rx;
150 pry = ry * ry;
151 prx = rx * rx;
152 if (radiiCheck > BEZIER_ARC_RADIICHECK) {
153 isRadiusJoinPath_ = false;
154 }
155 }
156 float sign = (largeArcFlag == sweepFlag) ? -1.0f : 1.0f;
157 float sq = (prx * pry - prx * py1 - pry * px1) / (prx * py1 + pry * px1);
158 float coef = sign * Sqrt((sq < 0) ? 0 : sq);
159 if (fabs(ry) < epsilon) {
160 ry += VERTEX_DIST_EPSILON;
161 }
162 if (fabs(rx) < epsilon) {
163 rx += VERTEX_DIST_EPSILON;
164 }
165 float cx1 = coef * ((rx * y1) / ry);
166 float cy1 = coef * -((ry * x1) / rx);
167 float sx2 = (x0 + x2) / FLOATNUM;
168 float sy2 = (y0 + y2) / FLOATNUM;
169 float cx = sx2 + (cosA * cx1 - sinA * cy1);
170 float cy = sy2 + (sinA * cx1 + cosA * cy1);
171 float ux = (x1 - cx1) / rx;
172 float uy = (y1 - cy1) / ry;
173 float vx = (-x1 - cx1) / rx;
174 float vy = (-y1 - cy1) / ry;
175 float p = ux;
176 float n = Sqrt(ux * ux + uy * uy);
177 sign = (uy < 0) ? -1.0f : 1.0f;
178 if (fabs(n) < epsilon) {
179 n += VERTEX_DIST_EPSILON;
180 }
181 float v = p / n;
182 if (v > 1.0f) {
183 v = 1.0f;
184 }
185 if (v < -1.0f) {
186 v = -1.0f;
187 }
188 float startAngle = sign * Acos(v);
189 n = Sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
190 p = ux * vx + uy * vy;
191 sign = (ux * vy - uy * vx < 0) ? -1.0f : 1.0f;
192 if (fabs(n) < epsilon) {
193 n += VERTEX_DIST_EPSILON;
194 }
195 v = p / n;
196 if (v < -1.0f) {
197 v = -1.0f;
198 }
199 if (v > 1.0f) {
200 v = 1.0f;
201 }
202 float sweepAngle = sign * Acos(v);
203 if (!sweepFlag && sweepAngle > 0.0f) {
204 sweepAngle -= PI * FLOATNUM;
205 } else if (sweepFlag && sweepAngle < 0.0f) {
206 sweepAngle += PI * FLOATNUM;
207 }
208 bezierArcModel_.Init(0.0f, 0.0f, rx, ry, startAngle, sweepAngle);
209 TransAffine mtx = TransAffine::TransAffineRotation(angle);
210 mtx *= TransAffine::TransAffineTranslation(cx, cy);
211 uint32_t limit = bezierArcModel_.GetNumberVertices() - BEZIER_ARC_SETUP;
212 for (uint32_t i = BEZIER_ARC_SETUP; i < limit; i += BEZIER_ARC_SETUP) {
213 mtx.Transform(bezierArcModel_.GetVertices() + i, bezierArcModel_.GetVertices() + i + 1);
214 }
215 bezierArcModel_.GetVertices()[0] = x0;
216 bezierArcModel_.GetVertices()[1] = y0;
217 if (bezierArcModel_.GetNumberVertices() > BEZIER_ARC_SETUP) {
218 bezierArcModel_.GetVertices()[bezierArcModel_.GetNumberVertices() - BEZIER_ARC_SETUP] = x2;
219 bezierArcModel_.GetVertices()[bezierArcModel_.GetNumberVertices() - 1] = y2;
220 }
221 }
222 #endif
223 } // namespace OHOS
224