1 /*$
2  Copyright (C) 2016-2020 Azel.
3 
4  This file is part of AzPainterB.
5 
6  AzPainterB 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  AzPainterB 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  * DrawData
22  *
23  * 定規関連
24  *****************************************/
25 /*
26  * - 角度などのパラメータは、すべてイメージに対する値
27  */
28 
29 #include <math.h>
30 
31 #include "mDef.h"
32 
33 #include "defDraw.h"
34 
35 #include "draw_calc.h"
36 #include "draw_rule.h"
37 #include "draw_op_def.h"
38 #include "draw_op_sub.h"
39 #include "draw_op_func.h"
40 
41 
42 
43 //==================================
44 // sub
45 //==================================
46 
47 
48 /** 角度 rd の cos,sin 値を dtmp[0,1] にセット */
49 
_set_tmp_sincos(DrawData * p,double rd)50 static void _set_tmp_sincos(DrawData *p,double rd)
51 {
52 	p->rule.dtmp[0] = cos(rd);
53 	p->rule.dtmp[1] = sin(rd);
54 }
55 
56 /** mDoublePoint の位置を小数点切り捨て +0.5 にする */
57 
_set_doublepoint_dotmiddle(mDoublePoint * pt)58 static void _set_doublepoint_dotmiddle(mDoublePoint *pt)
59 {
60 	pt->x = floor(pt->x) + 0.5;
61 	pt->y = floor(pt->y) + 0.5;
62 }
63 
64 /** w.pttmp[0] の領域位置から、中心イメージ位置取得 */
65 
_get_imagepos_middle(DrawData * p,mDoublePoint * dst)66 static void _get_imagepos_middle(DrawData *p,mDoublePoint *dst)
67 {
68 	drawCalc_areaToimage_double(p,
69 		&dst->x, &dst->y, p->w.pttmp[0].x, p->w.pttmp[0].y);
70 
71 	_set_doublepoint_dotmiddle(dst);
72 }
73 
74 
75 
76 //==================================
77 // 補正位置取得関数
78 //==================================
79 
80 
81 /** 平行線/グリッド/集中線 */
82 
_getpoint_line(DrawData * p,double * px,double * py)83 static void _getpoint_line(DrawData *p,double *px,double *py)
84 {
85 	DrawRuleData *rule = &p->rule;
86 	double xx,yy,vi,len,dcos,dsin;
87 
88 	dcos = rule->dtmp[0];
89 	dsin = rule->dtmp[1];
90 
91 	xx = *px - rule->press_pos.x;
92 	yy = *py - rule->press_pos.y;
93 
94 	len = sqrt(xx * xx + yy * yy);
95 
96 	//ベクトルの内積 = cos の値
97 	/* (v1x * v2x + v1y * v2y) / (v1len * v2len)
98 	 * v2 は長さ 1 の指定角度の線とするので、v2x = cos, v2y = sin */
99 
100 	if(len == 0)
101 		vi = 0;
102 	else
103 		vi = (xx * dcos + yy * dsin) / len;
104 
105 	//グリッド時は、ある程度長さが出るまで角度を確定しない
106 
107 	if(rule->type == RULE_TYPE_GRID_LINE && !rule->ntmp)
108 	{
109 		if(len >= 3)
110 		{
111 			if(vi > -0.7 && vi < 0.7)
112 				_set_tmp_sincos(p, rule->grid_rd + M_MATH_PI / 2);
113 
114 			rule->ntmp = 1;
115 		}
116 
117 		*px = rule->press_pos.x;
118 		*py = rule->press_pos.y;
119 
120 		return;
121 	}
122 
123 	//内積が負なら 180 度反転
124 
125 	if(vi < 0) dcos = -dcos, dsin = -dsin;
126 
127 	*px = len * dcos + rule->press_pos.x;
128 	*py = len * dsin + rule->press_pos.y;
129 }
130 
131 /** 正円 */
132 
_getpoint_circle(DrawData * p,double * px,double * py)133 static void _getpoint_circle(DrawData *p,double *px,double *py)
134 {
135 	double rd;
136 
137 	rd = atan2(*py - p->rule.circle_pos.y, *px - p->rule.circle_pos.x);
138 
139 	*px = p->rule.dtmp[0] * cos(rd) + p->rule.circle_pos.x;
140 	*py = p->rule.dtmp[0] * sin(rd) + p->rule.circle_pos.y;
141 }
142 
143 /** 楕円 */
144 
_getpoint_ellipse(DrawData * p,double * px,double * py)145 static void _getpoint_ellipse(DrawData *p,double *px,double *py)
146 {
147 	DrawRuleData *rule = &p->rule;
148 	double xx,yy,x,y,rd;
149 
150 	//楕円を正円の状態に戻して、カーソル位置の角度取得
151 
152 	xx = *px - rule->ellipse_pos.x;
153 	yy = *py - rule->ellipse_pos.y;
154 
155 	x = (xx * rule->dtmp[0] - yy * rule->dtmp[1]) * rule->ellipse_yx;
156 	y = xx * rule->dtmp[1] + yy * rule->dtmp[0];
157 
158 	rd = atan2(y, x);
159 
160 	//求めた角度の位置を取得
161 
162 	xx = rule->dtmp[2] / rule->ellipse_yx * cos(rd);
163 	yy = rule->dtmp[2] * sin(rd);
164 
165 	x =  xx * rule->dtmp[0] + yy * rule->dtmp[1];
166 	y = -xx * rule->dtmp[1] + yy * rule->dtmp[0];
167 
168 	*px = x + rule->ellipse_pos.x;
169 	*py = y + rule->ellipse_pos.y;
170 }
171 
172 
173 
174 //==================================
175 // main
176 //==================================
177 
178 
179 /** 定規タイプ変更 */
180 
drawRule_setType(DrawData * p,int type)181 void drawRule_setType(DrawData *p,int type)
182 {
183 	void (*func_getpoint[])(DrawData *,double *,double *) = {
184 		NULL, _getpoint_line, _getpoint_line, _getpoint_line,
185 		_getpoint_circle, _getpoint_ellipse
186 	};
187 
188 	p->rule.type = type;
189 
190 	p->rule.funcGetPoint = func_getpoint[type];
191 }
192 
193 /** 自由線、ボタン押し時 */
194 
drawRule_onPress(DrawData * p,mBool dotpen)195 void drawRule_onPress(DrawData *p,mBool dotpen)
196 {
197 	DrawPoint dpt;
198 	double x,y,xx,yy;
199 
200 	//押し時のイメージ位置
201 
202 	drawOpSub_getDrawPoint(p, &dpt);
203 
204 	if(dotpen)
205 	{
206 		dpt.x = floor(dpt.x) + 0.5;
207 		dpt.y = floor(dpt.y) + 0.5;
208 	}
209 
210 	p->rule.press_pos.x = dpt.x;
211 	p->rule.press_pos.y = dpt.y;
212 
213 	//各タイプ
214 
215 	switch(p->rule.type)
216 	{
217 		//平行線
218 		case RULE_TYPE_PARALLEL_LINE:
219 			_set_tmp_sincos(p, p->rule.parallel_rd);
220 			break;
221 		//グリッド
222 		case RULE_TYPE_GRID_LINE:
223 			p->rule.ntmp = 0;
224 			_set_tmp_sincos(p, p->rule.grid_rd);
225 			break;
226 		//集中線
227 		case RULE_TYPE_CONC_LINE:
228 			_set_tmp_sincos(p,
229 				atan2(dpt.y - p->rule.conc_pos.y, dpt.x - p->rule.conc_pos.x));
230 			break;
231 		//正円 (dtmp[0] = 半径)
232 		case RULE_TYPE_CIRCLE:
233 			x = dpt.x - p->rule.circle_pos.x;
234 			y = dpt.y - p->rule.circle_pos.y;
235 
236 			p->rule.dtmp[0] = sqrt(x * x + y * y);
237 			break;
238 		//楕円 (dtmp[2] = 半径)
239 		case RULE_TYPE_ELLIPSE:
240 			_set_tmp_sincos(p, p->rule.ellipse_rd);
241 
242 			x = dpt.x - p->rule.ellipse_pos.x;
243 			y = dpt.y - p->rule.ellipse_pos.y;
244 
245 			xx = (x * p->rule.dtmp[0] - y * p->rule.dtmp[1]) * p->rule.ellipse_yx;
246 			yy = x * p->rule.dtmp[1] + y * p->rule.dtmp[0];
247 
248 			p->rule.dtmp[2] = sqrt(xx * xx + yy * yy);
249 			break;
250 	}
251 }
252 
253 
254 //==========================
255 // 定規設定
256 //==========================
257 
258 
259 /** +Ctrl での定規の設定開始時
260  *
261  * @return グラブするか */
262 
drawRule_onPress_setting(DrawData * p)263 mBool drawRule_onPress_setting(DrawData *p)
264 {
265 	switch(p->rule.type)
266 	{
267 		//集中線
268 		case RULE_TYPE_CONC_LINE:
269 			drawOpSub_getImagePoint_double(p, &p->rule.conc_pos);
270 			_set_doublepoint_dotmiddle(&p->rule.conc_pos);
271 
272 			return drawOpXor_rulepoint_press(p);
273 
274 		//同心円(正円)
275 		case RULE_TYPE_CIRCLE:
276 			drawOpSub_getImagePoint_double(p, &p->rule.circle_pos);
277 			_set_doublepoint_dotmiddle(&p->rule.circle_pos);
278 
279 			return drawOpXor_rulepoint_press(p);
280 
281 		//同心円(楕円)
282 		case RULE_TYPE_ELLIPSE:
283 			return drawOpXor_ellipse_press(p, DRAW_OPSUB_RULE_SETTING, FALSE);
284 
285 		//平行線、グリッド
286 		default:
287 			return drawOpXor_line_press(p, DRAW_OPSUB_RULE_SETTING, FALSE);
288 	}
289 }
290 
291 /** 定規設定 : 平行線、グリド */
292 
drawRule_setting_line(DrawData * p)293 void drawRule_setting_line(DrawData *p)
294 {
295 	double rd;
296 
297 	rd = drawCalc_getLineRadian_forImage(p);
298 
299 	switch(p->rule.type)
300 	{
301 		//平行線
302 		case RULE_TYPE_PARALLEL_LINE:
303 			p->rule.parallel_rd = rd;
304 			break;
305 		//グリッド
306 		case RULE_TYPE_GRID_LINE:
307 			p->rule.grid_rd = rd;
308 			break;
309 	}
310 }
311 
312 /** 定規設定 : 楕円 */
313 
drawRule_setting_ellipse(DrawData * p)314 void drawRule_setting_ellipse(DrawData *p)
315 {
316 	DrawRuleData *rule = &p->rule;
317 	double rx,ry;
318 
319 	//位置
320 
321 	_get_imagepos_middle(p, &rule->ellipse_pos);
322 
323 	//半径
324 
325 	rx = p->w.pttmp[1].x * p->viewparam.scalediv;
326 	ry = p->w.pttmp[1].y * p->viewparam.scalediv;
327 
328 	if(rx == 0) rx = 0.1;
329 	if(ry == 0) ry = 0.1;
330 
331 	//パラメータ
332 
333 	rule->ellipse_yx = ry / rx;
334 	rule->ellipse_rd = p->viewparam.rd;
335 
336 	//左右反転表示の場合、x を反転した角度
337 
338 	if(p->canvas_mirror)
339 	{
340 		rx = cos(p->viewparam.rd);
341 		ry = sin(p->viewparam.rd);
342 
343 		rule->ellipse_rd = atan2(ry, -rx);
344 	}
345 }
346 
347 
348 //==========================
349 // 記録
350 //==========================
351 
352 
353 /** 現在のデータを記録する */
354 
drawRule_setRecord(DrawData * p,int no)355 void drawRule_setRecord(DrawData *p,int no)
356 {
357 	RuleRecord *pd;
358 	DrawRuleData *rule = &p->rule;
359 
360 	pd = p->rule.record + no;
361 
362 	pd->type = rule->type;
363 
364 	switch(rule->type)
365 	{
366 		case RULE_TYPE_OFF:
367 			break;
368 		case RULE_TYPE_PARALLEL_LINE:
369 			pd->d[0] = rule->parallel_rd;
370 			break;
371 		case RULE_TYPE_GRID_LINE:
372 			pd->d[0] = rule->grid_rd;
373 			break;
374 		case RULE_TYPE_CONC_LINE:
375 			pd->d[0] = rule->conc_pos.x;
376 			pd->d[1] = rule->conc_pos.y;
377 			break;
378 		case RULE_TYPE_CIRCLE:
379 			pd->d[0] = rule->circle_pos.x;
380 			pd->d[1] = rule->circle_pos.y;
381 			break;
382 		case RULE_TYPE_ELLIPSE:
383 			pd->d[0] = rule->ellipse_pos.x;
384 			pd->d[1] = rule->ellipse_pos.y;
385 			pd->d[2] = rule->ellipse_yx;
386 			pd->d[3] = rule->ellipse_rd;
387 			break;
388 	}
389 }
390 
391 /** 記録データを呼び出し */
392 
drawRule_callRecord(DrawData * p,int no)393 void drawRule_callRecord(DrawData *p,int no)
394 {
395 	RuleRecord *ps;
396 	DrawRuleData *rule = &p->rule;
397 
398 	ps = p->rule.record + no;
399 
400 	switch(ps->type)
401 	{
402 		case RULE_TYPE_OFF:
403 			break;
404 		case RULE_TYPE_PARALLEL_LINE:
405 			rule->parallel_rd = ps->d[0];
406 			break;
407 		case RULE_TYPE_GRID_LINE:
408 			rule->grid_rd = ps->d[0];
409 			break;
410 		case RULE_TYPE_CONC_LINE:
411 			rule->conc_pos.x = ps->d[0];
412 			rule->conc_pos.y = ps->d[1];
413 			break;
414 		case RULE_TYPE_CIRCLE:
415 			rule->circle_pos.x = ps->d[0];
416 			rule->circle_pos.y = ps->d[1];
417 			break;
418 		case RULE_TYPE_ELLIPSE:
419 			rule->ellipse_pos.x = ps->d[0];
420 			rule->ellipse_pos.y = ps->d[1];
421 			rule->ellipse_yx = ps->d[2];
422 			rule->ellipse_rd = ps->d[3];
423 			break;
424 	}
425 
426 	drawRule_setType(p, ps->type);
427 }
428