1 /*$
2 Copyright (C) 2013-2020 Azel.
3
4 This file is part of AzPainter.
5
6 AzPainter is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 AzPainter is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 $*/
19
20 /*****************************************
21 * SplineBuf
22 *
23 * スプラインのポイントバッファ
24 *****************************************/
25
26 #include <math.h>
27
28 #include "mDef.h"
29 #include "mMemAuto.h"
30
31 #include "defDrawGlobal.h"
32 #include "draw_calc.h"
33
34
35 //----------------------
36
37 typedef struct
38 {
39 int x,y; //キャンバス位置
40 uint8_t pressure; //筆圧 (0 or 1)
41
42 double dx,dy, //イメージ位置
43 len, //次の点との長さ
44 a,b,c,
45 wx,wy;
46 }_point;
47
48 //----------------------
49
50 typedef struct
51 {
52 mMemAuto mem; //ポイントバッファ (_point)
53 int num, //ポイント数
54 cur; //現在の取得ポイント番号
55 }SplineBuf;
56
57 static SplineBuf g_dat;
58
59 //----------------------
60
61 #define _GETLASTPT(p) (((_point *)p->mem.buf) + p->num - 1)
62 #define _GETTOP(p) ((_point *)p->mem.buf)
63
64 //----------------------
65
66
67
68 /** 初期化 */
69
SplineBuf_init()70 void SplineBuf_init()
71 {
72 mMemzero(&g_dat, sizeof(SplineBuf));
73 }
74
75 /** 解放 */
76
SplineBuf_free()77 void SplineBuf_free()
78 {
79 mMemAutoFree(&g_dat.mem);
80 }
81
82
83 /** 操作開始時 */
84
SplineBuf_start()85 mBool SplineBuf_start()
86 {
87 g_dat.num = 0;
88
89 //確保
90
91 return mMemAutoAlloc(&g_dat.mem, sizeof(_point) * 20, sizeof(_point) * 20);
92 }
93
94 /** ポイント追加
95 *
96 * @param pressure 0 or 1 */
97
SplineBuf_addPoint(mPoint * pt,uint8_t pressure)98 mBool SplineBuf_addPoint(mPoint *pt,uint8_t pressure)
99 {
100 SplineBuf *p = &g_dat;
101 _point *buf,dat;
102
103 if(p->num >= 100) return FALSE;
104
105 //前回の位置と同じ
106
107 if(p->num)
108 {
109 buf = _GETLASTPT(p);
110
111 if(pt->x == buf->x && pt->y == buf->y)
112 return FALSE;
113 }
114
115 //追加
116
117 dat.x = pt->x;
118 dat.y = pt->y;
119 dat.pressure = pressure;
120
121 if(!mMemAutoAppend(&p->mem, &dat, sizeof(_point)))
122 return FALSE;
123
124 p->num++;
125
126 return TRUE;
127 }
128
129 /** 最後の点を削除して一つ戻す
130 *
131 * @param ptlast 削除後の最後の点が入る
132 * @param 点が一つだった場合 TRUE */
133
SplineBuf_deleteLastPoint(mPoint * ptlast)134 mBool SplineBuf_deleteLastPoint(mPoint *ptlast)
135 {
136 if(g_dat.num == 1)
137 return TRUE;
138 else
139 {
140 SplineBuf *p = &g_dat;
141 _point *buf;
142
143 mMemAutoBack(&p->mem, sizeof(_point));
144 p->num--;
145
146 //最後の点取得
147
148 buf = _GETLASTPT(p);
149
150 ptlast->x = buf->x;
151 ptlast->y = buf->y;
152
153 return FALSE;
154 }
155 }
156
157 /** すべてのポイントの座標をスクロール */
158
SplineBuf_scrollPoint(mPoint * pt)159 void SplineBuf_scrollPoint(mPoint *pt)
160 {
161 _point *buf;
162 int i,xx,yy;
163
164 buf = (_point *)g_dat.mem.buf;
165
166 xx = -(pt->x);
167 yy = -(pt->y);
168
169 for(i = g_dat.num; i > 0; i--, buf++)
170 {
171 buf->x += xx;
172 buf->y += yy;
173 }
174 }
175
176 /** ポイント取得開始 (再描画用) */
177
SplineBuf_beginGetPoint()178 void SplineBuf_beginGetPoint()
179 {
180 g_dat.cur = 0;
181 }
182
183 /** ポイント取得
184 *
185 * @return [0]終了 [1]点あり [2]点あり(筆圧0) */
186
SplineBuf_getPoint(mPoint * pt)187 int SplineBuf_getPoint(mPoint *pt)
188 {
189 SplineBuf *p = &g_dat;
190 _point *buf;
191
192 if(p->cur >= p->num) return 0;
193
194 buf = _GETTOP(p) + p->cur;
195
196 pt->x = buf->x;
197 pt->y = buf->y;
198
199 p->cur++;
200
201 return (buf->pressure == 0)? 2: 1;
202 }
203
204
205 /** 描画用、初期化 */
206
SplineBuf_initDraw()207 mBool SplineBuf_initDraw()
208 {
209 SplineBuf *p = &g_dat;
210 _point *topbuf,*endbuf,*buf;
211 int i;
212 double a,b,aa,bb;
213
214 if(p->num < 2) return FALSE;
215
216 topbuf = _GETTOP(p);
217 endbuf = topbuf + p->num - 1;
218
219 //キャンバス座標 -> イメージ座標に変換
220
221 for(i = p->num, buf = topbuf; i; i--, buf++)
222 drawCalc_areaToimage_double(APP_DRAW, &buf->dx, &buf->dy, buf->x, buf->y);
223
224 //長さ
225
226 for(i = p->num - 1, buf = topbuf; i; i--, buf++)
227 {
228 a = buf->dx - buf[1].dx;
229 b = buf->dy - buf[1].dy;
230
231 buf->len = sqrt(a * a + b * b);
232 }
233
234 //パラメータ
235
236 topbuf->a = 0, topbuf->b = 1, topbuf->c = 0.5;
237 topbuf->wx = (3 / (2 * topbuf->len)) * (topbuf[1].dx - topbuf->dx);
238 topbuf->wy = (3 / (2 * topbuf->len)) * (topbuf[1].dy - topbuf->dy);
239
240 endbuf->a = 1, endbuf->b = 2, endbuf->c = 0;
241 endbuf->wx = (3 / endbuf[-1].len) * (endbuf->dx - endbuf[-1].dx);
242 endbuf->wy = (3 / endbuf[-1].len) * (endbuf->dy - endbuf[-1].dy);
243
244 for(i = p->num - 2, buf = topbuf + 1; i; i--, buf++)
245 {
246 a = buf[-1].len;
247 b = buf->len;
248
249 buf->a = b;
250 buf->b = 2 * (a + b);
251 buf->c = a;
252
253 aa = 3 * a * a;
254 bb = 3 * b * b;
255
256 buf->wx = (aa * (buf[1].dx - buf->dx) + bb * (buf->dx - buf[-1].dx)) / (a * b);
257 buf->wy = (aa * (buf[1].dy - buf->dy) + bb * (buf->dy - buf[-1].dy)) / (a * b);
258 }
259
260 for(i = p->num - 1, buf = topbuf + 1; i; i--, buf++)
261 {
262 a = buf[-1].b / buf->a;
263
264 buf->b = buf->b * a - buf[-1].c;
265 buf->c *= a;
266
267 buf->wx = buf->wx * a - buf[-1].wx;
268 buf->wy = buf->wy * a - buf[-1].wy;
269
270 b = 1.0 / buf->b;
271
272 buf->c *= b;
273 buf->wx *= b;
274 buf->wy *= b;
275 buf->b = 1;
276 }
277
278 for(i = p->num - 1, buf = endbuf - 1; i; i--, buf--)
279 {
280 buf->wx -= buf->c * buf[1].wx;
281 buf->wy -= buf->c * buf[1].wy;
282 }
283
284 //
285
286 p->cur = 0;
287
288 return TRUE;
289 }
290
291 /** 次の描画用パラメータ取得
292 *
293 * @return FALSE で終了 */
294
SplineBuf_getNextDraw(mDoublePoint * pt,uint8_t * pressure)295 mBool SplineBuf_getNextDraw(mDoublePoint *pt,uint8_t *pressure)
296 {
297 SplineBuf *p = &g_dat;
298 _point *buf;
299 double xx,yy,a,aa,aaa;
300
301 if(p->cur >= p->num - 1) return FALSE;
302
303 buf = (_point *)p->mem.buf + p->cur;
304
305 xx = buf[1].dx - buf->dx;
306 yy = buf[1].dy - buf->dy;
307
308 a = buf->len;
309 aa = a * a;
310 aaa = -2 / (a * aa);
311
312 //
313
314 pt->x = buf->dx;
315 pt->y = buf->dy;
316
317 pt[1].x = buf->wx;
318 pt[1].y = buf->wy;
319
320 pt[2].x = xx * 3 / aa - (buf[1].wx + 2 * buf->wx) / a;
321 pt[2].y = yy * 3 / aa - (buf[1].wy + 2 * buf->wy) / a;
322
323 pt[3].x = xx * aaa + (buf[1].wx + buf->wx) / aa;
324 pt[3].y = yy * aaa + (buf[1].wy + buf->wy) / aa;
325
326 pt[4].x = buf->len;
327
328 pressure[0] = buf->pressure;
329 pressure[1] = buf[1].pressure;
330
331 p->cur++;
332
333 return TRUE;
334 }
335