• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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