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