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