LMMS
Loading...
Searching...
No Matches
lice_bezier.h
Go to the documentation of this file.
1#ifndef _LICE_BEZIER_
2#define _LICE_BEZIER_
3
4#include "lice.h"
5#include <math.h>
6
7// Returns quadratic bezier x, y for a given t in [0,1].
8template <class T>
9void LICE_Bezier(T ctrl_x1, T ctrl_x2, T ctrl_x3,
10 T ctrl_y1, T ctrl_y2, T ctrl_y3, double t, T* pX, T* pY)
11{
12 double it = 1.0 - t;
13 double a = it * it;
14 double b = 2.0 * it * t;
15 double c = t * t;
16 *pX = (T) (a * (double) ctrl_x1 + b * (double) ctrl_x2 + c * (double) ctrl_x3);
17 *pY = (T) (a * (double) ctrl_y1 + b * (double) ctrl_y2 + c * (double) ctrl_y3);
18}
19
20template <class T>
21void LICE_CBezier_GetCoeffs(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4,
22 T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4,
23 double* pAX, double* pBX, double* pCX,
24 double* pAY, double* pBY, double* pCY)
25{
26 double cx = *pCX = 3.0 * (double) (ctrl_x2 - ctrl_x1);
27 double bx = *pBX = 3.0 * (double) (ctrl_x3 - ctrl_x2) - cx;
28 *pAX = (double) (ctrl_x4 - ctrl_x1) - cx - bx;
29 double cy = *pCY = 3.0 * (double) (ctrl_y2 - ctrl_y1);
30 double by = *pBY = 3.0 * (double) (ctrl_y3 - ctrl_y2) - cy;
31 *pAY = (double) (ctrl_y4 - ctrl_y1) - cy - by;
32}
33
34// Returns cubic bezier x, y for a given t in [0,1].
35template <class T>
36void LICE_CBezier(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4,
37 T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4, double t, T* pX, T* pY)
38{
39 double ax, bx, cx, ay, by, cy;
40 LICE_CBezier_GetCoeffs(ctrl_x1, ctrl_x2, ctrl_x3, ctrl_x4,
41 ctrl_y1, ctrl_y2, ctrl_y3, ctrl_y4,
42 &ax, &bx, &cx, &ay, &by, &cy);
43
44 double t2 = t * t;
45 double t3 = t * t2;
46 *pX = (T) (ax * t3 + bx * t2 + cx * t) + ctrl_x1;
47 *pY = (T) (ay * t3 + by * t2 + cy * t) + ctrl_y1;
48}
49
50// Returns quadratic bezier y for a given x in [x1, x3] (for rasterizing).
51// ctrl_x1 < ctrl_x3 required.
52template <class T>
53T LICE_Bezier_GetY(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_y1, T ctrl_y2, T ctrl_y3, T x, double* pt=0)
54{
55 if (x <= ctrl_x1)
56 {
57 if (pt) *pt = 0.0;
58 return ctrl_y1;
59 }
60 if (x >= ctrl_x3)
61 {
62 if (pt) *pt = 1.0;
63 return ctrl_y3;
64 }
65
66 double t, a = (double) ctrl_x1 - (double) (2 * ctrl_x2) + (double) ctrl_x3;
67 if (a == 0.0)
68 {
69 t=(ctrl_x1 == ctrl_x3) ? 0.0 : (x-ctrl_x1)/(ctrl_x3-ctrl_x1);
70 }
71 else
72 {
73 t = (double) (ctrl_x2 - ctrl_x1);
74 t = (-t + sqrt(t * t - a * (ctrl_x1 - x))) / a;
75 }
76 const double it = 1.0 - t;
77
78 if (pt) *pt = t;
79 return (T) (it * it * (double) ctrl_y1 + t * (2.0*it*(double)ctrl_y2 + t * (double) ctrl_y3));
80}
81
82// Special case for x = y = [0,1]
83template <class T>
84void LICE_Bezier_Norm(T ctrl_x2, T ctrl_y2, double t, T* pX, T* pY)
85{
86 double b = 2.0 * (1.0 - t) * t;
87 double c = t * t;
88 *pX = (T) (b * (double) ctrl_x2 + c);
89 *pY = (T) (b * (double) ctrl_y2 + c);
90}
91
92// special case for x = y = [0,1].
93template <class T>
94T LICE_Bezier_GetY_Norm(T ctrl_x2, T ctrl_y2, T x)
95{
96 if (x < (T) 0.0) {
97 return (T) 0.0;
98 }
99 if (x >= (T) 1.0) {
100 return (T) 1.0;
101 }
102 if (ctrl_x2 == (T) 0.5) { // linear
103 return x;
104 }
105
106
107/*
108 // this causes ICC 11.0 to produce bad results on OSX/386
109 double b = (double) (2 * ctrl_x2);
110 double a = 1.0 - b;
111 double c = (double) -x;
112 double t = (-b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a);
113
114 b = 2.0 * (1.0 - t) * t;
115 c = t * t;
116 return (T) (b * (double) ctrl_y2 + c);
117
118 // the simplified math below works properly
119*/
120
121
122 const double t = (-ctrl_x2 + sqrt(ctrl_x2 * (ctrl_x2 - 2.0*x) + x)) / (1.0-2.0*ctrl_x2);
123
124 return (T) (((2.0 * (1.0-t)) * ctrl_y2 + t)*t);
125}
126
127// Finds the cardinal bezier control points surrounding x2.
128// Cubic bezier over (x1,x1b,x2a,x2), (y1,y1b,y2a,y2) or
129// quadratic bezier over (x1,x1b,mid(x1b,x2a)), (y1,y1b,mid(y1b,y2a))
130// will smoothly interpolate between (x1,y1) and (x2,y2) while preserving all existing values.
131// The lower alpha is, the more tame the bezier curve will be (0.25 = subtle).
132template <class T>
133void LICE_Bezier_FindCardinalCtlPts(double alpha, T x1, T x2, T x3, T y1, T y2, T y3,
134 T* ctrl_x2a, T* ctrl_x2b, T* ctrl_y2a, T* ctrl_y2b)
135{
136 double dxa = alpha * (double) (x2 - x1);
137 double dxb = alpha * (double) (x3 - x2);
138 if (ctrl_x2a) *ctrl_x2a = x2 - (T) dxa;
139 if (ctrl_x2b) *ctrl_x2b = x2 + (T) dxb;
140
141 if (x1 == x3)
142 {
143 if (ctrl_y2a) *ctrl_y2a = y2;
144 if (ctrl_y2b) *ctrl_y2b = y2;
145 }
146 else
147 {
148 double m = (double) (y3 - y1) / (double) (x3 - x1);
149 if (ctrl_y2a) *ctrl_y2a = y2 - (T) (m * dxa);
150 if (ctrl_y2b) *ctrl_y2b = y2 + (T) (m * dxb);
151 }
152}
153
154// Basic quadratic nurbs. Given a set of n (x,y) pairs,
155// populate pDest with the unit-spaced nurbs curve.
156// pDest must be passed in with size (int) (*(pX+n-1) - *pX).
157// pX must be monotonically increasing and no duplicates.
158template <class T>
159inline void LICE_QNurbs(T* pDest, int pDest_sz, int *pX, T* pY, int n)
160{
161 int x1 = *pX++, x2 = *pX++;
162 T y1 = *pY++, y2 = *pY++;
163 double xm1, xm2 = 0.5 * (x1 + x2);
164 double ym1, ym2 = 0.5 * (y1 + y2);
165
166 double yi = y1, m = (y2 - y1) / (double) (x2 - x1);
167 int xi = x1, iend = (int)floor(xm2+0.5); // this (and below) was previously ceil(), but can't see any reason why it should matter (this should be more correct, I'd imagine)
168 for (; xi < iend; xi++, yi += m)
169 {
170 if (--pDest_sz<0) return;
171 *pDest++ = (T) yi;
172 }
173
174 for (int i = 2; i < n; ++i)
175 {
176 x1 = x2;
177 x2 = *pX++;
178 y1 = y2;
179 y2 = *pY++;
180
181 xm1 = xm2;
182 xm2 = 0.5 * (x1 + x2);
183 ym1 = ym2;
184 ym2 = 0.5 * (y1 + y2);
185
186 iend = (int)floor(xm2+0.5);
187 if (ym1 == ym2 && y1 == ym1)
188 {
189 for (; xi < iend; xi++)
190 {
191 if (--pDest_sz<0) return;
192 *pDest++ = (T) y1;
193 }
194 }
195 else
196 {
197 for (; xi < iend; xi++)
198 {
199 if (--pDest_sz<0) return;
200 *pDest++ = (T) LICE_Bezier_GetY(xm1, (double)x1, xm2, ym1, (double)y1, ym2, (double)xi);
201 }
202 }
203 }
204
205 m = (y2 - y1) / (double) (x2 - x1);
206 yi = ym2;
207 for (; xi < x2; xi++, yi += m)
208 {
209 if (--pDest_sz<0) return;
210 *pDest++ = (T) yi;
211 }
212}
213
214#define CBEZ_ITERS 8
215
216#define EVAL_CBEZ(tx,a,b,c,d,t) \
217{ \
218 double _t2=t*t; \
219 tx=(a*t*_t2+b*_t2+c*t+d); \
220}
221
222#define EVAL_CBEZXY(tx, ty, ax, bx, cx, dx, ay, by, cy, dy, t) \
223{ \
224 double _t2=t*t; \
225 double _t3=t*_t2; \
226 tx=ax*_t3+bx*_t2+cx*t+dx; \
227 ty=ay*_t3+by*_t2+cy*t+dy; \
228}
229
230template <class T>
231T LICE_CBezier_GetY(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4,
232 T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4, T x,
233 T* pNextX = 0, T* pdYdX = 0, double* ptLo = 0, double* ptHi = 0)
234{
235 if (x < ctrl_x1)
236 {
237 if (pNextX) *pNextX = ctrl_x1;
238 if (pdYdX) *pdYdX = (T) 0.0;
239 return ctrl_y1;
240 }
241 if (x >= ctrl_x4)
242 {
243 if (pNextX) *pNextX = ctrl_x4;
244 if (pdYdX) *pdYdX = (T) 0.0;
245 return ctrl_y4;
246 }
247
248 double ax, bx, cx, ay, by, cy;
249 LICE_CBezier_GetCoeffs(ctrl_x1, ctrl_x2, ctrl_x3, ctrl_x4,
250 ctrl_y1, ctrl_y2, ctrl_y3, ctrl_y4,
251 &ax, &bx, &cx, &ay, &by, &cy);
252
253 double tx, t, tLo = 0.0, tHi = 1.0;
254 double xLo=0.0, xHi=0.0, yLo, yHi;
255 int i;
256 for (i = 0; i < CBEZ_ITERS; ++i)
257 {
258 t = 0.5 * (tLo + tHi);
259 EVAL_CBEZ(tx, ax, bx, cx, (double) ctrl_x1, t);
260 if (tx < (double) x)
261 {
262 tLo = t;
263 xLo = tx;
264 }
265 else if (tx > (double) x)
266 {
267 tHi = t;
268 xHi = tx;
269 }
270 else
271 {
272 tLo = t;
273 xLo = tx;
274 tHi = t + 1.0/pow(2.0,CBEZ_ITERS);
275 if (tHi > 1.0) tHi = 1.0; // floating point error
276 EVAL_CBEZ(xHi, ax, bx, cx, (double) ctrl_x1, tHi);
277 break;
278 }
279 }
280
281 if (tLo == 0.0) EVAL_CBEZ(xLo, ax, bx, cx, (double) ctrl_x1, 0.0);
282 if (tHi == 1.0) EVAL_CBEZ(xHi, ax, bx, cx, (double) ctrl_x1, 1.0);
283
284 EVAL_CBEZ(yLo, ay, by, cy, (double) ctrl_y1, tLo);
285 EVAL_CBEZ(yHi, ay, by, cy, (double) ctrl_y1, tHi);
286
287 double dYdX = (xLo == xHi ? 0.0 : (yHi - yLo) / (xHi - xLo));
288 double y = yLo + ((double) x - xLo) * dYdX;
289
290 if (pNextX) *pNextX = (T) xHi;
291 if (pdYdX) *pdYdX = (T) dYdX;
292
293 if (ptLo) *ptLo = tLo;
294 if (ptHi) *ptHi = tHi;
295
296 return (T) y;
297}
298
299#endif
300
uint8_t a
Definition Spc_Cpu.h:141
unsigned * m
Definition inflate.c:1559
struct huft * t
Definition inflate.c:943
int y
Definition inflate.c:1588
register unsigned i
Definition inflate.c:1575
unsigned x[BMAX+1]
Definition inflate.c:1586
void LICE_Bezier(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_y1, T ctrl_y2, T ctrl_y3, double t, T *pX, T *pY)
Definition lice_bezier.h:9
#define CBEZ_ITERS
Definition lice_bezier.h:214
void LICE_CBezier_GetCoeffs(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4, T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4, double *pAX, double *pBX, double *pCX, double *pAY, double *pBY, double *pCY)
Definition lice_bezier.h:21
void LICE_CBezier(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4, T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4, double t, T *pX, T *pY)
Definition lice_bezier.h:36
void LICE_Bezier_Norm(T ctrl_x2, T ctrl_y2, double t, T *pX, T *pY)
Definition lice_bezier.h:84
T LICE_Bezier_GetY(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_y1, T ctrl_y2, T ctrl_y3, T x, double *pt=0)
Definition lice_bezier.h:53
T LICE_Bezier_GetY_Norm(T ctrl_x2, T ctrl_y2, T x)
Definition lice_bezier.h:94
#define EVAL_CBEZ(tx, a, b, c, d, t)
Definition lice_bezier.h:216
void LICE_Bezier_FindCardinalCtlPts(double alpha, T x1, T x2, T x3, T y1, T y2, T y3, T *ctrl_x2a, T *ctrl_x2b, T *ctrl_y2a, T *ctrl_y2b)
Definition lice_bezier.h:133
void LICE_QNurbs(T *pDest, int pDest_sz, int *pX, T *pY, int n)
Definition lice_bezier.h:159
T LICE_CBezier_GetY(T ctrl_x1, T ctrl_x2, T ctrl_x3, T ctrl_x4, T ctrl_y1, T ctrl_y2, T ctrl_y3, T ctrl_y4, T x, T *pNextX=0, T *pdYdX=0, double *ptLo=0, double *ptHi=0)
Definition lice_bezier.h:231
int n
Definition crypt.c:458
return c
Definition crypt.c:175
b
Definition crypt.c:628
typedef int(UZ_EXP MsgFn)()