1 /*
2 * FIG : Facility for Interactive Generation of figures
3 * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4 * Parts Copyright (c) 1989-2007 by Brian V. Smith
5 * Parts Copyright (c) 1991 by Paul King
6 *
7 * Any party obtaining a copy of these files is granted, free of charge, a
8 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9 * nonexclusive right and license to deal in this software and documentation
10 * files (the "Software"), including without limitation the rights to use,
11 * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
12 * the Software, and to permit persons who receive copies from any such
13 * party to do so, with the only requirement being that the above copyright
14 * and this permission notice remain intact.
15 *
16 */
17
18 #include "e_rotate.h"
19
20 #include <stddef.h>
21 #include <math.h>
22
23 #include "resources.h"
24 #include "mode.h"
25 #include "object.h"
26 #include "paintop.h"
27 #include "d_text.h"
28 #include "e_flip.h"
29 #include "u_bound.h"
30 #include "u_draw.h"
31 #include "u_geom.h"
32 #include "u_create.h"
33 #include "u_list.h"
34 #include "u_markers.h"
35 #include "u_redraw.h"
36 #include "u_search.h"
37 #include "w_canvas.h"
38 #include "w_cursor.h"
39 #include "w_mousefun.h"
40 #include "w_msgpanel.h"
41 #include "xfig_math.h"
42
43
44 /* EXPORTS */
45
46 int setcenter;
47 int setcenter_x;
48 int setcenter_y;
49 int rotn_dirn;
50 float act_rotnangle;
51
52 /* LOCAL */
53
54 static int copy;
55
56 static void init_rotate(F_line *p, int type, int x, int y, int px, int py);
57 static void set_unset_center(int x, int y);
58 static void init_copynrotate(F_line *p, int type, int x,int y,int px,int py);
59 static void rotate_selected(void);
60 static void rotate_search(F_line *p, int type, int x, int y, int px, int py);
61 static void init_rotateline(F_line *l, int px, int py);
62 static void init_rotatetext(F_text *t, int px, int py);
63 static void init_rotatearc (F_arc *a, int px, int py);
64 static void init_rotateellipse (F_ellipse *e, int px, int py);
65 static void init_rotatespline (F_spline *s, int px, int py);
66 static void init_rotatecompound (F_compound *c, int px, int py);
67 static void rotate_text (F_text *t, int x, int y);
68 static void rotate_ellipse (F_ellipse *e, int x, int y);
69 static void rotate_arc (F_arc *a, int x, int y);
70 static void rotate_spline (F_spline *s, int x, int y);
71 static int valid_rot_angle (F_compound *c);
72 static void rotate_point (F_point *p, int x, int y);
73 static void rotate_xy (int *orig_x, int *orig_y, int x, int y);
74
75
76 void
rotate_cw_selected(void)77 rotate_cw_selected(void)
78 {
79 rotn_dirn = 1;
80 /* erase any existing center */
81 if (setcenter)
82 center_marker(setcenter_x, setcenter_y);
83 /* and any anchor */
84 if (setanchor)
85 center_marker(setanchor_x, setanchor_y);
86 setcenter = 0;
87 setanchor = 0;
88 rotate_selected();
89 }
90
91 void
rotate_ccw_selected(void)92 rotate_ccw_selected(void)
93 {
94 rotn_dirn = -1;
95 /* erase any existing center */
96 if (setcenter)
97 center_marker(setcenter_x, setcenter_y);
98 /* and any anchor */
99 if (setanchor)
100 center_marker(setanchor_x, setanchor_y);
101 setcenter = 0;
102 setanchor = 0;
103 rotate_selected();
104 }
105
106 static void
rotate_selected(void)107 rotate_selected(void)
108 {
109 set_mousefun("rotate object", "copy & rotate", "set center",
110 LOC_OBJ, LOC_OBJ, "set center");
111 canvas_kbd_proc = null_proc;
112 canvas_locmove_proc = null_proc;
113 canvas_ref_proc = null_proc;
114 init_searchproc_left(init_rotate);
115 init_searchproc_middle(init_copynrotate);
116 canvas_leftbut_proc = object_search_left;
117 canvas_middlebut_proc = object_search_middle;
118 canvas_rightbut_proc = set_unset_center;
119 set_cursor(pick15_cursor);
120 reset_action_on();
121 }
122
123 static void
set_unset_center(int x,int y)124 set_unset_center(int x, int y)
125 {
126 if (setcenter) {
127 set_mousefun("rotate object", "copy & rotate", "set center",
128 LOC_OBJ, LOC_OBJ, "set center");
129 draw_mousefun_canvas();
130 setcenter = 0;
131 center_marker(setcenter_x,setcenter_y);
132 /* second call to center_mark on same position deletes */
133 }
134 else {
135 set_mousefun("rotate object", "copy & rotate", "unset center",
136 LOC_OBJ, LOC_OBJ, "unset center");
137 draw_mousefun_canvas();
138 setcenter = 1;
139 setcenter_x = x;
140 setcenter_y = y;
141 center_marker(setcenter_x,setcenter_y);
142 }
143
144 }
145
146 static void
init_rotate(F_line * p,int type,int x,int y,int px,int py)147 init_rotate(F_line *p, int type, int x, int y, int px, int py)
148 {
149 copy = 0;
150 act_rotnangle = cur_rotnangle;
151 if (setcenter)
152 rotate_search(p, type, x, y,setcenter_x,setcenter_y );
153 /* remember rotation center, e.g for multiple rotation*/
154 else
155 rotate_search(p, type, x, y, px, py);
156 }
157
158 static void
init_copynrotate(F_line * p,int type,int x,int y,int px,int py)159 init_copynrotate(F_line *p, int type, int x, int y, int px, int py)
160 {
161 int i;
162
163 copy = 1;
164 act_rotnangle = cur_rotnangle;
165 for ( i = 1; i <= cur_numcopies; act_rotnangle += cur_rotnangle, i++) {
166 if (setcenter)
167 rotate_search(p, type, x, y,setcenter_x,setcenter_y );
168 /* remember rotation center */
169 else
170 rotate_search(p, type, x, y, px, py);
171 }
172 }
173
174 static void
rotate_search(F_line * p,int type,int x,int y,int px,int py)175 rotate_search(F_line *p, int type, int x, int y, int px, int py)
176 {
177 (void)x;
178 (void)y;
179
180 switch (type) {
181 case O_POLYLINE:
182 cur_l = (F_line *) p;
183 init_rotateline(cur_l, px, py);
184 break;
185 case O_ARC:
186 cur_a = (F_arc *) p;
187 init_rotatearc(cur_a, px, py);
188 break;
189 case O_ELLIPSE:
190 cur_e = (F_ellipse *) p;
191 init_rotateellipse(cur_e, px, py);
192 break;
193 case O_SPLINE:
194 cur_s = (F_spline *) p;
195 init_rotatespline(cur_s, px, py);
196 break;
197 case O_TXT:
198 cur_t = (F_text *) p;
199 init_rotatetext(cur_t, px, py);
200 break;
201 case O_COMPOUND:
202 cur_c = (F_compound *) p;
203 init_rotatecompound(cur_c, px, py);
204 break;
205 default:
206 return;
207 }
208 }
209
210 static void
init_rotateline(F_line * l,int px,int py)211 init_rotateline(F_line *l, int px, int py)
212 {
213 F_line *line;
214
215 set_temp_cursor(wait_cursor);
216 line = copy_line(l);
217 rotate_line(line, px, py);
218 if (copy) {
219 add_line(line);
220 } else {
221 toggle_linemarker(l);
222 draw_line(l, ERASE);
223 change_line(l, line);
224 }
225 /* redisplay objects under this object before it was rotated */
226 redisplay_line(l);
227 /* and this line and any other objects on top */
228 redisplay_line(line);
229 reset_cursor();
230 }
231
232 static void
init_rotatetext(F_text * t,int px,int py)233 init_rotatetext(F_text *t, int px, int py)
234 {
235 F_text *text;
236
237 set_temp_cursor(wait_cursor);
238 text = copy_text(t);
239 rotate_text(text, px, py);
240 if (copy) {
241 add_text(text);
242 } else {
243 toggle_textmarker(t);
244 draw_text(t, ERASE);
245 change_text(t, text);
246 }
247 /* redisplay objects under this object before it was rotated */
248 redisplay_text(t);
249 /* and this text and any other objects on top */
250 redisplay_text(text);
251 reset_cursor();
252 }
253
init_rotateellipse(F_ellipse * e,int px,int py)254 void init_rotateellipse(F_ellipse *e, int px, int py)
255 {
256 F_ellipse *ellipse;
257
258 set_temp_cursor(wait_cursor);
259 ellipse = copy_ellipse(e);
260 rotate_ellipse(ellipse, px, py);
261 if (copy) {
262 add_ellipse(ellipse);
263 } else {
264 toggle_ellipsemarker(e);
265 draw_ellipse(e, ERASE);
266 change_ellipse(e, ellipse);
267 }
268 /* redisplay objects under this object before it was rotated */
269 redisplay_ellipse(e);
270 /* and this ellipse and any other objects on top */
271 redisplay_ellipse(ellipse);
272 reset_cursor();
273 }
274
init_rotatearc(F_arc * a,int px,int py)275 void init_rotatearc(F_arc *a, int px, int py)
276 {
277 F_arc *arc;
278
279 set_temp_cursor(wait_cursor);
280 arc = copy_arc(a);
281 rotate_arc(arc, px, py);
282 if (copy) {
283 add_arc(arc);
284 } else {
285 toggle_arcmarker(a);
286 draw_arc(a, ERASE);
287 change_arc(a, arc);
288 }
289 /* redisplay objects under this object before it was rotated */
290 redisplay_arc(a);
291 /* and this arc and any other objects on top */
292 redisplay_arc(arc);
293 reset_cursor();
294 }
295
init_rotatespline(F_spline * s,int px,int py)296 void init_rotatespline(F_spline *s, int px, int py)
297 {
298 F_spline *spline;
299
300 set_temp_cursor(wait_cursor);
301 spline = copy_spline(s);
302 rotate_spline(spline, px, py);
303 if (copy) {
304 add_spline(spline);
305 } else {
306 toggle_splinemarker(s);
307 draw_spline(s, ERASE);
308 change_spline(s, spline);
309 }
310 /* redisplay objects under this object before it was rotated */
311 redisplay_spline(s);
312 /* and this spline and any other objects on top */
313 redisplay_spline(spline);
314 reset_cursor();
315 }
316
init_rotatecompound(F_compound * c,int px,int py)317 void init_rotatecompound(F_compound *c, int px, int py)
318 {
319 F_compound *compound;
320
321 if (!valid_rot_angle(c)) {
322 put_msg("Invalid rotation angle for this compound object");
323 return;
324 }
325 set_temp_cursor(wait_cursor);
326 compound = copy_compound(c);
327 rotate_compound(compound, px, py);
328 if (copy) {
329 add_compound(compound);
330 } else {
331 toggle_compoundmarker(c);
332 draw_compoundelements(c, ERASE);
333 change_compound(c, compound);
334 }
335 /* redisplay objects under this object before it was rotated */
336 redisplay_compound(c);
337 /* and this compound and any other objects on top */
338 redisplay_compound(compound);
339 reset_cursor();
340 }
341
342 void
rotate_line(F_line * l,int x,int y)343 rotate_line(F_line *l, int x, int y)
344 {
345 F_point *p;
346 int dx;
347
348 /* for speed we treat 90 degrees as a special case */
349 if (act_rotnangle == 90.0) {
350 for (p = l->points; p != NULL; p = p->next) {
351 dx = p->x - x;
352 p->x = x + rotn_dirn * (y - p->y);
353 p->y = y + rotn_dirn * dx;
354 }
355 } else {
356 for (p = l->points; p != NULL; p = p->next)
357 rotate_point(p, x, y);
358 }
359
360 }
361
rotate_figure(F_compound * f,int x,int y)362 void rotate_figure(F_compound *f, int x, int y)
363 {
364 float old_rotn_dirn, old_act_rotnangle;
365
366 old_rotn_dirn = rotn_dirn;
367 old_act_rotnangle = act_rotnangle;
368 rotn_dirn = -1;
369 act_rotnangle = 90.0;
370 rotate_compound(f,x,y);
371 rotn_dirn = old_rotn_dirn;
372 act_rotnangle = old_act_rotnangle;
373 }
374
rotate_spline(F_spline * s,int x,int y)375 void rotate_spline(F_spline *s, int x, int y)
376 {
377 F_point *p;
378 int dx;
379
380 /* for speed we treat 90 degrees as a special case */
381 if (act_rotnangle == 90.0) {
382 for (p = s->points; p != NULL; p = p->next) {
383 dx = p->x - x;
384 p->x = x + rotn_dirn * (y - p->y);
385 p->y = y + rotn_dirn * dx;
386 }
387 } else {
388 for (p = s->points; p != NULL; p = p->next)
389 rotate_point(p, x, y);
390 }
391 }
392
rotate_text(F_text * t,int x,int y)393 void rotate_text(F_text *t, int x, int y)
394 {
395 int dx;
396
397 if (act_rotnangle == 90.0) { /* treat 90 degs as special case for speed */
398 dx = t->base_x - x;
399 t->base_x = x + rotn_dirn * (y - t->base_y);
400 t->base_y = y + rotn_dirn * dx;
401 } else {
402 rotate_xy(&t->base_x, &t->base_y, x, y);
403 }
404 t->angle -= (float) (rotn_dirn * act_rotnangle * M_PI / 180.0);
405 if (t->angle < 0.0)
406 t->angle += M_2PI;
407 else if (t->angle >= M_2PI - 0.001)
408 t->angle -= M_2PI;
409 reload_text_fstruct(t);
410 }
411
rotate_ellipse(F_ellipse * e,int x,int y)412 void rotate_ellipse(F_ellipse *e, int x, int y)
413 {
414 int dxc,dxs,dxe;
415
416 if (act_rotnangle == 90.0) { /* treat 90 degs as special case for speed */
417 dxc = e->center.x - x;
418 dxs = e->start.x - x;
419 dxe = e->end.x - x;
420 e->center.x = x + rotn_dirn * (y - e->center.y);
421 e->center.y = y + rotn_dirn * dxc;
422 e->start.x = x + rotn_dirn * (y - e->start.y);
423 e->start.y = y + rotn_dirn * dxs;
424 e->end.x = x + rotn_dirn * (y - e->end.y);
425 e->end.y = y + rotn_dirn * dxe;
426 } else {
427 rotate_point((F_point *)&e->center, x, y);
428 rotate_point((F_point *)&e->start, x, y);
429 rotate_point((F_point *)&e->end, x, y);
430 }
431 e->angle -= (float) (rotn_dirn * act_rotnangle * M_PI / 180.0);
432 if (e->angle < 0.0)
433 e->angle += M_2PI;
434 else if (e->angle >= M_2PI - 0.001)
435 e->angle -= M_2PI;
436 }
437
rotate_arc(F_arc * a,int x,int y)438 void rotate_arc(F_arc *a, int x, int y)
439 {
440 int dx;
441 F_pos p[3];
442 float xx, yy;
443
444 /* for speed we treat 90 degrees as a special case */
445 if (act_rotnangle == 90.0) {
446 dx = a->center.x - x;
447 a->center.x = x + rotn_dirn * (y - a->center.y);
448 a->center.y = y + rotn_dirn * dx;
449 dx = a->point[0].x - x;
450 a->point[0].x = x + rotn_dirn * (y - a->point[0].y);
451 a->point[0].y = y + rotn_dirn * dx;
452 dx = a->point[1].x - x;
453 a->point[1].x = x + rotn_dirn * (y - a->point[1].y);
454 a->point[1].y = y + rotn_dirn * dx;
455 dx = a->point[2].x - x;
456 a->point[2].x = x + rotn_dirn * (y - a->point[2].y);
457 a->point[2].y = y + rotn_dirn * dx;
458 } else {
459 p[0] = a->point[0];
460 p[1] = a->point[1];
461 p[2] = a->point[2];
462 rotate_point((F_point *)&p[0], x, y);
463 rotate_point((F_point *)&p[1], x, y);
464 rotate_point((F_point *)&p[2], x, y);
465 if (compute_arccenter(p[0], p[1], p[2], &xx, &yy)) {
466 a->point[0].x = p[0].x;
467 a->point[0].y = p[0].y;
468 a->point[1].x = p[1].x;
469 a->point[1].y = p[1].y;
470 a->point[2].x = p[2].x;
471 a->point[2].y = p[2].y;
472 a->center.x = xx;
473 a->center.y = yy;
474 a->direction = compute_direction(p[0], p[1], p[2]);
475 }
476 }
477 }
478
479 /* checks to see if the objects within c can be rotated by act_rotnangle */
480
481 int
valid_rot_angle(F_compound * c)482 valid_rot_angle(F_compound *c)
483 {
484 F_line *l;
485 F_compound *c1;
486
487 if (fabs(act_rotnangle) == 90.0 || fabs(act_rotnangle) == 180.0)
488 return 1; /* always valid */
489 for (l = c->lines; l != NULL; l = l->next)
490 if (l->type == T_ARCBOX || l->type == T_BOX)
491 return 0;
492 for (c1 = c->compounds; c1 != NULL; c1 = c1->next)
493 if (!valid_rot_angle(c1))
494 return 0;
495 return 1;
496 }
497
498 void
rotate_compound(F_compound * c,int x,int y)499 rotate_compound(F_compound *c, int x, int y)
500 {
501 F_line *l;
502 F_arc *a;
503 F_ellipse *e;
504 F_spline *s;
505 F_text *t;
506 F_compound *c1;
507
508 for (l = c->lines; l != NULL; l = l->next)
509 rotate_line(l, x, y);
510 for (a = c->arcs; a != NULL; a = a->next)
511 rotate_arc(a, x, y);
512 for (e = c->ellipses; e != NULL; e = e->next)
513 rotate_ellipse(e, x, y);
514 for (s = c->splines; s != NULL; s = s->next)
515 rotate_spline(s, x, y);
516 for (t = c->texts; t != NULL; t = t->next)
517 rotate_text(t, x, y);
518 for (c1 = c->compounds; c1 != NULL; c1 = c1->next)
519 rotate_compound(c1, x, y);
520
521 /*
522 * Make the bounding box exactly match the dimensions of the compound.
523 */
524 compound_bound(c, &c->nwcorner.x, &c->nwcorner.y,
525 &c->secorner.x, &c->secorner.y);
526 }
527
rotate_point(F_point * p,int x,int y)528 void rotate_point(F_point *p, int x, int y)
529 {
530 /* rotate point p about coordinate (x, y) */
531 double dx, dy;
532 double cosa, sina, mag, theta;
533
534 dx = p->x - x;
535 dy = y - p->y;
536 if (dx == 0 && dy == 0)
537 return;
538
539 theta = compute_angle(dx, dy);
540 theta -= (double) (rotn_dirn * act_rotnangle * M_PI / 180.0);
541 if (theta < 0.0)
542 theta += M_2PI;
543 else if (theta >= M_2PI - 0.001)
544 theta -= M_2PI;
545 mag = sqrt(dx * dx + dy * dy);
546 cosa = mag * cos(theta);
547 sina = mag * sin(theta);
548 p->x = round(x + cosa);
549 p->y = round(y - sina);
550 }
551
rotate_xy(int * orig_x,int * orig_y,int x,int y)552 void rotate_xy(int *orig_x, int *orig_y, int x, int y)
553 {
554 /* rotate coord (orig_x, orig_y) about coordinate (x, y) */
555 double dx, dy;
556 double cosa, sina, mag, theta;
557
558 dx = *orig_x - x;
559 dy = y - *orig_y;
560 if (dx == 0 && dy == 0)
561 return;
562
563 theta = compute_angle(dx, dy);
564 theta -= (double) (rotn_dirn * act_rotnangle * M_PI / 180.0);
565 if (theta < 0.0)
566 theta += M_2PI;
567 else if (theta >= M_2PI - 0.001)
568 theta -= M_2PI;
569 mag = sqrt(dx * dx + dy * dy);
570 cosa = mag * cos(theta);
571 sina = mag * sin(theta);
572 *orig_x = round(x + cosa);
573 *orig_y = round(y - sina);
574 }
575