f3df458ac19bdefd80ae656e1c9c3d734a5e01ef
[ipdf/code.git] / src / bezier.h
1 #ifndef _BEZIER_H
2 #define _BEZIER_H
3
4 #include "real.h"
5 #include "rect.h"
6 namespace IPDF
7 {
8         extern int Factorial(int n);
9         extern int BinomialCoeff(int n, int k);
10         extern Real Bernstein(int k, int n, const Real & u);
11         
12         inline std::pair<Real,Real> SolveQuadratic(const Real & a, const Real & b, const Real & c)
13         {
14                 Real x0((-b + Sqrt(b*b - Real(4)*a*c))/(Real(2)*a));
15                 Real x1((-b - Sqrt(b*b - Real(4)*a*c))/(Real(2)*a));
16                 return std::pair<Real,Real>(x0,x1);
17         }
18
19         /** A _cubic_ bezier. **/
20         struct Bezier
21         {
22                 Real x0; Real y0;
23                 Real x1; Real y1;
24                 Real x2; Real y2;
25                 Real x3; Real y3;
26                 Bezier() = default; // Needed so we can fread/fwrite this struct... for now.
27                 Bezier(Real _x0, Real _y0, Real _x1, Real _y1, Real _x2, Real _y2, Real _x3, Real _y3) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x3), y3(_y3) 
28                 {
29                         
30                 }
31                 
32                 Bezier(Real _x0, Real _y0, Real _x1, Real _y1, Real _x2, Real _y2) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x2), y3(_y2) {}
33                 
34                 std::string Str() const
35                 {
36                         std::stringstream s;
37                         s << "Bezier{" << Float(x0) << "," << Float(y0) << " -> " << Float(x1) << "," << Float(y1) << " -> " << Float(x2) << "," << Float(y2) << " -> " << Float(x3) << "," << Float(y3) << "}";
38                         return s.str();
39                 }
40                 
41                 /**
42                  * Construct absolute control points using relative control points to a bounding rectangle
43                  * ie: If cpy is relative to bounds rectangle, this will be absolute
44                  */
45                 Bezier(const Bezier & cpy, const Rect & t = Rect(0,0,1,1)) : x0(cpy.x0), y0(cpy.y0), x1(cpy.x1), y1(cpy.y1), x2(cpy.x2),y2(cpy.y2), x3(cpy.x3), y3(cpy.y3)
46                 {
47                         x0 *= t.w;
48                         y0 *= t.h;
49                         x1 *= t.w;
50                         y1 *= t.h;
51                         x2 *= t.w;
52                         y2 *= t.h;
53                         x3 *= t.w;
54                         y3 *= t.h;
55                         x0 += t.x;
56                         y0 += t.y;
57                         x1 += t.x;
58                         y1 += t.y;
59                         x2 += t.x;
60                         y2 += t.y;
61                         x3 += t.x;
62                         y3 += t.y;
63                 }
64
65                 Rect SolveBounds() const;
66                 
67                 Bezier ToAbsolute(const Rect & bounds) const
68                 {
69                         return Bezier(*this, bounds);
70                 }
71                 
72                 /** Convert absolute control points to control points relative to bounds
73                  * (This basically does the opposite of the Copy constructor)
74                  * ie: If this is absolute, the returned Bezier will be relative to the bounds rectangle
75                  */
76                 Bezier ToRelative(const Rect & bounds) const
77                 {
78                         // x' <- (x - x0)/w etc
79                         // special cases when w or h = 0
80                         // (So can't just use the Copy constructor on the inverse of bounds)
81                         // Rect inverse = {-bounds.x/bounds.w, -bounds.y/bounds.h, Real(1)/bounds.w, Real(1)/bounds.h};
82                         Bezier result;
83                         if (bounds.w == 0)
84                         {
85                                 result.x0 = 0;
86                                 result.x1 = 0;
87                                 result.x2 = 0;
88                                 result.x3 = 0;
89                         }
90                         else
91                         {
92                                 result.x0 = (x0 - bounds.x)/bounds.w;   
93                                 result.x1 = (x1 - bounds.x)/bounds.w;
94                                 result.x2 = (x2 - bounds.x)/bounds.w;
95                                 result.x3 = (x3 - bounds.x)/bounds.w;
96                         }
97
98                         if (bounds.h == 0)
99                         {
100                                 result.y0 = 0;
101                                 result.y1 = 0;
102                                 result.y2 = 0;
103                                 result.y3 = 0;
104                         }
105                         else
106                         {
107                                 result.y0 = (y0 - bounds.y)/bounds.h;   
108                                 result.y1 = (y1 - bounds.y)/bounds.h;
109                                 result.y2 = (y2 - bounds.y)/bounds.h;
110                                 result.y3 = (y3 - bounds.y)/bounds.h;
111                         }
112                         return result;
113                 }
114                 
115
116                 /** Evaluate the Bezier at parametric parameter u, puts resultant point in (x,y) **/
117                 void Evaluate(Real & x, Real & y, const Real & u) const
118                 {
119                         Real coeff[4];
120                         for (unsigned i = 0; i < 4; ++i)
121                                 coeff[i] = Bernstein(i,3,u);
122                         x = x0*coeff[0] + x1*coeff[1] + x2*coeff[2] + x3*coeff[3];
123                         y = y0*coeff[0] + y1*coeff[1] + y2*coeff[2] + y3*coeff[3];
124                 }
125
126         };
127
128
129
130 }
131
132 #endif //_BEZIER_H

UCC git Repository :: git.ucc.asn.au