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 "fig.h"
19 #include "resources.h"
20 #include "mode.h"
21 #include "object.h"
22 #include "paintop.h"
23 #include "u_elastic.h"
24 #include "u_geom.h"
25 #include "w_canvas.h"
26 #include "w_drawprim.h"
27 #include "w_setup.h"
28 #include "w_zoom.h"
29 #include "d_arc.h"
30 
31 #include "u_draw.h"
32 #include "w_cursor.h"
33 #include "w_msgpanel.h"
34 
35 /********************** EXPORTS **************/
36 
37 int		constrained;
38 int		work_numsides;
39 float		cur_angle;
40 int		x1off, x2off, y1off, y2off;
41 Cursor		cur_latexcursor;
42 int		from_x, from_y;
43 double		cosa, sina;
44 intptr_t	movedpoint_num;
45 F_point	       *left_point, *right_point;
46 
47 /**************** LOCAL ***********/
48 
49 static void	elastic_links(int dx, int dy, float sx, float sy);
50 static void	angle0_line(int x, int y);
51 static void	angle45_line(int x, int y);
52 static void	angle90_line(int x, int y);
53 static void	angle135_line(int x, int y);
54 
55 /*************************** BOXES *************************/
56 
57 
58 
59 void
elastic_box(int x1,int y1,int x2,int y2)60 elastic_box(int x1, int y1, int x2, int y2)
61 {
62     int		    wid, ht;
63 
64     set_line_stuff(1, RUBBER_LINE, 0.0, JOIN_MITER, CAP_BUTT,
65 		INV_PAINT, DEFAULT);
66     wid = abs(x2-x1)+1;
67     ht = abs(y2-y1)+1;
68     zXDrawRectangle(tool_d, canvas_win, gccache[INV_PAINT],min2(x1,x2),min2(y1,y2),wid,ht);
69 }
70 
71 void
elastic_fixedbox(void)72 elastic_fixedbox(void)
73 {
74     elastic_box(fix_x, fix_y, cur_x, cur_y);
75 }
76 
77 void
elastic_movebox(void)78 elastic_movebox(void)
79 {
80     register int    x1, y1, x2, y2;
81 
82     x1 = cur_x + x1off;
83     x2 = cur_x + x2off;
84     y1 = cur_y + y1off;
85     y2 = cur_y + y2off;
86     elastic_box(x1, y1, x2, y2);
87     elastic_links(cur_x - fix_x, cur_y - fix_y, 1.0, 1.0);
88 }
89 
90 void
moving_box(int x,int y)91 moving_box(int x, int y)
92 {
93     elastic_movebox();
94     adjust_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
95     length_msg(MSG_DIST);
96     elastic_movebox();
97 }
98 
99 void
resizing_box(int x,int y)100 resizing_box(int x, int y)
101 {
102     elastic_fixedbox();
103     cur_x = x;
104     cur_y = y;
105     boxsize_msg(1);
106     elastic_fixedbox();
107 }
108 
109 void
constrained_resizing_box(int x,int y)110 constrained_resizing_box(int x, int y)
111 {
112     elastic_fixedbox();
113     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
114     boxsize_msg(1);
115     elastic_fixedbox();
116 }
117 
118 void
constrained_resizing_scale_box(int x,int y)119 constrained_resizing_scale_box(int x, int y)
120 {
121     elastic_fixedbox();
122     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
123     elastic_fixedbox();
124     boxsize_scale_msg(1);
125 }
126 
127 void
scaling_compound(int x,int y)128 scaling_compound(int x, int y)
129 {
130     elastic_scalecompound(cur_c);
131     adjust_box_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
132     elastic_scalecompound(cur_c);
133 }
134 
135 void
elastic_scale_curcompound(void)136 elastic_scale_curcompound(void)
137 {
138     elastic_scalecompound(cur_c);
139 }
140 
141 void
elastic_scalecompound(F_compound * c)142 elastic_scalecompound(F_compound *c)
143 {
144     double	    newx, newy, oldx, oldy;
145     double	    newd, oldd, scalefact;
146     int		    x1, y1, x2, y2;
147 
148     newx = cur_x - fix_x;
149     newy = cur_y - fix_y;
150     newd = sqrt(newx * newx + newy * newy);
151     oldx = from_x - fix_x;
152     oldy = from_y - fix_y;
153     oldd = sqrt(oldx * oldx + oldy * oldy);
154     scalefact = newd / oldd;
155     x1 = fix_x + round((c->secorner.x - fix_x) * scalefact);
156     y1 = fix_y + round((c->secorner.y - fix_y) * scalefact);
157     x2 = fix_x + round((c->nwcorner.x - fix_x) * scalefact);
158     y2 = fix_y + round((c->nwcorner.y - fix_y) * scalefact);
159     boxsize_scale_msg(2);
160     elastic_box(x1, y1, x2, y2);
161 }
162 
163 /*************************** LINES *************************/
164 
165 /* refresh a line segment */
166 
167 void
elastic_line(void)168 elastic_line(void)
169 {
170     pw_vector(canvas_win, fix_x, fix_y, cur_x, cur_y,
171 	      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
172     /* erase endpoint because next seg will redraw it */
173     pw_vector(canvas_win, cur_x, cur_y, cur_x, cur_y,
174 	      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
175 }
176 
177 /* this is only called by  get_intermediatepoint() for drawing lines and by
178    the canvas_locmove_proc for drawing arcs */
179 
180 void
unconstrained_line(int x,int y)181 unconstrained_line(int x, int y)
182 {
183     elastic_line();
184     cur_x = x;
185     cur_y = y;
186     length_msg(MSG_PNTS_LENGTH);
187     elastic_line();
188 }
189 
190 void
latex_line(int x,int y)191 latex_line(int x, int y)
192 {
193     Cursor c;
194 
195     elastic_line();
196     latex_endpoint(fix_x, fix_y, x, y, &cur_x, &cur_y, latexarrow_mode,
197 		(cur_pointposn == P_ANY) ? 1 : max2(1, point_spacing()));
198     length_msg(MSG_LENGTH);
199     elastic_line();
200     c = (x == cur_x && y == cur_y) ? null_cursor : crosshair_cursor;
201     if (c != cur_cursor) {
202 	set_temp_cursor(c);
203 	cur_cursor = c;
204     }
205 }
206 
207 void
constrainedangle_line(int x,int y)208 constrainedangle_line(int x, int y)
209 {
210     double	    angle, dx, dy;
211 
212     if (x == cur_x && y == cur_y)
213 	return;
214 
215     dx = x - fix_x;
216     dy = fix_y - y;
217     /* only move if the pointer has moved at least 2 pixels */
218     if (sqrt(dx * dx + dy * dy) < 2.0)
219 	return;
220     if (dx == 0)
221 	angle = -90.0;
222     else
223 	angle = 180.0 * atan(dy / dx) / M_PI;
224 
225     elastic_line();
226     if (manhattan_mode) {
227 	if (mountain_mode) {
228 	    if (angle < -67.5)
229 		angle90_line(x, y);
230 	    else if (angle < -22.5)
231 		angle135_line(x, y);
232 	    else if (angle < 22.5)
233 		angle0_line(x, y);
234 	    else if (angle < 67.5)
235 		angle45_line(x, y);
236 	    else
237 		angle90_line(x, y);
238 	} else {
239 	    if (angle < -45.0)
240 		angle90_line(x, y);
241 	    else if (angle < 45.0)
242 		angle0_line(x, y);
243 	    else
244 		angle90_line(x, y);
245 	}
246     } else {
247 	if (angle < 0.0)
248 	    angle135_line(x, y);
249 	else
250 	    angle45_line(x, y);
251     }
252     length_msg(MSG_LENGTH);
253     elastic_line();
254 }
255 
256 static void
angle0_line(int x,int y)257 angle0_line(int x, int y)
258 {
259     cur_x = x;
260     cur_y = fix_y;
261 }
262 
263 static void
angle90_line(int x,int y)264 angle90_line(int x, int y)
265 {
266     cur_y = y;
267     cur_x = fix_x;
268 }
269 
270 static void
angle45_line(int x,int y)271 angle45_line(int x, int y)
272 {
273     if (abs(x - fix_x) < abs(y - fix_y)) {
274 	cur_x = fix_x - y + fix_y;
275 	cur_y = y;
276     } else {
277 	cur_y = fix_y + fix_x - x;
278 	cur_x = x;
279     }
280 }
281 
282 static void
angle135_line(int x,int y)283 angle135_line(int x, int y)
284 {
285     if (abs(x - fix_x) < abs(y - fix_y)) {
286 	cur_x = fix_x + y - fix_y;
287 	cur_y = y;
288     } else {
289 	cur_y = fix_y + x - fix_x;
290 	cur_x = x;
291     }
292 }
293 
294 void
reshaping_line(int x,int y)295 reshaping_line(int x, int y)
296 {
297     elastic_linelink();
298     adjust_pos(x, y, from_x, from_y, &cur_x, &cur_y);
299     /* one or two lines moving with the move point? */
300     if (left_point != NULL && right_point != NULL) {
301 	length_msg2(left_point->x,left_point->y,
302 		    right_point->x,right_point->y,cur_x,cur_y);
303     } else if (left_point != NULL) {
304 	altlength_msg(MSG_LENGTH,left_point->x,left_point->y);
305     } else if (right_point != NULL) {
306 	altlength_msg(MSG_LENGTH,right_point->x,right_point->y);
307     }
308     elastic_linelink();
309 }
310 
311 void
elastic_linelink(void)312 elastic_linelink(void)
313 {
314     if (left_point != NULL) {
315 	pw_vector(canvas_win, left_point->x, left_point->y,
316 	       cur_x, cur_y, INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
317     }
318     if (right_point != NULL) {
319 	pw_vector(canvas_win, right_point->x, right_point->y,
320 	       cur_x, cur_y, INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
321     }
322 }
323 
324 void
moving_line(int x,int y)325 moving_line(int x, int y)
326 {
327     elastic_moveline(new_l->points);
328     adjust_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
329     length_msg(MSG_DIST);
330     elastic_moveline(new_l->points);
331 }
332 
333 void
elastic_movenewline(void)334 elastic_movenewline(void)
335 {
336     elastic_moveline(new_l->points);
337 }
338 
339 void
elastic_moveline(F_point * pts)340 elastic_moveline(F_point *pts)
341 {
342     F_point	   *p;
343     int		    dx, dy, x, y, xx, yy;
344 
345     p = pts;
346     if (p->next == NULL) {	/* dot */
347 	pw_vector(canvas_win, cur_x, cur_y, cur_x, cur_y,
348 		  INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
349     } else {
350 	dx = cur_x - fix_x;
351 	dy = cur_y - fix_y;
352 	x = p->x + dx;
353 	y = p->y + dy;
354 	for (p = p->next; p != NULL; x = xx, y = yy, p = p->next) {
355 	    xx = p->x + dx;
356 	    yy = p->y + dy;
357 	    pw_vector(canvas_win, x, y, xx, yy, INV_PAINT, 1,
358 		      RUBBER_LINE, 0.0, DEFAULT);
359 	    /* erase endpoint of last segment because next will redraw it */
360 	    if (p->next)
361 		pw_vector(canvas_win, xx, yy, xx, yy, INV_PAINT, 1,
362 		      RUBBER_LINE, 0.0, DEFAULT);
363 	}
364 	elastic_links(dx, dy, 1.0, 1.0);
365     }
366 }
367 
368 static void
elastic_links(int dx,int dy,float sx,float sy)369 elastic_links(int dx, int dy, float sx, float sy)
370 {
371     F_linkinfo	   *k;
372 
373     if (cur_linkmode == SMART_OFF)
374 	return;
375 
376     for (k = cur_links; k != NULL; k = k->next)
377 	if (k->prevpt == NULL) {/* dot */
378 	    pw_vector(canvas_win, k->endpt->x, k->endpt->y,
379 		      k->endpt->x, k->endpt->y,
380 		      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
381 	} else {
382 	    if (cur_linkmode == SMART_MOVE)
383 		pw_vector(canvas_win, k->endpt->x + dx, k->endpt->y + dy,
384 			  k->prevpt->x, k->prevpt->y,
385 			  INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
386 	    else if (cur_linkmode == SMART_SLIDE) {
387 		if (k->endpt->x == k->prevpt->x) {
388 		    if (!k->two_pts)
389 			pw_vector(canvas_win, k->prevpt->x,
390 			      k->prevpt->y, k->prevpt->x + dx, k->prevpt->y,
391 			     INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
392 		    pw_vector(canvas_win, k->endpt->x + dx,
393 			  k->endpt->y + dy, k->prevpt->x + dx, k->prevpt->y,
394 			      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
395 		} else {
396 		    if (!k->two_pts)
397 			pw_vector(canvas_win, k->prevpt->x,
398 			      k->prevpt->y, k->prevpt->x, k->prevpt->y + dy,
399 			     INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
400 		    pw_vector(canvas_win, k->endpt->x + dx,
401 			  k->endpt->y + dy, k->prevpt->x, k->prevpt->y + dy,
402 			      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
403 		}
404 	    }
405 	}
406 }
407 
408 void
scaling_line(int x,int y)409 scaling_line(int x, int y)
410 {
411     elastic_scalepts(cur_l->points);
412     adjust_box_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
413     if (cur_l->type == T_BOX || cur_l->type == T_ARCBOX || cur_l->type == T_PICTURE)
414 	boxsize_msg(2);
415     elastic_scalepts(cur_l->points);
416 }
417 
418 void
elastic_scale_curline(int x,int y)419 elastic_scale_curline(int x, int y)
420 {
421     elastic_scalepts(cur_l->points);
422 }
423 
424 void
scaling_spline(int x,int y)425 scaling_spline(int x, int y)
426 {
427     elastic_scalepts(cur_s->points);
428     adjust_box_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
429     elastic_scalepts(cur_s->points);
430 }
431 
432 void
elastic_scale_curspline(void)433 elastic_scale_curspline(void)
434 {
435     elastic_scalepts(cur_s->points);
436 }
437 
438 void
elastic_scalepts(F_point * pts)439 elastic_scalepts(F_point *pts)
440 {
441     F_point	   *p;
442     double	    newx, newy, oldx, oldy;
443     double	    newd, oldd, scalefact;
444     int		    ox, oy, xx, yy;
445 
446     p = pts;
447     newx = cur_x - fix_x;
448     newy = cur_y - fix_y;
449     newd = sqrt(newx * newx + newy * newy);
450 
451     oldx = from_x - fix_x;
452     oldy = from_y - fix_y;
453     oldd = sqrt(oldx * oldx + oldy * oldy);
454 
455     scalefact = newd / oldd;
456     ox = fix_x + round((p->x - fix_x) * scalefact);
457     oy = fix_y + round((p->y - fix_y) * scalefact);
458     for (p = p->next; p != NULL; ox = xx, oy = yy, p = p->next) {
459 	xx = fix_x + round((p->x - fix_x) * scalefact);
460 	yy = fix_y + round((p->y - fix_y) * scalefact);
461 	pw_vector(canvas_win, ox, oy, xx, yy, INV_PAINT, 1,
462 		  RUBBER_LINE, 0.0, DEFAULT);
463     }
464 }
465 
466 void
elastic_poly(int x1,int y1,int x2,int y2,int numsides)467 elastic_poly(int x1, int y1, int x2, int y2, int numsides)
468 {
469     register float  angle;
470     register int    nx, ny, i;
471     double	    dx, dy;
472     double	    init_angle, mag;
473     int		    ox, oy;
474 
475     dx = x2 - x1;
476     dy = y2 - y1;
477     mag = sqrt(dx * dx + dy * dy);
478     init_angle = compute_angle(dx, dy);
479     ox = x2;
480     oy = y2;
481 
482     /* now append numsides points */
483     for (i = 1; i < numsides; i++) {
484 	angle = (float)(init_angle - M_2PI * (double) i / (double) numsides);
485 	if (angle < 0)
486 	    angle += M_2PI;
487 	nx = x1 + round(mag * cos((double) angle));
488 	ny = y1 + round(mag * sin((double) angle));
489 	pw_vector(canvas_win, nx, ny, ox, oy, INV_PAINT, 1,
490 		  RUBBER_LINE, 0.0, DEFAULT);
491 	ox = nx;
492 	oy = ny;
493     }
494     pw_vector(canvas_win, ox, oy, x2, y2, INV_PAINT, 1,
495 	      RUBBER_LINE, 0.0, DEFAULT);
496 }
497 
498 void
resizing_poly(int x,int y)499 resizing_poly(int x, int y)
500 {
501     elastic_poly(fix_x, fix_y, cur_x, cur_y, work_numsides);
502     cur_x = x;
503     cur_y = y;
504     work_numsides = cur_numsides;
505     length_msg(MSG_LENGTH);
506     elastic_poly(fix_x, fix_y, cur_x, cur_y, work_numsides);
507 }
508 
509 /*********************** ELLIPSES *************************/
510 
511 void
elastic_ebr(void)512 elastic_ebr(void)
513 {
514     register int    x1, y1, x2, y2;
515     int		    rx, ry;
516 
517     rx = cur_x - fix_x;
518     ry = cur_y - fix_y;
519     if (cur_angle != 0.0) {
520 	angle_ellipse(fix_x, fix_y, rx, ry, cur_angle, INV_PAINT, MAX_DEPTH+1, 1,
521 	     RUBBER_LINE, 0.0, UNFILLED, DEFAULT, DEFAULT);
522     } else {
523 	x1 = fix_x + rx;
524 	x2 = fix_x - rx;
525 	y1 = fix_y + ry;
526 	y2 = fix_y - ry;
527 	pw_curve(canvas_win, x1, y1, x2, y2, INV_PAINT, MAX_DEPTH+1, 1,
528 	     RUBBER_LINE, 0.0, UNFILLED, DEFAULT, DEFAULT, CAP_BUTT);
529     }
530 }
531 
532 void
resizing_ebr(int x,int y)533 resizing_ebr(int x, int y)
534 {
535     elastic_ebr();
536     cur_x = x;
537     cur_y = y;
538     length_msg(MSG_RADIUS2);
539     elastic_ebr();
540 }
541 
542 void
constrained_resizing_ebr(int x,int y)543 constrained_resizing_ebr(int x, int y)
544 {
545     elastic_ebr();
546     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
547     length_msg(MSG_RADIUS2);
548     elastic_ebr();
549 }
550 
551 void
elastic_ebd(void)552 elastic_ebd(void)
553 {
554     int	    centx,centy;
555 
556     centx = (fix_x+cur_x)/2;
557     centy = (fix_y+cur_y)/2;
558     length_msg(MSG_DIAM);
559     if (cur_angle != 0.0) {
560 	angle_ellipse(centx, centy, abs(cur_x-fix_x)/2,
561 		  abs(cur_y-fix_y)/2, cur_angle,
562 		  INV_PAINT, MAX_DEPTH+1, 1, RUBBER_LINE, 0.0, UNFILLED,
563 		  DEFAULT, DEFAULT);
564     } else {
565 	pw_curve(canvas_win, fix_x, fix_y, cur_x, cur_y, INV_PAINT, MAX_DEPTH+1, 1,
566 			RUBBER_LINE, 0.0, UNFILLED, DEFAULT, DEFAULT, CAP_BUTT);
567     }
568 }
569 
570 void
resizing_ebd(int x,int y)571 resizing_ebd(int x, int y)
572 {
573     elastic_ebd();
574     cur_x = x;
575     cur_y = y;
576     length_msg(MSG_DIAM);
577     elastic_ebd();
578 }
579 
580 void
constrained_resizing_ebd(int x,int y)581 constrained_resizing_ebd(int x, int y)
582 {
583     elastic_ebd();
584     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
585     length_msg(MSG_DIAM);
586     elastic_ebd();
587 }
588 
589 void
elastic_cbr(void)590 elastic_cbr(void)
591 {
592     register int    radius, x1, y1, x2, y2;
593     double	    rx, ry;
594 
595     rx = cur_x - fix_x;
596     ry = cur_y - fix_y;
597     radius = round(sqrt(rx * rx + ry * ry));
598     x1 = fix_x + radius;
599     x2 = fix_x - radius;
600     y1 = fix_y + radius;
601     y2 = fix_y - radius;
602     pw_curve(canvas_win, x1, y1, x2, y2, INV_PAINT, MAX_DEPTH+1, 1,
603 	     RUBBER_LINE, 0.0, UNFILLED, DEFAULT, DEFAULT, CAP_BUTT);
604 }
605 
606 void
resizing_cbr(int x,int y)607 resizing_cbr(int x, int y)
608 {
609     elastic_cbr();
610     cur_x = x;
611     cur_y = y;
612     length_msg(MSG_RADIUS);
613     elastic_cbr();
614 }
615 
616 void
elastic_cbd(void)617 elastic_cbd(void)
618 {
619     register int    x1, y1, x2, y2;
620     int		    radius;
621     double	    rx, ry;
622 
623     rx = (cur_x - fix_x) / 2;
624     ry = (cur_y - fix_y) / 2;
625     radius = round(sqrt(rx * rx + ry * ry));
626     x1 = fix_x + rx + radius;
627     x2 = fix_x + rx - radius;
628     y1 = fix_y + ry + radius;
629     y2 = fix_y + ry - radius;
630     pw_curve(canvas_win, x1, y1, x2, y2, INV_PAINT, MAX_DEPTH+1, 1,
631 	     RUBBER_LINE, 0.0, UNFILLED, DEFAULT, DEFAULT, CAP_BUTT);
632 }
633 
634 void
resizing_cbd(int x,int y)635 resizing_cbd(int x, int y)
636 {
637     elastic_cbd();
638     cur_x = x;
639     cur_y = y;
640     length_msg(MSG_DIAM);
641     elastic_cbd();
642 }
643 
644 void
constrained_resizing_cbd(int x,int y)645 constrained_resizing_cbd(int x, int y)
646 {
647     elastic_cbd();
648     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
649     length_msg(MSG_DIAM);
650     elastic_cbd();
651 }
652 
653 void
elastic_moveellipse(void)654 elastic_moveellipse(void)
655 {
656     register int    x1, y1, x2, y2;
657 
658     x1 = cur_x + x1off;
659     x2 = cur_x + x2off;
660     y1 = cur_y + y1off;
661     y2 = cur_y + y2off;
662     if (cur_angle != 0.0) {
663 	angle_ellipse((x1+x2)/2, (y1+y2)/2, abs(x1-x2)/2, abs(y1-y2)/2, cur_angle,
664 		  INV_PAINT, MAX_DEPTH+1, 1, RUBBER_LINE, 0.0, UNFILLED,
665 		  DEFAULT, DEFAULT);
666     } else {
667 	pw_curve(canvas_win, x1, y1, x2, y2, INV_PAINT, MAX_DEPTH+1, 1,
668 	     RUBBER_LINE, 0.0, UNFILLED, DEFAULT, DEFAULT, CAP_BUTT);
669     }
670 }
671 
672 void
moving_ellipse(int x,int y)673 moving_ellipse(int x, int y)
674 {
675     elastic_moveellipse();
676     adjust_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
677     length_msg(MSG_DIST);
678     elastic_moveellipse();
679 }
680 
681 void
elastic_scaleellipse(F_ellipse * e)682 elastic_scaleellipse(F_ellipse *e)
683 {
684     register int    x1, y1, x2, y2;
685     int		    rx, ry;
686     double	    newx, newy, oldx, oldy;
687     float	    newd, oldd, scalefact;
688 
689     newx = cur_x - fix_x;
690     newy = cur_y - fix_y;
691     newd = sqrt(newx * newx + newy * newy);
692 
693     oldx = from_x - fix_x;
694     oldy = from_y - fix_y;
695     oldd = sqrt(oldx * oldx + oldy * oldy);
696 
697     scalefact = newd / oldd;
698 
699     rx = round(e->radiuses.x * scalefact);
700     ry = round(e->radiuses.y * scalefact);
701     if (cur_angle != 0.0) {
702 	angle_ellipse(e->center.x, e->center.y, rx, ry, cur_angle,
703 		  INV_PAINT, MAX_DEPTH+1, 1, RUBBER_LINE, 0.0, UNFILLED,
704 		  DEFAULT, DEFAULT);
705     } else {
706 	x1 = fix_x + rx;
707 	x2 = fix_x - rx;
708 	y1 = fix_y + ry;
709 	y2 = fix_y - ry;
710 	pw_curve(canvas_win, x1, y1, x2, y2, INV_PAINT, MAX_DEPTH+1, 1,
711 	     RUBBER_LINE, 0.0, UNFILLED, DEFAULT, DEFAULT, CAP_BUTT);
712     }
713 }
714 
715 void
scaling_ellipse(int x,int y)716 scaling_ellipse(int x, int y)
717 {
718     elastic_scaleellipse(cur_e);
719     adjust_box_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
720     if (cur_e->type == T_ELLIPSE_BY_RAD)
721 	length_msg(MSG_RADIUS2);
722     else if (cur_e->type == T_CIRCLE_BY_RAD)
723 	length_msg(MSG_RADIUS);
724     else
725 	length_msg(MSG_DIAM);
726     elastic_scaleellipse(cur_e);
727 }
728 
729 void
elastic_scale_curellipse(void)730 elastic_scale_curellipse(void)
731 {
732     elastic_scaleellipse(cur_e);
733 }
734 
735 /*************************** ARCS *************************/
736 
737 void
arc_point(int x,int y,int numpoint)738 arc_point(int x, int y, int numpoint)
739 {
740     elastic_line();
741     cur_x = x;
742     cur_y = y;
743     altlength_msg(MSG_RADIUS_ANGLE, center_point.x, center_point.y);
744     elastic_line();
745 }
746 
747 void
reshaping_arc(int x,int y)748 reshaping_arc(int x, int y)
749 {
750     elastic_arclink();
751     adjust_pos(x, y, cur_a->point[movedpoint_num].x,
752 	       cur_a->point[movedpoint_num].y, &cur_x, &cur_y);
753     if (movedpoint_num == 1) {
754 	/* middle point */
755         arc_msg(cur_a->point[0].x, cur_a->point[0].y,
756 		 cur_a->point[2].x, cur_a->point[2].y,
757 		 cur_x, cur_y);
758     } else {
759 	/* end point */
760 	altlength_msg(MSG_LENGTH,cur_a->point[1].x,cur_a->point[1].y);
761     }
762     elastic_arclink();
763 }
764 
765 void
elastic_arclink(void)766 elastic_arclink(void)
767 {
768     switch (movedpoint_num) {
769     case 0:
770 	pw_vector(canvas_win, cur_x, cur_y,
771 		  cur_a->point[1].x, cur_a->point[1].y,
772 		  INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
773 	break;
774     case 1:
775 	pw_vector(canvas_win, cur_a->point[0].x, cur_a->point[0].y,
776 		  cur_x, cur_y, INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
777 	pw_vector(canvas_win, cur_a->point[2].x, cur_a->point[2].y,
778 		  cur_x, cur_y, INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
779 	break;
780     default:
781 	pw_vector(canvas_win, cur_a->point[1].x, cur_a->point[1].y,
782 		  cur_x, cur_y, INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
783     }
784 }
785 
786 void
moving_arc(int x,int y)787 moving_arc(int x, int y)
788 {
789     elastic_movearc(new_a);
790     adjust_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
791     length_msg(MSG_DIST);
792     elastic_movearc(new_a);
793 }
794 
795 void
elastic_movenewarc(void)796 elastic_movenewarc(void)
797 {
798     elastic_movearc(new_a);
799 }
800 
801 void
elastic_movearc(F_arc * a)802 elastic_movearc(F_arc *a)
803 {
804     int		    dx, dy;
805 
806     dx = cur_x - fix_x;
807     dy = cur_y - fix_y;
808     pw_vector(canvas_win, a->point[0].x + dx, a->point[0].y + dy,
809 	      a->point[1].x + dx, a->point[1].y + dy,
810 	      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
811     pw_vector(canvas_win, a->point[1].x + dx, a->point[1].y + dy,
812 	      a->point[2].x + dx, a->point[2].y + dy,
813 	      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
814 }
815 
816 void
scaling_arc(int x,int y)817 scaling_arc(int x, int y)
818 {
819     elastic_scalearc(cur_a);
820     adjust_box_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
821     elastic_scalearc(cur_a);
822 }
823 
824 void
elastic_scale_curarc(void)825 elastic_scale_curarc(void)
826 {
827     elastic_scalearc(cur_a);
828 }
829 
830 void
elastic_scalearc(F_arc * a)831 elastic_scalearc(F_arc *a)
832 {
833     double	    newx, newy, oldx, oldy;
834     double	    newd, oldd, scalefact;
835     F_pos	    p0, p1, p2;
836 
837     newx = cur_x - fix_x;
838     newy = cur_y - fix_y;
839     newd = sqrt(newx * newx + newy * newy);
840 
841     oldx = from_x - fix_x;
842     oldy = from_y - fix_y;
843     oldd = sqrt(oldx * oldx + oldy * oldy);
844 
845     scalefact = newd / oldd;
846 
847     p0 = a->point[0];
848     p1 = a->point[1];
849     p2 = a->point[2];
850     p0.x = fix_x + round((p0.x - fix_x) * scalefact);
851     p0.y = fix_y + round((p0.y - fix_y) * scalefact);
852     p1.x = fix_x + round((p1.x - fix_x) * scalefact);
853     p1.y = fix_y + round((p1.y - fix_y) * scalefact);
854     p2.x = fix_x + round((p2.x - fix_x) * scalefact);
855     p2.y = fix_y + round((p2.y - fix_y) * scalefact);
856 
857     length_msg2(p0.x, p0.y, p2.x, p2.y, p1.x, p1.y);
858     pw_vector(canvas_win, p0.x, p0.y, p1.x, p1.y,
859 	      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
860     pw_vector(canvas_win, p1.x, p1.y, p2.x, p2.y,
861 	      INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
862 }
863 
864 /*************************** TEXT *************************/
865 
866 void
moving_text(int x,int y)867 moving_text(int x, int y)
868 {
869     elastic_movetext();
870     adjust_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
871     length_msg(MSG_DIST);
872     elastic_movetext();
873 }
874 
875 /* use x1off, y1off so that the beginning of the text isn't
876    shifted under the cursor */
877 
878 void
elastic_movetext(void)879 elastic_movetext(void)
880 {
881     pw_text(canvas_win, cur_x + x1off, cur_y + y1off, INV_PAINT, MAX_DEPTH+1,
882 	    new_t->fontstruct, new_t->angle,
883 	    new_t->cstring, new_t->color, COLOR_NONE);
884 }
885 
886 
887 /*************************** SPLINES *************************/
888 
889 void
moving_spline(int x,int y)890 moving_spline(int x, int y)
891 {
892     elastic_moveline(new_s->points);
893     adjust_pos(x, y, fix_x, fix_y, &cur_x, &cur_y);
894     length_msg(MSG_DIST);
895     elastic_moveline(new_s->points);
896 }
897 
898 void
elastic_movenewspline(void)899 elastic_movenewspline(void)
900 {
901     elastic_moveline(new_s->points);
902 }
903 
904 /*********** AUXILIARY FUNCTIONS FOR CONSTRAINED MOVES ******************/
905 
906 void
adjust_box_pos(int curs_x,int curs_y,int orig_x,int orig_y,int * ret_x,int * ret_y)907 adjust_box_pos(int curs_x, int curs_y, int orig_x, int orig_y, int *ret_x, int *ret_y)
908 {
909     int		    xx, sgn_csr2fix_x, yy, sgn_csr2fix_y;
910     double	    mag_csr2fix_x, mag_csr2fix_y;
911 
912     switch (constrained) {
913     case MOVE_ARB:
914 	*ret_x = curs_x;
915 	*ret_y = curs_y;
916 	break;
917     case BOX_HSTRETCH:
918 	*ret_x = curs_x;
919 	*ret_y = orig_y;
920 	break;
921     case BOX_VSTRETCH:
922 	*ret_x = orig_x;
923 	*ret_y = curs_y;
924 	break;
925     default:
926 	/* calculate where scaled and stretched box corners would be */
927 	xx = curs_x - fix_x;
928 	sgn_csr2fix_x = signof(xx);
929 	mag_csr2fix_x = (double) abs(xx);
930 
931 	yy = curs_y - fix_y;
932 	sgn_csr2fix_y = signof(yy);
933 	mag_csr2fix_y = (double) abs(yy);
934 
935 	if (mag_csr2fix_x * sina > mag_csr2fix_y * cosa) {	/* above diagonal */
936 	    *ret_x = curs_x;
937 	    if (constrained == BOX_SCALE) {
938 		if (cosa == 0.0) {
939 		    *ret_y = fix_y + sgn_csr2fix_y * (int) (mag_csr2fix_x);
940 		} else {
941 		    *ret_y = fix_y + sgn_csr2fix_y * (int) (mag_csr2fix_x * sina / cosa);
942 		}
943 	    } else {
944 		    *ret_y = fix_y + sgn_csr2fix_y * abs(fix_y - orig_y);
945 		 }
946 	} else {
947 	    *ret_y = curs_y;
948 	    if (constrained == BOX_SCALE) {
949 		if (sina == 0.0) {
950 		    *ret_x = fix_x + sgn_csr2fix_x * (int) (mag_csr2fix_y);
951 		} else {
952 		    *ret_x = fix_x + sgn_csr2fix_x * (int) (mag_csr2fix_y * cosa / sina);
953 		}
954 	    } else {
955 		*ret_x = fix_x + sgn_csr2fix_x * abs(fix_x - orig_x);
956 	    }
957 	}
958     } /* switch */
959 }
960 
961 void
adjust_pos(int curs_x,int curs_y,int orig_x,int orig_y,int * ret_x,int * ret_y)962 adjust_pos(int curs_x, int curs_y, int orig_x, int orig_y, int *ret_x, int *ret_y)
963 {
964     if (constrained) {
965 	if (abs(orig_x - curs_x) > abs(orig_y - curs_y)) {
966 	    *ret_x = curs_x;
967 	    *ret_y = orig_y;
968 	} else {
969 	    *ret_x = orig_x;
970 	    *ret_y = curs_y;
971 	}
972     } else {
973 	*ret_x = curs_x;
974 	*ret_y = curs_y;
975     }
976 }
977