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