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 /**
17 * @file geometry_curves.h
18 *
19 * @brief Bezier Curve
20 *
21 * @since 1.0
22 * @version 1.0
23 */
24
25 #ifndef GRAPHIC_LITE_GEOMETRY_CURVES_H
26 #define GRAPHIC_LITE_GEOMETRY_CURVES_H
27
28 #include "gfx_utils/vector.h"
29 namespace OHOS {
30 const uint8_t CURVE_POINTS_LENGTH = 8;
31
32 enum CurveApproximationMethod {
33 CURVEINCREMENT,
34 CURVEDIVIDOPERATE
35 };
36
37 class QuadBezierCurveIncr {
38 public:
QuadBezierCurveIncr()39 QuadBezierCurveIncr() : numberSteps_(0), currentStep_(0), approximationScale_(1.0f) {}
40
QuadBezierCurveIncr(float x1,float y1,float x2,float y2,float x3,float y3)41 QuadBezierCurveIncr(float x1, float y1,
42 float x2, float y2,
43 float x3, float y3)
44 : numberSteps_(0), currentStep_(0), approximationScale_(1.0f)
45 {
46 Init(x1, y1, x2, y2, x3, y3);
47 }
48
49 void Init(float x1, float y1, float x2, float y2, float x3, float y3);
50
51 void Reset();
52
ApproximationMethod(CurveApproximationMethod)53 void ApproximationMethod(CurveApproximationMethod) {}
54
55 CurveApproximationMethod ApproximationMethod() const;
56
57 void ApproximationScale(float scale);
58
59 float ApproximationScale() const;
60
AngleTolerance(float)61 void AngleTolerance(float) {}
62
63 float AngleTolerance() const;
64
CuspLimit(float)65 void CuspLimit(float) {}
66
67 float CuspLimit() const;
68
69 void Rewind(uint32_t pathId);
70
71 uint32_t GenerateVertex(float* x, float* y);
72
73 private:
74 int32_t numberSteps_;
75 int32_t currentStep_;
76 float approximationScale_;
77 PointF startCoordinate_;
78 PointF endCoordinate_;
79 PointF finalCoordinate_;
80 PointF deltaFinalCoordinate_;
81 PointF copyDeltaFinalCoordinate_;
82 PointF savedFinalCoordinate_;
83 PointF savedDeltaFinalCoordinate_;
84 };
85
86 class QuadrBezierCurveDividOp {
87 public:
QuadrBezierCurveDividOp()88 QuadrBezierCurveDividOp()
89 : approximationScale_(1.0f), distanceToleranceSquare_(0.0f), angleTolerance_(0.0f), count_(0) {}
90
QuadrBezierCurveDividOp(float x1,float y1,float x2,float y2,float x3,float y3)91 QuadrBezierCurveDividOp(float x1, float y1,
92 float x2, float y2,
93 float x3, float y3)
94 : approximationScale_(1.0f), angleTolerance_(0.0f), count_(0)
95 {
96 Init(x1, y1, x2, y2, x3, y3);
97 }
98
99 void Init(float x1, float y1, float x2, float y2, float x3, float y3);
100
101 void Reset();
102
ApproximationMethod(CurveApproximationMethod)103 void ApproximationMethod(CurveApproximationMethod) {}
104
105 CurveApproximationMethod ApproximationMethod() const;
106
107 void ApproximationScale(float scale);
108
109 float ApproximationScale() const;
110
111 void AngleTolerance(float angle);
112
113 float AngleTolerance() const;
114
CuspLimit(float)115 void CuspLimit(float) {}
116
117 float CuspLimit() const;
118
119 void Rewind(uint32_t);
120
121 uint32_t GenerateVertex(float* x, float* y);
122
123 private:
124 void Bezier(float x1, float y1,
125 float x2, float y2,
126 float x3, float y3);
127 void Recursive(float x1, float y1,
128 float x2, float y2,
129 float x3, float y3,
130 uint32_t level);
131
132 float approximationScale_;
133 float distanceToleranceSquare_;
134 float angleTolerance_;
135 uint32_t count_;
136 Graphic::Vector<PointF> points_;
137 };
138
139 struct CubicBezierCurvePoints {
140 float cpArray[CURVE_POINTS_LENGTH];
141
CubicBezierCurvePointsCubicBezierCurvePoints142 CubicBezierCurvePoints() {}
143
CubicBezierCurvePointsCubicBezierCurvePoints144 CubicBezierCurvePoints(float x1, float y1,
145 float x2, float y2,
146 float x3, float y3,
147 float x4, float y4)
148 {
149 cpArray[0] = x1;
150 cpArray[1] = y1;
151 cpArray[2] = x2;
152 cpArray[3] = y2;
153 cpArray[4] = x3;
154 cpArray[5] = y3;
155 cpArray[6] = x4;
156 cpArray[7] = y4;
157 }
158
InitCubicBezierCurvePoints159 void Init(float x1, float y1,
160 float x2, float y2,
161 float x3, float y3,
162 float x4, float y4)
163 {
164 cpArray[0] = x1;
165 cpArray[1] = y1;
166 cpArray[2] = x2;
167 cpArray[3] = y2;
168 cpArray[4] = x3;
169 cpArray[5] = y3;
170 cpArray[6] = x4;
171 cpArray[7] = y4;
172 }
173
174 float operator[](uint32_t i) const
175 {
176 return cpArray[i];
177 }
178 float& operator[](uint32_t i)
179 {
180 return cpArray[i];
181 }
182 };
183
184 class CubicBezierCurveIncrement {
185 public:
CubicBezierCurveIncrement()186 CubicBezierCurveIncrement()
187 : numberSteps_(0), currentStep_(0), approximationScale_(1.0f) {}
188
CubicBezierCurveIncrement(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)189 CubicBezierCurveIncrement(float x1, float y1, float x2, float y2,
190 float x3, float y3, float x4, float y4)
191 : numberSteps_(0), currentStep_(0), approximationScale_(1.0f)
192 {
193 Init(x1, y1, x2, y2, x3, y3, x4, y4);
194 }
195
CubicBezierCurveIncrement(const CubicBezierCurvePoints & curve4Points)196 CubicBezierCurveIncrement(const CubicBezierCurvePoints& curve4Points)
197 : numberSteps_(0), currentStep_(0), approximationScale_(1.0f)
198 {
199 Init(curve4Points[0], curve4Points[1], curve4Points[2], curve4Points[3],
200 curve4Points[4], curve4Points[5], curve4Points[6], curve4Points[7]);
201 }
202
203 void Init(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4);
Init(const CubicBezierCurvePoints & curve4Points)204 void Init(const CubicBezierCurvePoints& curve4Points)
205 {
206 Init(curve4Points[0], curve4Points[1], curve4Points[2], curve4Points[3],
207 curve4Points[4], curve4Points[5], curve4Points[6], curve4Points[7]);
208 }
209
210 void Reset();
211
ApproximationMethod(CurveApproximationMethod)212 void ApproximationMethod(CurveApproximationMethod) {}
213
214 CurveApproximationMethod ApproximationMethod() const;
215
216 void ApproximationScale(float scale);
217
218 float ApproximationScale() const;
219
AngleTolerance(float)220 void AngleTolerance(float) {}
221
222 float AngleTolerance() const;
223
CuspLimit(float)224 void CuspLimit(float) {}
225
226 float CuspLimit() const;
227
228 void Rewind(uint32_t pathId);
229
230 uint32_t GenerateVertex(float* x, float* y);
231
232 private:
233 int32_t numberSteps_;
234 int32_t currentStep_;
235 float approximationScale_;
236 PointF startCoordinate_;
237 PointF endCoordinate_;
238 PointF finalCoordinate_;
239 PointF deltaFinalCoordinate_;
240 PointF copyDeltaFinalCoordinate_;
241 PointF repeatCopyDeltaFinalCoordinate_;
242 PointF savedFinalCoordinate_;
243 PointF savedDeltaFinalCoordinate_;
244 PointF savedCopyDeltaFinalCoordinate_;
245 };
246
CatromToBezier(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)247 inline CubicBezierCurvePoints CatromToBezier(float x1, float y1,
248 float x2, float y2,
249 float x3, float y3,
250 float x4, float y4)
251 {
252 return CubicBezierCurvePoints(
253 x2,
254 y2,
255 (-x1 + SIX_TIMES * x2 + x3) / SIX_TIMES,
256 (-y1 + SIX_TIMES * y2 + y3) / SIX_TIMES,
257 (x2 + SIX_TIMES * x3 - x4) / SIX_TIMES,
258 (y2 + SIX_TIMES * y3 - y4) / SIX_TIMES,
259 x3,
260 y3);
261 }
262
CatromToBezier(const CubicBezierCurvePoints & curve4Points)263 inline CubicBezierCurvePoints CatromToBezier(const CubicBezierCurvePoints& curve4Points)
264 {
265 return CatromToBezier(curve4Points[0], curve4Points[1], curve4Points[2],
266 curve4Points[3], curve4Points[4], curve4Points[5],
267 curve4Points[6], curve4Points[7]);
268 }
269 /**
270 * @brief bspline Convert Curve to Cubic Bezier Curve
271 * @param bspline Curve 4 points, start, end and middle 2 control points
272 * @since 1.0
273 * @version 1.0
274 */
UbsplineToBezier(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)275 inline CubicBezierCurvePoints UbsplineToBezier(float x1, float y1,
276 float x2, float y2,
277 float x3, float y3,
278 float x4, float y4)
279 {
280 return CubicBezierCurvePoints(
281 (x1 + FOUR_TIMES * x2 + x3) / SIX_TIMES,
282 (y1 + FOUR_TIMES * y2 + y3) / SIX_TIMES,
283 (FOUR_TIMES * x2 + TWO_TIMES * x3) / SIX_TIMES,
284 (FOUR_TIMES * y2 + TWO_TIMES * y3) / SIX_TIMES,
285 (TWO_TIMES * x2 + FOUR_TIMES * x3) / SIX_TIMES,
286 (TWO_TIMES * y2 + FOUR_TIMES * y3) / SIX_TIMES,
287 (x2 + FOUR_TIMES * x3 + x4) / SIX_TIMES,
288 (y2 + FOUR_TIMES * y3 + y4) / SIX_TIMES);
289 }
290 /**
291 * @brief bspline Convert Curve to Bezier Curve
292 * @param bspline Curve 4 points, start, end and middle 2 control points
293 * @since 1.0
294 * @version 1.0
295 */
UbsplineToBezier(const CubicBezierCurvePoints & curve4Points)296 inline CubicBezierCurvePoints UbsplineToBezier(const CubicBezierCurvePoints& curve4Points)
297 {
298 return UbsplineToBezier(curve4Points[0], curve4Points[1], curve4Points[2], curve4Points[3],
299 curve4Points[4], curve4Points[5], curve4Points[6], curve4Points[7]);
300 }
301 /**
302 * @brief Hermite Convert Curve to 3-order Bezier Curve
303 * @param Hermite Curve 2 points, start and end
304 * @since 1.0
305 * @version 1.0
306 */
HermiteToBezier(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)307 inline CubicBezierCurvePoints HermiteToBezier(float x1, float y1,
308 float x2, float y2,
309 float x3, float y3,
310 float x4, float y4)
311 {
312 return CubicBezierCurvePoints(
313 x1, y1,
314 (THREE_TIMES * x1 + x3) / THREE_TIMES,
315 (THREE_TIMES * y1 + y3) / THREE_TIMES,
316 (THREE_TIMES * x2 - x4) / THREE_TIMES,
317 (THREE_TIMES * y2 - y4) / THREE_TIMES,
318 x2, y2);
319 }
320 /**
321 * @brief Hermite Convert Curve to 3-order Bezier Curve
322 * @param Hermite Curve 2 points, start and end
323 * @since 1.0
324 * @version 1.0
325 */
HermiteToBezier(const CubicBezierCurvePoints & curve4Points)326 inline CubicBezierCurvePoints HermiteToBezier(const CubicBezierCurvePoints& curve4Points)
327 {
328 return HermiteToBezier(curve4Points[0], curve4Points[1],
329 curve4Points[2], curve4Points[3],
330 curve4Points[4], curve4Points[5],
331 curve4Points[6], curve4Points[7]);
332 }
333
334 class CubicBezierCurveDividOperate {
335 public:
CubicBezierCurveDividOperate()336 CubicBezierCurveDividOperate()
337 : approximationScale_(1.0f), distanceToleranceSquare_(0.0f),
338 angleTolerance_(0.0f), cuspLimit_(0.0f), count_(0) {}
339
CubicBezierCurveDividOperate(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)340 CubicBezierCurveDividOperate(float x1, float y1,
341 float x2, float y2,
342 float x3, float y3,
343 float x4, float y4)
344 : approximationScale_(1.0f), angleTolerance_(0.0f), cuspLimit_(0.0f), count_(0)
345 {
346 Init(x1, y1, x2, y2, x3, y3, x4, y4);
347 }
348
CubicBezierCurveDividOperate(const CubicBezierCurvePoints & curve4Points)349 CubicBezierCurveDividOperate(const CubicBezierCurvePoints& curve4Points)
350 : approximationScale_(1.0f), angleTolerance_(0.0f), count_(0)
351 {
352 Init(curve4Points[0], curve4Points[1],
353 curve4Points[2], curve4Points[3],
354 curve4Points[4], curve4Points[5],
355 curve4Points[6], curve4Points[7]);
356 }
357
358 void Init(float x1, float y1,
359 float x2, float y2,
360 float x3, float y3,
361 float x4, float y4);
362
Init(const CubicBezierCurvePoints & curve4Points)363 void Init(const CubicBezierCurvePoints& curve4Points)
364 {
365 Init(curve4Points[0], curve4Points[1],
366 curve4Points[2], curve4Points[3],
367 curve4Points[4], curve4Points[5],
368 curve4Points[6], curve4Points[7]);
369 }
370
371 void Reset();
372
ApproximationMethod(CurveApproximationMethod)373 void ApproximationMethod(CurveApproximationMethod) {}
374
375 CurveApproximationMethod ApproximationMethod() const;
376
377 void ApproximationScale(float scale);
378
379 float ApproximationScale() const;
380
381 void AngleTolerance(float angleValue);
382
383 float AngleTolerance() const;
384
385 void CuspLimit(float angleValue);
386
387 float CuspLimit() const;
388
389 void Rewind(uint32_t);
390
391 uint32_t GenerateVertex(float* x, float* y);
392
393 private:
394 void Bezier(float x1, float y1,
395 float x2, float y2,
396 float x3, float y3,
397 float x4, float y4);
398
399 void Recursive(float x1, float y1,
400 float x2, float y2,
401 float x3, float y3,
402 float x4, float y4,
403 uint32_t level);
404
405 float approximationScale_;
406 float distanceToleranceSquare_;
407 float angleTolerance_;
408 float cuspLimit_;
409 uint32_t count_;
410 Graphic::Vector<PointF> points_;
411 };
412
413 /**
414 * @brief quadratic Bezier curve.
415 *
416 * Draw a curve from the start, inflection and end points.
417 *
418 * @see QuadraticBezierCurve.
419 * @since 1.0
420 * @version 1.0
421 */
422 class QuadraticBezierCurve {
423 public:
QuadraticBezierCurve()424 QuadraticBezierCurve()
425 : approximationMethod_(CURVEDIVIDOPERATE) {}
426
QuadraticBezierCurve(float x1,float y1,float x2,float y2,float x3,float y3)427 QuadraticBezierCurve(float x1, float y1, float x2, float y2, float x3, float y3)
428 : approximationMethod_(CURVEDIVIDOPERATE)
429 {
430 Init(x1, y1, x2, y2, x3, y3);
431 }
432
Init(float x1,float y1,float x2,float y2,float x3,float y3)433 void Init(float x1, float y1, float x2, float y2, float x3, float y3)
434 {
435 if (approximationMethod_ == CURVEINCREMENT) {
436 curveInc_.Init(x1, y1, x2, y2, x3, y3);
437 } else {
438 curveDiv_.Init(x1, y1, x2, y2, x3, y3);
439 }
440 }
441
Reset()442 void Reset()
443 {
444 curveInc_.Reset();
445 curveDiv_.Reset();
446 }
447
ApproximationMethod(CurveApproximationMethod curveApproximationMethod)448 void ApproximationMethod(CurveApproximationMethod curveApproximationMethod)
449 {
450 approximationMethod_ = curveApproximationMethod;
451 }
452
ApproximationMethod()453 CurveApproximationMethod ApproximationMethod() const
454 {
455 return approximationMethod_;
456 }
457
SetApproximationScale(float scale)458 void SetApproximationScale(float scale)
459 {
460 curveInc_.ApproximationScale(scale);
461 curveDiv_.ApproximationScale(scale);
462 }
463
ApproximationScale()464 float ApproximationScale() const
465 {
466 return curveInc_.ApproximationScale();
467 }
468
AngleTolerance(float angle)469 void AngleTolerance(float angle)
470 {
471 curveDiv_.AngleTolerance(angle);
472 }
473
AngleTolerance()474 float AngleTolerance() const
475 {
476 return curveDiv_.AngleTolerance();
477 }
478
CuspLimit(float angleValue)479 void CuspLimit(float angleValue)
480 {
481 curveDiv_.CuspLimit(angleValue);
482 }
483
CuspLimit()484 float CuspLimit() const
485 {
486 return curveDiv_.CuspLimit();
487 }
488
Rewind(uint32_t pathId)489 void Rewind(uint32_t pathId)
490 {
491 if (approximationMethod_ == CURVEINCREMENT) {
492 curveInc_.Rewind(pathId);
493 } else {
494 curveDiv_.Rewind(pathId);
495 }
496 }
497
GenerateVertex(float * x,float * y)498 uint32_t GenerateVertex(float* x, float* y)
499 {
500 if (approximationMethod_ == CURVEINCREMENT) {
501 return curveInc_.GenerateVertex(x, y);
502 }
503 return curveDiv_.GenerateVertex(x, y);
504 }
505
506 private:
507 QuadBezierCurveIncr curveInc_;
508 QuadrBezierCurveDividOp curveDiv_;
509 CurveApproximationMethod approximationMethod_;
510 };
511
512 /**
513 * @brief Cubic Bezier curve
514 *
515 * Draw a curve according to the start point, control point and end point.
516 *
517 * @see CubicBezierCurve
518 * @since 1.0
519 * @version 1.0.
520 */
521 class CubicBezierCurve {
522 public:
CubicBezierCurve()523 CubicBezierCurve()
524 : approximationMethod_(CURVEDIVIDOPERATE) {}
525
CubicBezierCurve(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)526 CubicBezierCurve(float x1, float y1,
527 float x2, float y2,
528 float x3, float y3,
529 float x4, float y4)
530 : approximationMethod_(CURVEDIVIDOPERATE)
531 {
532 Init(x1, y1, x2, y2, x3, y3, x4, y4);
533 }
534
CubicBezierCurve(const CubicBezierCurvePoints & curve4Points)535 CubicBezierCurve(const CubicBezierCurvePoints& curve4Points)
536 : approximationMethod_(CURVEDIVIDOPERATE)
537 {
538 Init(curve4Points[0], curve4Points[1], curve4Points[2], curve4Points[3],
539 curve4Points[4], curve4Points[5], curve4Points[6], curve4Points[7]);
540 }
541
Init(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)542 void Init(float x1, float y1,
543 float x2, float y2,
544 float x3, float y3,
545 float x4, float y4)
546 {
547 if (approximationMethod_ == CURVEINCREMENT) {
548 curveInc_.Init(x1, y1, x2, y2, x3, y3, x4, y4);
549 } else {
550 curveDiv_.Init(x1, y1, x2, y2, x3, y3, x4, y4);
551 }
552 }
553
Init(const CubicBezierCurvePoints & curve4Points)554 void Init(const CubicBezierCurvePoints& curve4Points)
555 {
556 Init(curve4Points[0], curve4Points[1], curve4Points[2], curve4Points[3],
557 curve4Points[4], curve4Points[5], curve4Points[6], curve4Points[7]);
558 }
559
Reset()560 void Reset()
561 {
562 curveInc_.Reset();
563 curveDiv_.Reset();
564 }
565
ApproximationMethod(CurveApproximationMethod curveApproximationMethod)566 void ApproximationMethod(CurveApproximationMethod curveApproximationMethod)
567 {
568 approximationMethod_ = curveApproximationMethod;
569 }
570
ApproximationMethod()571 CurveApproximationMethod ApproximationMethod() const
572 {
573 return approximationMethod_;
574 }
575
SetApproximationScale(float scale)576 void SetApproximationScale(float scale)
577 {
578 curveInc_.ApproximationScale(scale);
579 curveDiv_.ApproximationScale(scale);
580 }
ApproximationScale()581 float ApproximationScale() const
582 {
583 return curveInc_.ApproximationScale();
584 }
585
AngleTolerance(float angleValue)586 void AngleTolerance(float angleValue)
587 {
588 curveDiv_.AngleTolerance(angleValue);
589 }
590
AngleTolerance()591 float AngleTolerance() const
592 {
593 return curveDiv_.AngleTolerance();
594 }
595
CuspLimit(float angleValue)596 void CuspLimit(float angleValue)
597 {
598 curveDiv_.CuspLimit(angleValue);
599 }
600
CuspLimit()601 float CuspLimit() const
602 {
603 return curveDiv_.CuspLimit();
604 }
605
Rewind(uint32_t pathId)606 void Rewind(uint32_t pathId)
607 {
608 if (approximationMethod_ == CURVEINCREMENT) {
609 curveInc_.Rewind(pathId);
610 } else {
611 curveDiv_.Rewind(pathId);
612 }
613 }
614
GenerateVertex(float * x,float * y)615 uint32_t GenerateVertex(float* x, float* y)
616 {
617 if (approximationMethod_ == CURVEINCREMENT) {
618 return curveInc_.GenerateVertex(x, y);
619 }
620 return curveDiv_.GenerateVertex(x, y);
621 }
622
623 private:
624 CubicBezierCurveIncrement curveInc_;
625 CubicBezierCurveDividOperate curveDiv_;
626 CurveApproximationMethod approximationMethod_;
627 };
628 } // namespace OHOS
629 #endif
630