1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/arc.c,v 1.9 2011/05/16 16:21:56 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_ARC_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "arc.e"
26 #include "attr.e"
27 #include "auxtext.e"
28 #include "choice.e"
29 #include "cmd.e"
30 #include "color.e"
31 #include "cursor.e"
32 #include "cutpaste.e"
33 #include "dialog.e"
34 #include "drawing.e"
35 #include "dup.e"
36 #include "file.e"
37 #include "grid.e"
38 #include "mainloop.e"
39 #include "mark.e"
40 #include "msg.e"
41 #include "obj.e"
42 #include "page.e"
43 #include "pattern.e"
44 #include "poly.e"
45 #include "ps.e"
46 #include "raster.e"
47 #include "rect.e"
48 #include "ruler.e"
49 #include "select.e"
50 #include "setup.e"
51 #include "special.e"
52 #include "spline.e"
53 #include "strtbl.e"
54 #include "util.e"
55 #include "xpixmap.e"
56 
57 #define EXPAND_BBOX(bbox,x,y) \
58    if ((x)<(bbox)->ltx) (bbox)->ltx=(x); if ((y)<(bbox)->lty) (bbox)->lty=(y); \
59    if ((x)>(bbox)->rbx) (bbox)->rbx=(x); if ((y)>(bbox)->rby) (bbox)->rby=(y)
60 
61 int	arcDrawn=FALSE;
62 
63 /*
64  * 0 degree is horizontal in the direction of the X axis.
65  * Positive angles measures counter-clockwise from 0 degree.
66  * Negative angles measures clockwise from 0 degree.
67  * Angle1 means the start angle.
68  * Angle2 means the amount between angle1 and the real angle2.
69  */
70 
71 static
ArcDirection(xc,yc,x1,y1,x2,y2)72 int ArcDirection(xc, yc, x1, y1, x2, y2)
73    int xc, yc, x1, y1, x2, y2;
74 {
75    register int dx, dy;
76    register double theta1, theta2;
77 
78    dx = x1-xc; dy = y1-yc;
79    theta1 = (dx==0) ? ((dy>=0) ? M_PI/2.0 : -M_PI/2.0) :
80          atan2 ((double)(dy), (double)(dx));
81    theta2 = (x2==xc) ? ((y2>=yc) ? M_PI/2.0 : -M_PI/2.0) :
82          atan2 ((double)(y2-yc), (double)(x2-xc));
83    if (theta1 < 0) theta1 += 2*M_PI;
84    if (theta2 < 0) theta2 += 2*M_PI;
85 
86    if (theta2 > theta1) {
87       if (theta2-theta1 >= 2*M_PI-theta2+theta1) {
88          return ARC_CCW;
89       } else {
90          return ARC_CW;
91       }
92    } else if (theta1 > theta2) {
93       if (theta1-theta2 >= 2*M_PI-theta1+theta2) {
94          return ARC_CW;
95       } else {
96          return ARC_CCW;
97       }
98    } else {
99       return ARC_CCW;
100    }
101 }
102 
PointsToArc(xc,yc,x1,y1,x2,y2,dir,int_degree,ltx,lty,w,h,angle1,angle2)103 void PointsToArc(xc, yc, x1, y1, x2, y2, dir, int_degree, ltx, lty, w, h,
104       angle1, angle2)
105    int xc, yc, x1, y1, x2, y2, dir, int_degree;
106    int *ltx, *lty, *w, *h, *angle1, *angle2;
107    /* Only good if the points are part of a circle, not an oval */
108 {
109    register int dx, dy, radius;
110    double tmp_theta;
111 
112    dx = x1-xc; dy = y1-yc;
113    radius = (int)sqrt((double)(((double)dx)*((double)dx) +
114          ((double)dy)*((double)dy)));
115    if (ltx != NULL) *ltx = xc-radius;
116    if (lty != NULL) *lty = yc-radius;
117    if (w != NULL) *w = (radius<<1);
118    if (h != NULL) *h = (radius<<1);
119    if (int_degree) {
120       int theta1, theta2, d_theta;
121 
122       tmp_theta = (dx==0) ? ((dy>=0) ? M_PI/2.0 : -M_PI/2.0) :
123             atan2 ((double)(dy),(double)(dx));
124       theta1 = (int)(tmp_theta/M_PI*(-180.0));
125       tmp_theta = (x2==xc) ? ((y2>=yc) ? M_PI/2.0 : -M_PI/2.0) :
126             atan2 ((double)(y2-yc),(double)(x2-xc));
127       theta2 = (int)(tmp_theta/M_PI*(-180.0));
128       /* NOTE:  *angle1 must be between -180 degrees and +180 degrees */
129       if (angle1 != NULL) *angle1 = theta1*64;
130       d_theta = theta2-theta1;
131       switch (dir) {
132       case ARC_CCW: if (d_theta < 0) d_theta = 360 + d_theta; break;
133       case ARC_CW:  if (d_theta > 0) d_theta = d_theta - 360; break;
134       }
135       if (d_theta == 0) d_theta = 360;
136       if (angle2 != NULL) *angle2 = (d_theta<<6);
137    } else {
138       double theta1, theta2, d_theta;
139 
140       tmp_theta = (dx==0) ? ((dy>=0) ? M_PI/2.0 : -M_PI/2.0) :
141             atan2 ((double)(dy),(double)(dx));
142       theta1 = tmp_theta/M_PI*(-180.0);
143       tmp_theta = (x2==xc) ? ((y2>=yc) ? M_PI/2.0 : -M_PI/2.0) :
144             atan2 ((double)(y2-yc),(double)(x2-xc));
145       theta2 = tmp_theta/M_PI*(-180.0);
146       /* NOTE:  *angle1 must be between -180 degrees and +180 degrees */
147       if (angle1 != NULL) *angle1 = (int)(theta1*64.0);
148       d_theta = theta2-theta1;
149       switch (dir) {
150       case ARC_CCW: if (d_theta < 0) d_theta = 360.0 + d_theta; break;
151       case ARC_CW:  if (d_theta > 0) d_theta = d_theta - 360.0; break;
152       }
153       if (fabs(d_theta) < INT_TOL) d_theta = (double)360.0;
154       if (angle2 != NULL) *angle2 = (int)(d_theta*64.0);
155    }
156 }
157 
ArcRealX2Y2(ArcPtr,RealX2,RealY2)158 void ArcRealX2Y2(ArcPtr, RealX2, RealY2)
159    register struct ArcRec *ArcPtr;
160    int *RealX2, *RealY2;
161 {
162    register double angle_in_radian;
163    int w=ArcPtr->w, h=ArcPtr->h;
164 
165    angle_in_radian = (ArcPtr->angle1+ArcPtr->angle2)*M_PI/180/64;
166    *RealX2 = ArcPtr->xc + round((w/2)*cos(angle_in_radian));
167    *RealY2 = ArcPtr->yc - round((h/2)*sin(angle_in_radian));
168 }
169 
170 static
GetRadianInArc(arc_ptr,x,y)171 double GetRadianInArc(arc_ptr, x, y)
172    struct ArcRec *arc_ptr;
173    int x, y; /* x and y are abs */
174 {
175    return ((double)atan2((double)((arc_ptr->yc-y)*arc_ptr->w),
176          (double)((x-arc_ptr->xc)*arc_ptr->h)));
177 }
178 
179 #define RETREAT (0.8)
180 
GetArcArrowInfo(obj_ptr,ptip_vs1,ptail_vs1,vs1,pa_angle1,ptip_vs2,ptail_vs2,vs2,pa_angle2)181 void GetArcArrowInfo(obj_ptr, ptip_vs1, ptail_vs1, vs1, pa_angle1,
182       ptip_vs2, ptail_vs2, vs2, pa_angle2)
183    struct ObjRec *obj_ptr;
184    IntPoint *ptip_vs1, *ptail_vs1, *vs1, *ptip_vs2, *ptail_vs2, *vs2;
185    int *pa_angle1, *pa_angle2;
186    /*
187     * if want to get a_angle1 and a_angle2, this function must be
188     * called in the following fashion (cannot omit the second call):
189     *
190     *     a_angle1 = arc_ptr->angle1;
191     *     a_angle2 = arc_ptr->angle2;
192     *     GetArcArrowInfo(*, *, *, *, &a_angle1, *, *, *, &a_angle2);
193     *     arc_ptr->a_angle1 = a_angle1;
194     *     arc_ptr->a_angle2 = a_angle2;
195     */
196 {
197    struct ArcRec *arc_ptr=obj_ptr->detail.a;
198    int style=arc_ptr->style, a_angle1, a_angle2, angle90, angle360;
199    int x1, y1, x2, y2, int_dx, int_dy, x, y, angle1, angle2, dir, w, h, aw, ah;
200    double dx, dy, angle_in_radian, theta1, theta2;
201    IntPoint tip_vs1, tail_vs1, tip_vs2, tail_vs2;
202 
203    if (style == LS_PLAIN) return;
204 
205    angle90 = (90<<6);
206    angle360 = (360<<6);
207    dir = arc_ptr->dir;
208    x1 = arc_ptr->x1; y1 = arc_ptr->y1;
209    angle1 = a_angle1 = arc_ptr->angle1; angle2 = a_angle2 = arc_ptr->angle2;
210    w = arc_ptr->w; h = arc_ptr->h;
211    aw = arc_ptr->aw; ah = arc_ptr->ah;
212 
213    /* the arrow should appear at angle1 */
214    theta1 = 0.0;
215    tip_vs1.x = x1;
216    tip_vs1.y = y1;
217    if ((style & LS_LEFT) && obj_ptr->ctm != NULL) {
218       TransformPointThroughCTM(x1-obj_ptr->x, y1-obj_ptr->y,
219             obj_ptr->ctm, &x, &y);
220       tip_vs1.x = x+obj_ptr->x;
221       tip_vs1.y = y+obj_ptr->y;
222    }
223    switch (dir) {
224    case ARC_CCW: theta1=(double)(angle1-(angle90)); break;
225    case ARC_CW: theta1=(double)(angle1+(angle90)); break;
226    }
227    dx = -((double)w)*cos(theta1*M_PI/180.0/64.0);
228    dy = ((double)h)*sin(theta1*M_PI/180.0/64.0);
229    int_dx = round(dx);
230    int_dy = round(dy);
231    tail_vs1.x = x1+int_dx;
232    tail_vs1.y = y1+int_dy;
233    if ((style & LS_LEFT) && obj_ptr->ctm != NULL) {
234       TransformPointThroughCTM(x1+int_dx-obj_ptr->x, y1+int_dy-obj_ptr->y,
235             obj_ptr->ctm, &x, &y);
236       tail_vs1.x = x+obj_ptr->x;
237       tail_vs1.y = y+obj_ptr->y;
238    }
239    if (int_dx==0 && int_dy==0) {
240       if ((style & LS_LEFT) && vs1 != NULL) {
241          if (obj_ptr->ctm == NULL) {
242             vs1[0].x = vs1[1].x = vs1[2].x = vs1[3].x = x1;
243             vs1[0].y = vs1[1].y = vs1[2].y = vs1[3].y = y1;
244          } else {
245             TransformPointThroughCTM(x1-obj_ptr->x, y1-obj_ptr->y,
246                   obj_ptr->ctm, &x, &y);
247             vs1[0].x = vs1[1].x = vs1[2].x = vs1[3].x = x+obj_ptr->x;
248             vs1[0].y = vs1[1].y = vs1[2].y = vs1[3].y = y+obj_ptr->y;
249          }
250       }
251    } else {
252       double sin_val, cos_val, len;
253 
254       dx = (double)(tail_vs1.x - tip_vs1.x);
255       dy = (double)(tail_vs1.y - tip_vs1.y);
256       len = (double)sqrt(dx*dx+dy*dy);
257       sin_val = dy/len;
258       cos_val = dx/len;
259       if ((style & LS_LEFT) && vs1 != NULL) {
260          vs1[0].x = tip_vs1.x;
261          vs1[0].y = tip_vs1.y;
262          vs1[1].x = round(tip_vs1.x + aw*cos_val - ah*sin_val);
263          vs1[1].y = round(tip_vs1.y + aw*sin_val + ah*cos_val);
264          vs1[2].x = round(tip_vs1.x + aw*cos_val + ah*sin_val);
265          vs1[2].y = round(tip_vs1.y + aw*sin_val - ah*cos_val);
266          vs1[3].x = vs1[0].x;
267          vs1[3].y = vs1[0].y;
268       }
269       if ((style & LS_LEFT) && (pa_angle1 != NULL || pa_angle2 != NULL)) {
270          x = round(tip_vs1.x + aw*cos_val*RETREAT);
271          y = round(tip_vs1.y + aw*sin_val*RETREAT);
272          if (obj_ptr->ctm == NULL) {
273             angle_in_radian = GetRadianInArc(arc_ptr, x, y);
274          } else {
275             int tmp_x, tmp_y;
276 
277             ReverseTransformPointThroughCTM(x-obj_ptr->x, y-obj_ptr->y,
278                   obj_ptr->ctm, &tmp_x, &tmp_y);
279             x = tmp_x+obj_ptr->x;
280             y = tmp_y+obj_ptr->y;
281             angle_in_radian = GetRadianInArc(arc_ptr, x, y);
282          }
283          angle_in_radian = angle_in_radian*180.0/M_PI*64.0;
284          a_angle1 = round(angle_in_radian);
285       }
286    }
287    theta2 = 0.0;
288    ArcRealX2Y2(arc_ptr, &x2, &y2);
289    tip_vs2.x = x2;
290    tip_vs2.y = y2;
291    if ((style & LS_RIGHT) && obj_ptr->ctm != NULL) {
292       TransformPointThroughCTM(x2-obj_ptr->x, y2-obj_ptr->y,
293             obj_ptr->ctm, &x, &y);
294       tip_vs2.x = x+obj_ptr->x;
295       tip_vs2.y = y+obj_ptr->y;
296    }
297    switch (dir) {
298    case ARC_CCW: theta2=(double)((angle1+angle2)+(angle90)); break;
299    case ARC_CW: theta2=(double)((angle1+angle2)-(angle90)); break;
300    }
301    dx = -((double)w)*cos(theta2*M_PI/180.0/64.0);
302    dy = ((double)h)*sin(theta2*M_PI/180.0/64.0);
303    int_dx = round(dx);
304    int_dy = round(dy);
305    tail_vs2.x = x2+int_dx;
306    tail_vs2.y = y2+int_dy;
307    if ((style & LS_RIGHT) && obj_ptr->ctm != NULL) {
308       TransformPointThroughCTM(x2+int_dx-obj_ptr->x, y2+int_dy-obj_ptr->y,
309             obj_ptr->ctm, &x, &y);
310       tail_vs2.x = x+obj_ptr->x;
311       tail_vs2.y = y+obj_ptr->y;
312    }
313    if (int_dx==0 && int_dy==0) {
314       if ((style & LS_RIGHT) && vs2 != NULL) {
315          if (obj_ptr->ctm == NULL) {
316             vs2[0].x = vs2[1].x = vs2[2].x = vs2[3].x = x2;
317             vs2[0].y = vs2[1].y = vs2[2].y = vs2[3].y = y2;
318          } else {
319             TransformPointThroughCTM(x2-obj_ptr->x, y2-obj_ptr->y,
320                   obj_ptr->ctm, &x, &y);
321             vs2[0].x = vs2[1].x = vs2[2].x = vs2[3].x = x+obj_ptr->x;
322             vs2[0].y = vs2[1].y = vs2[2].y = vs2[3].y = y+obj_ptr->y;
323          }
324       }
325    } else {
326       double sin_val, cos_val, len;
327 
328       dx = tail_vs2.x - tip_vs2.x;
329       dy = tail_vs2.y - tip_vs2.y;
330       len = (double)sqrt(dx*dx+dy*dy);
331       sin_val = dy/len;
332       cos_val = dx/len;
333       if ((style & LS_RIGHT) && vs2 != NULL) {
334          vs2[0].x = tip_vs2.x;
335          vs2[0].y = tip_vs2.y;
336          vs2[1].x = round(tip_vs2.x + aw*cos_val - ah*sin_val);
337          vs2[1].y = round(tip_vs2.y + aw*sin_val + ah*cos_val);
338          vs2[2].x = round(tip_vs2.x + aw*cos_val + ah*sin_val);
339          vs2[2].y = round(tip_vs2.y + aw*sin_val - ah*cos_val);
340          vs2[3].x = vs2[0].x;
341          vs2[3].y = vs2[0].y;
342       }
343       if (pa_angle1 != NULL || pa_angle2 != NULL) {
344          int delta64;
345 
346          if (style & LS_RIGHT) {
347             x = round(tip_vs2.x + aw*cos_val*RETREAT);
348             y = round(tip_vs2.y + aw*sin_val*RETREAT);
349             if (obj_ptr->ctm == NULL) {
350                angle_in_radian = GetRadianInArc(arc_ptr, x, y);
351             } else {
352                int tmp_x, tmp_y;
353 
354                ReverseTransformPointThroughCTM(x-obj_ptr->x, y-obj_ptr->y,
355                      obj_ptr->ctm, &tmp_x, &tmp_y);
356                x = tmp_x+obj_ptr->x;
357                y = tmp_y+obj_ptr->y;
358                angle_in_radian = GetRadianInArc(arc_ptr, x, y);
359             }
360             angle_in_radian = angle_in_radian*180.0/M_PI*64.0;
361          } else {
362             angle_in_radian = angle1+angle2;
363             while (angle_in_radian > angle360) angle_in_radian -= angle360;
364             while (angle_in_radian < (-angle360)) angle_in_radian += angle360;
365          }
366          delta64 = round(angle_in_radian)-(a_angle1);
367          switch(dir) {
368          case ARC_CCW: if (delta64 < 0) delta64 += (angle360); break;
369          case ARC_CW: if (delta64 > 0) delta64 -= (angle360); break;
370          }
371          while (delta64 > angle360) delta64 -= angle360;
372          while (delta64 < (-angle360)) delta64 += angle360;
373          if (delta64 == 0 && angle2 != 0) delta64 = (angle360);
374          a_angle2 = delta64;
375       }
376    }
377    if (pa_angle1 != NULL) *pa_angle1 = a_angle1;
378    if (pa_angle2 != NULL) *pa_angle2 = a_angle2;
379    if (ptip_vs1 != NULL) memcpy(ptip_vs1, &tip_vs1, sizeof(IntPoint));
380    if (ptail_vs1 != NULL) memcpy(ptail_vs1, &tail_vs1, sizeof(IntPoint));
381    if (ptip_vs2 != NULL) memcpy(ptip_vs2, &tip_vs2, sizeof(IntPoint));
382    if (ptail_vs2 != NULL) memcpy(ptail_vs2, &tail_vs2, sizeof(IntPoint));
383 }
384 
CalcArcOBBox(ObjPtr)385 void CalcArcOBBox(ObjPtr)
386    struct ObjRec *ObjPtr;
387 {
388    struct ArcRec *arc_ptr=ObjPtr->detail.a;
389 
390    if (ObjPtr->ctm == NULL) {
391       int theta1, theta2, real_x2, real_y2;
392       int dir=arc_ptr->dir, ltx=arc_ptr->ltx, lty=arc_ptr->lty;
393       int w=arc_ptr->w, h=arc_ptr->h, pass_theta1=FALSE, coverage=0, angle;
394       struct BBRec obbox;
395 
396       memcpy(&obbox, &ObjPtr->obbox, sizeof(struct BBRec));
397 
398       ObjPtr->x = arc_ptr->xc;
399       ObjPtr->y = arc_ptr->yc;
400 
401       theta1 = (arc_ptr->angle1)/64;
402       theta2 = theta1 + (arc_ptr->angle2)/64;
403 
404       ArcRealX2Y2(arc_ptr, &real_x2, &real_y2);
405 
406       if (arc_ptr->fill == NONEPAT) {
407          /* don't counter the center of the arc */
408          obbox.ltx = min(arc_ptr->x1,real_x2);
409          obbox.lty = min(arc_ptr->y1,real_y2);
410          obbox.rbx = max(arc_ptr->x1,real_x2);
411          obbox.rby = max(arc_ptr->y1,real_y2);
412       } else {
413          obbox.ltx = min(arc_ptr->xc,min(arc_ptr->x1,real_x2));
414          obbox.lty = min(arc_ptr->yc,min(arc_ptr->y1,real_y2));
415          obbox.rbx = max(arc_ptr->xc,max(arc_ptr->x1,real_x2));
416          obbox.rby = max(arc_ptr->yc,max(arc_ptr->y1,real_y2));
417       }
418 
419       if (theta2 < -180) theta2 += 360;
420       if (theta2 > 180) theta2 -= 360;
421 
422       if (theta1 < 0) theta1 += 360;
423       if (theta2 < 0) theta2 += 360;
424 
425       if (theta1 == theta2) {
426          coverage = 0xf;
427       } else if (dir == ARC_CCW) {
428          angle = 0;
429          while (angle < theta2 || !pass_theta1) {
430             if (angle >= theta1 && !pass_theta1) {
431                pass_theta1 = TRUE;
432                if (theta2 > theta1 && angle >= theta2) break;
433                if (theta2 < theta1) angle -= 360;
434             }
435             if (pass_theta1) coverage |= 1 << (((angle+360)/90) % 4);
436             angle = (angle == 360) ? 0 : (angle+90);
437          }
438       } else {
439          angle = 360;
440          while (angle > theta2 || !pass_theta1) {
441             if (angle <= theta1 && !pass_theta1) {
442                pass_theta1 = TRUE;
443                if (theta2 < theta1 && angle <= theta2) break;
444                if (theta2 > theta1) angle += 360;
445             }
446             if (pass_theta1) coverage |= 1 << ((angle/90) % 4);
447             angle = (angle == 0) ? 360 : (angle-90);
448          }
449       }
450       if (coverage & 0x1) { EXPAND_BBOX(&obbox,(int)(ltx+w),(int)(lty+h/2)); }
451       if (coverage & 0x2) { EXPAND_BBOX(&obbox,(int)(ltx+w/2),lty); }
452       if (coverage & 0x4) { EXPAND_BBOX(&obbox,ltx,(int)(lty+h/2)); }
453       if (coverage & 0x8) { EXPAND_BBOX(&obbox,(int)(ltx+w/2),(int)(lty+h)); }
454       memcpy(&ObjPtr->obbox, &obbox, sizeof(struct BBRec));
455    } else {
456       IntPoint abs_obj_obbox_vs[5];
457 
458       GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
459       ObjPtr->obbox.ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
460             min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
461       ObjPtr->obbox.rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
462             max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
463       ObjPtr->obbox.lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
464             min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
465       ObjPtr->obbox.rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
466             max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
467    }
468 }
469 
CalcArcBBox(obj_ptr,obbox,bbox)470 void CalcArcBBox(obj_ptr, obbox, bbox)
471    struct ObjRec *obj_ptr;
472    struct BBRec obbox, *bbox;
473    /* given good obbox, figure out bbox */
474 {
475    struct ArcRec *arc_ptr=obj_ptr->detail.a;
476    int i, half_w=(arc_ptr->width>>1);
477    int ltx=obbox.ltx-half_w, lty=obbox.lty-half_w;
478    int rbx=obbox.rbx+half_w, rby=obbox.rby+half_w;
479    IntPoint vs1[4], vs2[4];
480 
481    GetArcArrowInfo(obj_ptr, NULL, NULL, vs1, NULL, NULL, NULL, vs2, NULL);
482    if (arc_ptr->style & LS_LEFT) {
483       for (i=0; i < 4; i++) {
484          if (vs1[i].x < ltx) ltx = vs1[i].x;
485          if (vs1[i].y < lty) lty = vs1[i].y;
486          if (vs1[i].x > rbx) rbx = vs1[i].x;
487          if (vs1[i].y > rby) rby = vs1[i].y;
488       }
489    }
490    if (arc_ptr->style & LS_RIGHT) {
491       for (i=0; i < 4; i++) {
492          if (vs2[i].x < ltx) ltx = vs2[i].x;
493          if (vs2[i].y < lty) lty = vs2[i].y;
494          if (vs2[i].x > rbx) rbx = vs2[i].x;
495          if (vs2[i].y > rby) rby = vs2[i].y;
496       }
497    }
498    bbox->ltx = min(ltx, obbox.ltx-(arc_ptr->width>>1));
499    bbox->lty = min(lty, obbox.lty-(arc_ptr->width>>1));
500    bbox->rbx = max(rbx, obbox.rbx+(arc_ptr->width>>1));
501    bbox->rby = max(rby, obbox.rby+(arc_ptr->width>>1));
502 }
503 
504 static
DumpArcPSPath(FP,xc,yc,xr,yr,dir,a1,a2,outline,blank1,blank2)505 void DumpArcPSPath(FP, xc, yc, xr, yr, dir, a1, a2, outline, blank1, blank2)
506    FILE *FP;
507    int xc, yc, xr, yr, dir, a1, a2, outline;
508    char *blank1, *blank2;
509 {
510 #ifdef INVERT_CTM_BUG
511    if (preDumpSetup) PSUseMinRadius();
512 #endif /* INVERT_CTM_BUG */
513 
514    if (preDumpSetup) PSUseArc();
515    fprintf(FP, "%s%s\n", blank1, gPsCmd[PS_NEWPATH]);
516    if (outline) fprintf(FP, "%s%1d %1d %s\n", blank2, xc, yc,
517          gPsCmd[PS_MOVETO]);
518 #ifdef INVERT_CTM_BUG
519    switch (dir) {
520    case ARC_CCW:
521       fprintf(FP, "%s%1d %1d %1d %s %1d %s %1d %1d TGAR\n", blank2,
522             xc, yc, xr, "tgif_min_radius", yr, "tgif_min_radius", a1, a2);
523       break;
524    case ARC_CW:
525       fprintf(FP, "%s%1d %1d %1d %s %1d %s %1d %1d TGAN\n", blank2,
526             xc, yc, xr, "tgif_min_radius", yr, "tgif_min_radius", a1, a2);
527       break;
528    }
529 #else
530    switch (dir) {
531    case ARC_CCW:
532       fprintf(FP, "%s%1d %1d %1d %1d %1d %1d TGAR\n", blank2,
533             xc, yc, xr, yr, a1, a2);
534       break;
535    case ARC_CW:
536       fprintf(FP, "%s%1d %1d %1d %1d %1d %1d TGAN\n", blank2,
537             xc, yc, xr, yr, a1, a2);
538       break;
539    }
540 #endif
541    if (outline) {
542       fprintf(FP, "%s%1d %1d %s\n", blank2, xc, yc, gPsCmd[PS_LINETO]);
543    }
544 }
545 
546 static
DumpArcArrows(FP,obj_ptr)547 void DumpArcArrows(FP, obj_ptr)
548    FILE *FP;
549    struct ObjRec *obj_ptr;
550 {
551    struct ArcRec *arc_ptr=obj_ptr->detail.a;
552    int style=arc_ptr->style, aw=arc_ptr->aw, ah=arc_ptr->ah, pen=arc_ptr->pen;
553    int trans_pat=obj_ptr->trans_pat, color_index=obj_ptr->color;
554    IntPoint tip_vs1, tail_vs1, tip_vs2, tail_vs2;
555    char *aw_spec=arc_ptr->aw_spec, *ah_spec=arc_ptr->ah_spec;
556 
557    GetArcArrowInfo(obj_ptr, &tip_vs1, &tail_vs1, NULL, NULL,
558          &tip_vs2, &tail_vs2, NULL, NULL);
559    if (obj_ptr->ctm == NULL) {
560       if (style & LS_LEFT) {
561          DumpArrow(FP, &tail_vs1, &tip_vs1, aw, ah, aw_spec, ah_spec,
562                pen, trans_pat, color_index);
563       }
564       if (style & LS_RIGHT) {
565          DumpArrow(FP, &tail_vs2, &tip_vs2, aw, ah, aw_spec, ah_spec,
566                pen, trans_pat, color_index);
567       }
568    } else {
569       if (style & LS_LEFT) {
570          DumpArrow(FP, &tail_vs1, &tip_vs1, aw, ah, aw_spec, ah_spec,
571                pen, trans_pat, color_index);
572       }
573       if (style & LS_RIGHT) {
574          DumpArrow(FP, &tail_vs2, &tip_vs2, aw, ah, aw_spec, ah_spec,
575                pen, trans_pat, color_index);
576       }
577    }
578 }
579 
580 static
DumpArcPath(FP,ObjPtr,xc,yc,xr,yr,dir,angle1,angle2,width,pen,dash,trans_pat)581 void DumpArcPath(FP, ObjPtr, xc, yc, xr, yr, dir, angle1, angle2,
582       width, pen, dash, trans_pat)
583    FILE *FP;
584    struct ObjRec *ObjPtr;
585    int xc, yc, xr, yr, dir, angle1, angle2, width, pen, dash, trans_pat;
586 {
587    register int i;
588    int w_is_int=TRUE;
589    char *width_spec=ObjPtr->detail.a->width_spec;
590    double dw=GetWidthInDouble(width, width_spec, &w_is_int);
591 
592    fprintf(FP, "   %s\n", gPsCmd[PS_GSAVE]);
593    if (!colorDump && useGray && pen > BACKPAT) {
594       GrayCheck(pen);
595       fprintf(FP, "      %s %s\n", GrayStr(pen), gPsCmd[PS_SETGRAY]);
596    }
597 
598    DumpArcPSPath(FP,xc,yc,xr,yr,dir,angle1,angle2,FALSE,"      ","         ");
599 
600    if (ObjPtr->ctm != NULL) {
601       fprintf(FP, "      %s\n", &(gPsCmd[PS_TGIFSETMATRIX])[1]);
602    }
603    if (w_is_int) {
604       if (width != 1) {
605          fprintf(FP, "      %1d %s\n", width, gPsCmd[PS_SETLINEWIDTH]);
606       }
607    } else {
608       fprintf(FP, "      %.3f %s\n", dw, gPsCmd[PS_SETLINEWIDTH]);
609    }
610    if (dash != 0) {
611       fprintf(FP, "      [");
612       for (i = 0; i < dashListLength[dash]-1; i++) {
613          fprintf(FP, "%1d ", (int)(dashList[dash][i]));
614       }
615       fprintf(FP, "%1d] 0 %s\n",
616             (int)(dashList[dash][dashListLength[dash]-1]), gPsCmd[PS_SETDASH]);
617    }
618    switch (pen) {
619    case SOLIDPAT: fprintf(FP, "      %s\n", gPsCmd[PS_STROKE]); break;
620    case BACKPAT:
621       if (!trans_pat) {
622          fprintf(FP, "      1 %s %s 0 %s\n",
623                gPsCmd[PS_SETGRAY], gPsCmd[PS_STROKE], gPsCmd[PS_SETGRAY]);
624       }
625       break;
626    default:
627       if (colorDump || !useGray) {
628          if (preDumpSetup) PSUseColorPattern();
629          fprintf(FP, "      %s\n", gPsCmd[PS_FLATTENPATH]);
630          DumpPatFill(FP, pen, ObjPtr->bbox, 6, TRUE);
631       } else {
632          fprintf(FP, "      %s\n", gPsCmd[PS_STROKE]);
633       }
634    }
635    fprintf(FP, "   %s\n", gPsCmd[PS_GRESTORE]);
636 }
637 
DumpArcObj(FP,ObjPtr)638 void DumpArcObj(FP, ObjPtr)
639    FILE *FP;
640    struct ObjRec *ObjPtr;
641 {
642    register struct ArcRec *arc_ptr=ObjPtr->detail.a;
643    int fill, trans_pat, width, pen, dash, color_index;
644    int xc, yc, xr, yr, dir, angle1, angle2, style, a_angle1, a_angle2;
645    int x1, y1, aw, ah;
646 
647    trans_pat = ObjPtr->trans_pat;
648    fill = arc_ptr->fill;
649    width = arc_ptr->width;
650    aw = arc_ptr->aw;
651    ah = arc_ptr->ah;
652    pen = arc_ptr->pen;
653    dash = arc_ptr->dash;
654    style = arc_ptr->style;
655    xc = arc_ptr->xc; yc = arc_ptr->yc;
656    x1 = arc_ptr->x1; y1 = arc_ptr->y1;
657    xr = (int)(arc_ptr->w/2); yr = (int)(arc_ptr->h/2);
658    dir = arc_ptr->dir;
659    angle1 = -round(((double)arc_ptr->angle1)/64.0);
660    angle2 = -round(((double)arc_ptr->angle2)/64.0) + angle1;
661    a_angle1 = -round(((double)arc_ptr->a_angle1)/64.0);
662    a_angle2 = -round(((double)arc_ptr->a_angle2)/64.0) + a_angle1;
663 
664    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
665          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
666       return;
667    }
668    fprintf(FP, "%% ARC\n");
669    if (ObjPtr->ctm != NULL) {
670       float m[6];
671 
672       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
673       m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
674       m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
675       m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
676       m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
677       fprintf(FP, "   %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
678             gPsCmd[PS_TRANSLATE]);
679       fprintf(FP, "   [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
680             m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
681             ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
682       fprintf(FP, "   %1d %s %1d %s %s\n",
683             ObjPtr->x, gPsCmd[PS_NEG], ObjPtr->y, gPsCmd[PS_NEG],
684             gPsCmd[PS_TRANSLATE]);
685    }
686    color_index = ObjPtr->color;
687    DumpRGBColorLine(FP, color_index, 0, TRUE);
688 
689    switch (fill) {
690    case NONEPAT: break;
691    case SOLIDPAT:
692       DumpArcPSPath(FP,xc,yc,xr,yr,dir,angle1,angle2,TRUE,"","   ");
693       fprintf(FP, "   %s\n", gPsCmd[PS_FILL]);
694       break;
695    case BACKPAT:
696       if (!trans_pat) {
697          DumpArcPSPath(FP,xc,yc,xr,yr,dir,angle1,angle2,TRUE,"","   ");
698          fprintf(FP, "   %s 1 %s %s\n", gPsCmd[PS_CLOSEPATH],
699                gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
700          DumpRGBColorLine(FP, color_index, 3, TRUE);
701       }
702       break;
703    default:
704       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
705       if (colorDump || !useGray) {
706          if (preDumpSetup) PSUseColorPattern();
707          if (!trans_pat) {
708             DumpArcPSPath(FP, xc, yc, xr, yr, dir, angle1, angle2, TRUE,
709                   "   ","      ");
710             fprintf(FP, "   %s 1 %s %s\n", gPsCmd[PS_CLOSEPATH],
711                   gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
712             DumpRGBColorLine(FP, color_index, 3, TRUE);
713          }
714          DumpArcPSPath(FP,xc,yc,xr,yr,dir,angle1,angle2,TRUE,"   ","      ");
715          fprintf(FP, "   %s %s %s\n", gPsCmd[PS_CLOSEPATH],
716                gPsCmd[PS_CLIP], gPsCmd[PS_NEWPATH]);
717          DumpPatFill(FP, fill, ObjPtr->bbox, 3, TRUE);
718       } else {
719          GrayCheck(fill);
720          fprintf(FP, "   %s %s\n", GrayStr(fill), gPsCmd[PS_SETGRAY]);
721          DumpArcPSPath(FP,xc,yc,xr,yr,dir,angle1,angle2,TRUE,"   ","      ");
722          fprintf(FP, "   %s\n", gPsCmd[PS_FILL]);
723       }
724       fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
725       break;
726    }
727 
728    if (pen == NONEPAT) {
729       if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
730       fprintf(FP, "\n");
731       return;
732    }
733 
734    fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
735 
736    if ((colorDump || !useGray) && pen > BACKPAT && !trans_pat) {
737       if (style == LS_PLAIN) {
738          DumpArcPath(FP, ObjPtr, xc, yc, xr, yr, dir, angle1, angle2,
739                width, BACKPAT, 0, trans_pat);
740       } else {
741          DumpArcPath(FP, ObjPtr, xc, yc, xr, yr, dir, a_angle1, a_angle2,
742                width, BACKPAT, 0, trans_pat);
743       }
744       DumpRGBColorLine(FP, color_index, 3, TRUE);
745    }
746    if (style == LS_PLAIN) {
747       DumpArcPath(FP, ObjPtr, xc, yc, xr, yr, dir, angle1, angle2,
748             width, pen, dash, trans_pat);
749    } else {
750       DumpArcPath(FP,ObjPtr,xc,yc,xr,yr,dir,a_angle1,a_angle2,
751             width, pen, dash, trans_pat);
752    }
753    fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
754 
755    if (style != LS_PLAIN && !(pen == BACKPAT && trans_pat)) {
756       DumpArcArrows(FP,ObjPtr);
757    }
758    if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
759    fprintf(FP, "\n");
760 }
761 
NeedsToCacheArcObj(ObjPtr)762 int NeedsToCacheArcObj(ObjPtr)
763    struct ObjRec *ObjPtr;
764 {
765    return (ObjPtr->ctm != NULL);
766 }
767 
768 static int arcXYMagInitialized=FALSE;
769 static double arcXMag[6], arcYMag[6];
770 
771 static
MakeArcRotatedVs(obj_ptr,oval_vs,angle1,angle2,rotated_n,rotated_vlist)772 void MakeArcRotatedVs(obj_ptr, oval_vs, angle1, angle2,
773       rotated_n, rotated_vlist)
774    struct ObjRec *obj_ptr;
775    IntPoint *oval_vs;
776    int angle1, angle2, *rotated_n;
777    XPoint **rotated_vlist;
778 {
779    struct ArcRec *arc_ptr=obj_ptr->detail.a;
780    XPoint *sv=NULL;
781    IntPoint *pv=NULL, *cntrlv=NULL;
782    int i=0, sn=0, cntrln=0, v_index=0, cur_index=0, angle=0;
783    int num_vs=0, angle90=(90<<6), angle360=(360<<6), seen_angle1=FALSE;
784    int cx=arc_ptr->xc, cy=arc_ptr->yc;
785    double hw=(double)(arc_ptr->w>>1), hh=(double)(arc_ptr->h>>1);
786    int start_angle=angle90-angle360, end_angle=angle360;
787    IntPoint first_pt;
788 
789    memset(&first_pt, 0, sizeof(IntPoint));
790 
791    if (angle1 > angle2) {
792       angle = angle2;
793       angle2 = angle1;
794       angle1 = angle;
795    }
796    while (start_angle > angle1) start_angle -= angle360;
797    while (end_angle < angle2) end_angle += angle360;
798    for (angle=start_angle; angle <= end_angle; angle+=angle90) {
799       /* the quadrant being considered is angle-angle90 to angle */
800       double angle_in_quadrant; /* 0 < angle_in_quadrant <= 90.0 degrees */
801 
802       if (seen_angle1) {
803          if (angle >= angle2) {
804             angle_in_quadrant = ((double)(angle2-(angle-angle90)))/64.0;
805             if (angle_in_quadrant < 20.0) {
806                num_vs++;
807             } else if (angle_in_quadrant < 35.0) {
808                num_vs += 2;
809             } else if (angle_in_quadrant < 50.0) {
810                num_vs += 3;
811             } else if (angle_in_quadrant < 65.0) {
812                num_vs += 4;
813             } else if (angle_in_quadrant < 80.0) {
814                num_vs += 5;
815             } else {
816                num_vs += 6;
817             }
818             break;
819          } else {
820             num_vs += 6;
821          }
822       } else {
823          if (angle >= angle1) {
824             angle_in_quadrant = ((double)(angle1-(angle-angle90)))/64.0;
825             if (angle_in_quadrant < 10.0) {
826                num_vs += 7;
827             } else if (angle_in_quadrant < 25.0) {
828                num_vs += 6;
829             } else if (angle_in_quadrant < 40.0) {
830                num_vs += 5;
831             } else if (angle_in_quadrant < 55.0) {
832                num_vs += 4;
833             } else if (angle_in_quadrant < 70.0) {
834                num_vs += 3;
835             } else if (angle_in_quadrant < 80.0) {
836                num_vs += 2;
837             } else {
838                num_vs++;
839             }
840             if (angle >= angle2) {
841                angle_in_quadrant = ((double)(angle2-(angle-angle90)))/64.0;
842                if (angle_in_quadrant < 20.0) {
843                   num_vs -= 5;
844                } else if (angle_in_quadrant < 35.0) {
845                   num_vs -= 4;
846                } else if (angle_in_quadrant < 50.0) {
847                   num_vs -= 3;
848                } else if (angle_in_quadrant < 65.0) {
849                   num_vs -= 2;
850                } else if (angle_in_quadrant < 80.0) {
851                   num_vs--;
852                }
853                break;
854             }
855             seen_angle1 = TRUE;
856          }
857       }
858    }
859    *rotated_n = 0;
860    *rotated_vlist = (XPoint*)malloc((num_vs+5)*sizeof(XPoint));
861    pv = (IntPoint*)malloc((num_vs+5)*sizeof(IntPoint));
862    if (*rotated_vlist == NULL || pv == NULL) FailAllocMessage();
863    memset(*rotated_vlist, 0, (num_vs+5)*sizeof(XPoint));
864    memset(pv, 0, (num_vs+5)*sizeof(IntPoint));
865 
866    cur_index = 0;
867    seen_angle1 = FALSE;
868    for (angle=start_angle, v_index=0; angle <= end_angle;
869          angle+=angle90, v_index+=6) {
870       /* the quadrant being considered is angle-angle90 to angle */
871       double angle_in_quadrant; /* 0 < angle_in_quadrant <= 90.0 degrees */
872       int count=(-1);
873       double sin_val, cos_val;
874 
875       if (v_index >= 24) v_index = 0;
876       if (seen_angle1) {
877          if (angle >= angle2) {
878             angle_in_quadrant = ((double)(angle2-(angle-angle90)))/64.0;
879             if (angle_in_quadrant < 20.0) {
880                count = 1;
881             } else if (angle_in_quadrant < 35.0) {
882                count = 2;
883             } else if (angle_in_quadrant < 50.0) {
884                count = 3;
885             } else if (angle_in_quadrant < 65.0) {
886                count = 4;
887             } else if (angle_in_quadrant < 80.0) {
888                count = 5;
889             } else {
890                count = 6;
891             }
892             for (i=1; i < count; i++) {
893                pv[cur_index].x = oval_vs[v_index+i].x;
894                pv[cur_index].y = oval_vs[v_index+i].y;
895                cur_index++;
896             }
897             sin_val = cos((double)(angle2*M_PI/180.0/64.0));
898             cos_val = sin((double)(angle2*M_PI/180.0/64.0));
899             pv[cur_index].x = cx + round(hw*sin_val);
900             pv[cur_index].y = cy - round(hh*cos_val);
901             cur_index++;
902             break;
903          } else {
904             for (i=1; i < 7; i++) {
905                pv[cur_index].x = oval_vs[v_index+i].x;
906                pv[cur_index].y = oval_vs[v_index+i].y;
907                cur_index++;
908             }
909          }
910       } else {
911          if (angle >= angle1) {
912             angle_in_quadrant = ((double)(angle1-(angle-angle90)))/64.0;
913             if (angle_in_quadrant < 10.0) {
914                count = 7;
915             } else if (angle_in_quadrant < 25.0) {
916                count = 6;
917             } else if (angle_in_quadrant < 40.0) {
918                count = 5;
919             } else if (angle_in_quadrant < 55.0) {
920                count = 4;
921             } else if (angle_in_quadrant < 70.0) {
922                count = 3;
923             } else if (angle_in_quadrant < 80.0) {
924                count = 2;
925             } else {
926                count = 1;
927             }
928             sin_val = cos((double)(angle1*M_PI/180.0/64.0));
929             cos_val = sin((double)(angle1*M_PI/180.0/64.0));
930             pv[0].x = first_pt.x = cx + round(hw*sin_val);
931             pv[0].y = first_pt.y = cy - round(hh*cos_val);
932             for (i=1; i < count; i++) {
933                pv[i].x = oval_vs[(v_index+7-(count-i)) % 24].x;
934                pv[i].y = oval_vs[(v_index+7-(count-i)) % 24].y;
935             }
936             cur_index += count;
937             if (angle >= angle2) {
938                angle_in_quadrant = ((double)(angle2-(angle-angle90)))/64.0;
939                if (angle_in_quadrant < 20.0) {
940                   cur_index -= 6;
941                } else if (angle_in_quadrant < 35.0) {
942                   cur_index -= 5;
943                } else if (angle_in_quadrant < 50.0) {
944                   cur_index -= 4;
945                } else if (angle_in_quadrant < 65.0) {
946                   cur_index -= 3;
947                } else if (angle_in_quadrant < 80.0) {
948                   cur_index -= 2;
949                } else {
950                   cur_index--;
951                }
952                sin_val = cos((double)(angle2*M_PI/180.0/64.0));
953                cos_val = sin((double)(angle2*M_PI/180.0/64.0));
954                pv[cur_index].x = cx + round(hw*sin_val);
955                pv[cur_index].y = cy - round(hh*cos_val);
956                cur_index++;
957                break;
958             }
959             seen_angle1 = TRUE;
960          }
961       }
962    }
963    if (num_vs != cur_index) {
964       fprintf(stderr, "num_vs (%1d) != cur_index (%1d)\n", num_vs, cur_index);
965    }
966    pv[num_vs].x = cx;
967    pv[num_vs].y = cy;
968    for (i=0; i < num_vs+1; i++) {
969       int x, y;
970 
971       if (i == 0) {
972          TransformPointThroughCTM(first_pt.x-obj_ptr->x, first_pt.y-obj_ptr->y,
973                obj_ptr->ctm, &x, &y);
974          first_pt.x = x + obj_ptr->x;
975          first_pt.y = y + obj_ptr->y;
976       }
977       TransformPointThroughCTM(pv[i].x-obj_ptr->x, pv[i].y-obj_ptr->y,
978             obj_ptr->ctm, &x, &y);
979       pv[i].x = x + obj_ptr->x;
980       pv[i].y = y + obj_ptr->y;
981       (*rotated_vlist)[i].x = (short)OFFSET_X(pv[i].x);
982       (*rotated_vlist)[i].y = (short)OFFSET_Y(pv[i].y);
983    }
984    if (num_vs == 1) {
985       /* well, the real way to do this is to use a mid-point */
986       sn = 2;
987       sv = (XPoint*)malloc((num_vs+1)*sizeof(XPoint));
988       if (sv == NULL) FailAllocMessage();
989       memset(sv, 0, (num_vs+1)*sizeof(XPoint));
990       sv[0].x = (short)(OFFSET_X(first_pt.x));
991       sv[0].y = (short)(OFFSET_Y(first_pt.y));
992       sv[1].x = (short)(OFFSET_X(pv[0].x));
993       sv[1].y = (short)(OFFSET_Y(pv[0].y));
994    } else {
995       sv = MakeIntSplinePolyVertex(&sn, &cntrln, &cntrlv,
996             drawOrigX, drawOrigY, num_vs, pv);
997    }
998    if (sv == NULL) {
999       FailAllocMessage();
1000    } else {
1001       XPoint *new_sv=(XPoint*)malloc((sn+3)*sizeof(XPoint));
1002 
1003       if (new_sv == NULL) FailAllocMessage();
1004       memset(new_sv, 0, (sn+3)*sizeof(XPoint));
1005       for (i=0; i < sn; i++) {
1006          new_sv[i].x = sv[i].x;
1007          new_sv[i].y = sv[i].y;
1008       }
1009       new_sv[sn].x = (*rotated_vlist)[num_vs].x;
1010       new_sv[sn].y = (*rotated_vlist)[num_vs].y;
1011       new_sv[sn+1].x = new_sv[0].x;
1012       new_sv[sn+1].y = new_sv[0].y;
1013       free(sv);
1014       sv = new_sv;
1015    }
1016    free(*rotated_vlist);
1017    *rotated_n = sn;
1018    *rotated_vlist = sv;
1019 
1020    free(pv);
1021    if (cntrlv != NULL) free(cntrlv);
1022 }
1023 
1024 static
MakeCachedArc(ObjPtr)1025 void MakeCachedArc(ObjPtr)
1026    struct ObjRec *ObjPtr;
1027 {
1028    struct ArcRec *arc_ptr=ObjPtr->detail.a;
1029    IntPoint tmp_vs[25];
1030    struct BBRec obbox;
1031    int i, cx, cy, a_angle1, a_angle2;
1032    double hw, hh; /* half w and half h */
1033 
1034    if (!arcXYMagInitialized) {
1035       int j;
1036 
1037       for (i=0, j=0; i < 90; i+=15, j++) {
1038          arcXMag[j] = cos((double)(((double)i)*M_PI/180.0));
1039          arcYMag[j] = sin((double)(((double)i)*M_PI/180.0));
1040       }
1041       arcXYMagInitialized = TRUE;
1042    }
1043    if (ObjPtr->ctm == NULL) return;
1044 
1045    a_angle1 = arc_ptr->angle1;
1046    a_angle2 = arc_ptr->angle2;
1047    if (arc_ptr->style != LS_PLAIN) {
1048       GetArcArrowInfo(ObjPtr, NULL, NULL, NULL, &a_angle1,
1049             NULL, NULL, NULL, &a_angle2);
1050    }
1051    arc_ptr->a_angle1 = a_angle1;
1052    arc_ptr->a_angle2 = a_angle2;
1053    cx = arc_ptr->xc;
1054    cy = arc_ptr->yc;
1055    obbox.ltx = cx-(arc_ptr->w>>1); obbox.lty = cy-(arc_ptr->h>>1);
1056    obbox.rbx = cx+(arc_ptr->w>>1); obbox.rby = cy+(arc_ptr->h>>1);
1057    hw = (double)(arc_ptr->w>>1);
1058    hh = (double)(arc_ptr->h>>1);
1059 
1060    for (i=0; i < 24; i++) {
1061       double dx, dy;
1062 
1063       switch (i) {
1064       case 0: tmp_vs[0].x=obbox.rbx; tmp_vs[0].y=cy; break;
1065       case 6: tmp_vs[6].x=cx; tmp_vs[6].y=obbox.lty; break;
1066       case 12: tmp_vs[12].x=obbox.ltx; tmp_vs[12].y=cy; break;
1067       case 18: tmp_vs[18].x=cx; tmp_vs[18].y=obbox.rby; break;
1068       default:
1069          if (i < 6) {
1070             dx = (hw*arcXMag[i % 6]); dy = (hh*arcYMag[i % 6]);
1071             tmp_vs[i].x=cx+round(dx); tmp_vs[i].y=cy-round(dy);
1072          } else if (i < 12) {
1073             dx = (hw*arcXMag[(24-i) % 6]); dy = (hh*arcYMag[(24-i) % 6]);
1074             tmp_vs[i].x=cx-round(dx); tmp_vs[i].y=cy-round(dy);
1075          } else if (i < 18) {
1076             dx = (hw*arcXMag[i % 6]); dy = (hh*arcYMag[i % 6]);
1077             tmp_vs[i].x=cx-round(dx); tmp_vs[i].y=cy+round(dy);
1078          } else {
1079             dx = (hw*arcXMag[(24-i) % 6]); dy = (hh*arcYMag[(24-i) % 6]);
1080             tmp_vs[i].x=cx+round(dx); tmp_vs[i].y=cy+round(dy);
1081          }
1082          break;
1083       }
1084    }
1085    tmp_vs[24].x=tmp_vs[0].x; tmp_vs[24].y=tmp_vs[0].y;
1086 
1087    if (arc_ptr->rotated_vlist != NULL) free(arc_ptr->rotated_vlist);
1088    if (arc_ptr->rotated_asvlist != NULL) free(arc_ptr->rotated_asvlist);
1089    arc_ptr->rotated_vlist = arc_ptr->rotated_asvlist = NULL;
1090    arc_ptr->rotated_n = arc_ptr->rotated_asn = 0;
1091 
1092    MakeArcRotatedVs(ObjPtr, tmp_vs, arc_ptr->angle1,
1093          arc_ptr->angle1+arc_ptr->angle2, &arc_ptr->rotated_n,
1094          &arc_ptr->rotated_vlist);
1095    if (arc_ptr->style != LS_PLAIN) {
1096       MakeArcRotatedVs(ObjPtr, tmp_vs, arc_ptr->a_angle1,
1097             arc_ptr->a_angle1+arc_ptr->a_angle2, &arc_ptr->rotated_asn,
1098             &arc_ptr->rotated_asvlist);
1099    }
1100 }
1101 
DrawArcObj(window,XOff,YOff,ObjPtr)1102 void DrawArcObj(window, XOff, YOff, ObjPtr)
1103    Window window;
1104    int XOff, YOff;
1105    struct ObjRec *ObjPtr;
1106 {
1107    struct ArcRec *arc_ptr=ObjPtr->detail.a;
1108    int i, ltx, lty, w, h, angle1, angle2;
1109    int fill, trans_pat, width, pen, dash, pixel, real_x_off, real_y_off;
1110    XPoint tmp_v[4];
1111    IntPoint vs1[4], vs2[4];
1112    XGCValues values;
1113 
1114    if (NeedsToCacheArcObj(ObjPtr) && arc_ptr->rotated_vlist==NULL) {
1115       MakeCachedArc(ObjPtr);
1116    }
1117    if (userDisableRedraw) return;
1118 
1119    real_x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
1120    real_y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
1121 
1122    ltx = ZOOMED_SIZE(arc_ptr->ltx-real_x_off);
1123    lty = ZOOMED_SIZE(arc_ptr->lty-real_y_off);
1124    w = ZOOMED_SIZE(arc_ptr->ltx+arc_ptr->w-real_x_off)-ltx;
1125    h = ZOOMED_SIZE(arc_ptr->lty+arc_ptr->h-real_y_off)-lty;
1126    angle1 = arc_ptr->angle1;
1127    angle2 = arc_ptr->angle2;
1128 
1129    trans_pat = ObjPtr->trans_pat;
1130    fill = arc_ptr->fill;
1131    width = arc_ptr->width;
1132    pen = arc_ptr->pen;
1133    dash = arc_ptr->dash;
1134    pixel = colorPixels[ObjPtr->color];
1135 
1136    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
1137          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
1138       return;
1139    }
1140    if (fill != NONEPAT) {
1141       values.foreground = GetDrawingBgPixel(fill, pixel);
1142       values.function = GXcopy;
1143       values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
1144       values.stipple = patPixmap[fill];
1145       XChangeGC(mainDisplay, drawGC,
1146             GCForeground | GCFunction | GCFillStyle | GCStipple, &values);
1147       if (ObjPtr->ctm != NULL) {
1148          XFillPolygon(mainDisplay, window, drawGC, arc_ptr->rotated_vlist,
1149                arc_ptr->rotated_n+2, Complex, CoordModeOrigin);
1150       } else {
1151          XFillArc(mainDisplay, window, drawGC, ltx, lty, w, h, angle1, angle2);
1152       }
1153    }
1154    if (pen == NONEPAT) return;
1155 
1156    values.foreground = GetDrawingBgPixel(pen, pixel);
1157    values.function = GXcopy;
1158    values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
1159    values.stipple = patPixmap[pen];
1160    values.line_width = ZOOMED_SIZE(width);
1161 #ifdef NO_THIN_LINE
1162    if (values.line_width < 1) values.line_width = 1;
1163 #else
1164 #ifdef THIN_OVAL_AND_ARC
1165    if (values.line_width <= 1) values.line_width = 0;
1166 #endif
1167 #endif
1168    if (dash != 0) {
1169       XSetDashes(mainDisplay, drawGC, 0, dashList[dash],
1170             dashListLength[dash]);
1171       values.line_style = LineOnOffDash;
1172    } else {
1173       values.line_style = LineSolid;
1174    }
1175    XChangeGC(mainDisplay, drawGC,
1176          GCForeground | GCFunction | GCFillStyle | GCStipple | GCLineWidth |
1177          GCLineStyle, &values);
1178 
1179    GetArcArrowInfo(ObjPtr, NULL, NULL, vs1, NULL, NULL, NULL, vs2, NULL);
1180    if (arc_ptr->style & LS_LEFT) {
1181       for (i=0; i < 3; i++) {
1182          tmp_v[i].x = (short)ZOOMED_SIZE(vs1[i].x-real_x_off);
1183          tmp_v[i].y = (short)ZOOMED_SIZE(vs1[i].y-real_y_off);
1184       }
1185       tmp_v[3].x = tmp_v[0].x;
1186       tmp_v[3].y = tmp_v[0].y;
1187       XFillPolygon(mainDisplay, window, drawGC, tmp_v, 4, Convex,
1188             CoordModeOrigin);
1189    }
1190    if (arc_ptr->style & LS_RIGHT) {
1191       for (i=0; i < 3; i++) {
1192          tmp_v[i].x = (short)ZOOMED_SIZE(vs2[i].x-real_x_off);
1193          tmp_v[i].y = (short)ZOOMED_SIZE(vs2[i].y-real_y_off);
1194       }
1195       tmp_v[3].x = tmp_v[0].x;
1196       tmp_v[3].y = tmp_v[0].y;
1197       XFillPolygon(mainDisplay, window, drawGC, tmp_v, 4, Convex,
1198             CoordModeOrigin);
1199    }
1200    if (ObjPtr->ctm != NULL) {
1201       if (arc_ptr->style == LS_PLAIN) {
1202          XDrawLines(mainDisplay, window, drawGC, arc_ptr->rotated_vlist,
1203                arc_ptr->rotated_n, CoordModeOrigin);
1204       } else {
1205          XDrawLines(mainDisplay, window, drawGC, arc_ptr->rotated_asvlist,
1206                arc_ptr->rotated_asn, CoordModeOrigin);
1207       }
1208    } else {
1209       if (arc_ptr->style == LS_PLAIN) {
1210          XDrawArc(mainDisplay, window, drawGC, ltx, lty, w, h, angle1, angle2);
1211       } else {
1212          XDrawArc(mainDisplay, window, drawGC, ltx, lty, w, h,
1213                arc_ptr->a_angle1, arc_ptr->a_angle2);
1214       }
1215    }
1216 }
1217 
CreateArcObj(xc,yc,x1,y1,x2,y2,dir,ltx,lty,w,h,angle1,angle2,CreateAbsolute)1218 struct ObjRec *CreateArcObj(xc, yc, x1, y1, x2, y2, dir, ltx, lty, w, h,
1219       angle1, angle2, CreateAbsolute)
1220    int xc, yc, x1, y1, x2, y2, dir, ltx, lty, w, h, angle1, angle2;
1221    int CreateAbsolute;
1222 {
1223    struct ArcRec *arc_ptr;
1224    struct ObjRec *obj_ptr;
1225 
1226    arc_ptr = (struct ArcRec *)malloc(sizeof(struct ArcRec));
1227    if (arc_ptr == NULL) FailAllocMessage();
1228    memset(arc_ptr, 0, sizeof(struct ArcRec));
1229    arc_ptr->fill = objFill;
1230    arc_ptr->width = curWidthOfLine[lineWidth];
1231    arc_ptr->aw = curArrowHeadW[lineWidth];
1232    arc_ptr->ah = curArrowHeadH[lineWidth];
1233    UtilStrCpyN(arc_ptr->width_spec, sizeof(arc_ptr->width_spec),
1234          curWidthOfLineSpec[lineWidth]);
1235    UtilStrCpyN(arc_ptr->aw_spec, sizeof(arc_ptr->aw_spec),
1236          curArrowHeadWSpec[lineWidth]);
1237    UtilStrCpyN(arc_ptr->ah_spec, sizeof(arc_ptr->ah_spec),
1238          curArrowHeadHSpec[lineWidth]);
1239    arc_ptr->pen = penPat;
1240    arc_ptr->dash = curDash;
1241    arc_ptr->style = lineStyle;
1242 
1243    if (CreateAbsolute) {
1244       arc_ptr->xc = xc;
1245       arc_ptr->yc = yc;
1246       arc_ptr->x1 = x1;
1247       arc_ptr->y1 = y1;
1248       arc_ptr->x2 = x2;
1249       arc_ptr->y2 = y2;
1250       arc_ptr->ltx = xc-(w>>1);
1251       arc_ptr->lty = yc-(h>>1);
1252    } else {
1253       arc_ptr->xc = ABS_X(xc);
1254       arc_ptr->yc = ABS_Y(yc);
1255       arc_ptr->x1 = ABS_X(x1);
1256       arc_ptr->y1 = ABS_Y(y1);
1257       arc_ptr->x2 = ABS_X(x2);
1258       arc_ptr->y2 = ABS_Y(y2);
1259       arc_ptr->ltx = ABS_X(xc-(w>>1));
1260       arc_ptr->lty = ABS_Y(yc-(h>>1));
1261    }
1262    arc_ptr->dir = dir;
1263    arc_ptr->w = (arc_ptr->xc-arc_ptr->ltx)<<1;
1264    arc_ptr->h = (arc_ptr->yc-arc_ptr->lty)<<1;
1265    arc_ptr->angle1 = arc_ptr->a_angle1 = angle1;
1266    arc_ptr->angle2 = arc_ptr->a_angle2 = angle2;
1267    arc_ptr->rotated_n = 0;
1268    arc_ptr->rotated_vlist = NULL;
1269    arc_ptr->rotated_asn = 0;
1270    arc_ptr->rotated_asvlist = NULL;
1271 
1272    obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
1273    if (obj_ptr == NULL) FailAllocMessage();
1274    memset(obj_ptr, 0, sizeof(struct ObjRec));
1275    obj_ptr->detail.a = arc_ptr;
1276 
1277    obj_ptr->type = OBJ_ARC;
1278    obj_ptr->color = colorIndex;
1279    if (mainDisplay != NULL) {
1280       UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
1281             colorMenuItems[colorIndex]);
1282    }
1283    obj_ptr->id = objId++;
1284    obj_ptr->dirty = FALSE;
1285    obj_ptr->rotation = 0;
1286    obj_ptr->locked = FALSE;
1287    obj_ptr->fattr = obj_ptr->lattr = NULL;
1288    obj_ptr->ctm = NULL;
1289    obj_ptr->invisible = FALSE;
1290    obj_ptr->trans_pat = transPat;
1291 
1292    AdjObjSplineVs(obj_ptr);
1293    AdjObjBBox(obj_ptr);
1294    AddObj(NULL, topObj, obj_ptr);
1295 
1296    return obj_ptr;
1297 }
1298 
1299 static
Colinear(Ax,Ay,Dx,Dy,Cx,Cy)1300 int Colinear(Ax, Ay, Dx, Dy, Cx, Cy)
1301    double Ax, Ay, Dx, Dy, Cx, Cy;
1302    /* returns TRUE if point D is between A and C and A, D, C are colinear */
1303 {
1304    double len_ad=(double)0, len_dc=(double)0, len_ac=(double)0;
1305    double dx=(double)0, dy=(double)0;
1306 
1307    dx = Ax-Cx;
1308    dy = Ay-Cy;
1309    len_ac = (double)sqrt(dx*dx+dy*dy);
1310 
1311    dx = Ax-Dx;
1312    dy = Ay-Dy;
1313    len_ad = (double)sqrt(dx*dx+dy*dy);
1314 
1315    dx = Cx-Dx;
1316    dy = Cy-Dy;
1317    len_dc = (double)sqrt(dx*dx+dy*dy);
1318 
1319    return (fabs(len_ad+len_dc-len_ac) < INT_TOL);
1320 }
1321 
1322 static
SegmentIntersects(Ax,Ay,Bx,By,Cx,Cy,Dx,Dy)1323 int SegmentIntersects(Ax, Ay, Bx, By, Cx, Cy, Dx, Dy)
1324    int Ax, Ay, Bx, By;
1325    double Cx, Cy, Dx, Dy;
1326    /* returns TRUE if line segments AB and CD intersects */
1327 {
1328    int AB_horizontal=(Ay==By), CD_horizontal=(fabs(Cy-Dy)<INT_TOL);
1329    int AB_vertical=(Ax==Bx), CD_vertical=(fabs(Cx-Dx)<INT_TOL);
1330    double y_intersect_AB=(double)0, slope_AB=(double)0;
1331    double y_intersect_CD=(double)0, slope_CD=(double)0;
1332    double Ix=(double)0, Iy=(double)0;
1333 
1334    if (AB_horizontal) {
1335       y_intersect_AB = (double)Ay;
1336       slope_AB = 0;
1337    } else if (AB_vertical) {
1338       /* y_intersect_AB = Inf; */
1339       /* slope_AB = Inf; */
1340    } else {
1341       slope_AB = (double)(((double)(Ay-By))/((double)(Ax-Bx)));
1342       y_intersect_AB = Ay - Ax * slope_AB;
1343    }
1344    if (CD_horizontal) {
1345       y_intersect_CD = Cy;
1346       slope_CD = 0;
1347    } else if (CD_vertical) {
1348       /* y_intersect_CD = Inf; */
1349       /* slope_CD = Inf; */
1350    } else {
1351       slope_CD = (double)((Cy-Dy)/(Cx-Dx));
1352       y_intersect_CD = Cy - Cx * slope_CD;
1353    }
1354    if (AB_horizontal) {
1355       if (CD_horizontal) {
1356          return FALSE;
1357       } else if (CD_vertical) {
1358          Ix = Cx;
1359          Iy = (double)Ay;
1360       } else {
1361          Ix = (((double)Ay) - y_intersect_CD) / slope_CD;
1362          Iy = (double)Ay;
1363       }
1364    } else if (AB_vertical) {
1365       if (CD_horizontal) {
1366          Ix = (double)Ax;
1367          Iy = Cy;
1368       } else if (CD_vertical) {
1369          return FALSE;
1370       } else {
1371          Ix = (double)Ax;
1372          Iy = slope_CD * ((double)Ax) + y_intersect_CD;
1373       }
1374    } else {
1375       if (CD_horizontal) {
1376          Ix = (Cy - y_intersect_AB) / slope_AB;
1377          Iy = Cy;
1378       } else if (CD_vertical) {
1379          Ix = Cx;
1380          Iy = slope_AB * Cx + y_intersect_AB;
1381       } else {
1382          Ix = (y_intersect_CD - y_intersect_AB) / (slope_AB - slope_CD);
1383          Iy = slope_AB * Ix + y_intersect_AB;
1384       }
1385    }
1386    return Colinear(Cx, Cy, Ix, Iy, Dx, Dy);
1387 }
1388 
1389 static
GetCenter(Ax,Ay,Cx,Cy,Bx,By,pcx,pcy,pdir)1390 int GetCenter(Ax, Ay, Cx, Cy, Bx, By, pcx, pcy, pdir)
1391    int Ax, Ay, Cx, Cy, Bx, By, *pcx, *pcy, *pdir;
1392 {
1393    /*
1394     * point A is (OrigX,OrigY) - start of arc
1395     * point B is (grid_x,grid_y) - this point is moving
1396     * point C is (first_x,first_y) - end of arc
1397     * point D is the center of the circle
1398     * point E is the midpoint of the AB segment
1399     * point F is the midpoint of the CB segment
1400     */
1401    int AB_horizontal=FALSE, BC_horizontal=FALSE;
1402    int AB_vertical=FALSE, BC_vertical=FALSE, saved_dir=(*pdir);
1403    double Dx=(double)0, Dy=(double)0;
1404    double Ex=(double)0, Ey=(double)0;
1405    double Fx=(double)0, Fy=(double)0;
1406    double y_intersect_DE=(double)0, slope_DE=(double)0;
1407    double y_intersect_DF=(double)0, slope_DF=(double)0;
1408 
1409    if ((Ax==Bx && Ay==By) || (Cx==Bx && Cy==By)) {
1410       return FALSE;
1411    }
1412    AB_horizontal = (Ay==By);
1413    AB_vertical = (Ax==Bx);
1414 
1415    Ex = (double)(((double)(Ax+Bx))/((double)2));
1416    Ey = (double)(((double)(Ay+By))/((double)2));
1417 
1418    if (AB_horizontal) {
1419       /* y_intersect_DE = Inf; */
1420       /* slope_DE = Inf; */
1421    } else if (AB_vertical) {
1422       y_intersect_DE = Ey;
1423       slope_DE = 0;
1424    } else {
1425       slope_DE = (double)(((double)(Bx-Ax))/((double)(Ay-By)));
1426       y_intersect_DE = Ey - Ex * slope_DE;
1427    }
1428    BC_horizontal = (Cy==By);
1429    BC_vertical = (Cx==Bx);
1430 
1431    Fx = (double)(((double)(Cx+Bx))/((double)2));
1432    Fy = (double)(((double)(Cy+By))/((double)2));
1433 
1434    if (BC_horizontal) {
1435       /* y_intersect_DF = Inf; */
1436       /* slope_DF = Inf; */
1437    } else if (BC_vertical) {
1438       y_intersect_DF = Fy;
1439       slope_DF = 0;
1440    } else {
1441       slope_DF = (double)(((double)(Bx-Cx))/((double)(Cy-By)));
1442       y_intersect_DF = Fy - Fx * slope_DF;
1443    }
1444    if (AB_horizontal) {
1445       if (BC_horizontal) {
1446          return FALSE;
1447       } else if (BC_vertical) {
1448          Dx = Ex;
1449          Dy = Fy;
1450       } else {
1451          Dx = Ex;
1452          Dy = slope_DF * Ex + y_intersect_DF;
1453       }
1454    } else if (AB_vertical) {
1455       if (BC_horizontal) {
1456          Dx = Fx;
1457          Dy = Ey;
1458       } else if (BC_vertical) {
1459          return FALSE;
1460       } else {
1461          Dx = (Ey - y_intersect_DF) / slope_DF;
1462          Dy = Ey;
1463       }
1464    } else {
1465       if (BC_horizontal) {
1466          Dx = Fx;
1467          Dy = slope_DE * Fx + y_intersect_DE;
1468       } else if (BC_vertical) {
1469          Dx = (Fy - y_intersect_DE) / slope_DE;
1470          Dy = Fy;
1471       } else {
1472          if (fabs(slope_DE - slope_DF) < INT_TOL) {
1473             return FALSE;
1474          } else {
1475             Dx = (y_intersect_DF - y_intersect_DE) / (slope_DE - slope_DF);
1476          }
1477          Dy = slope_DE * Dx + y_intersect_DE;
1478       }
1479    }
1480    *pcx = round(Dx);
1481    *pcy = round(Dy);
1482    if (Colinear(((double)Ax), ((double)Ay), Dx, Dy,
1483          ((double)Cx), ((double)Cy))) {
1484       if (saved_dir == INVALID) {
1485          *pdir = ArcDirection(*pcx, *pcy, Ax, Ay, Cx, Cy);
1486       } else {
1487          /* don't change dir */
1488       }
1489    } else {
1490       if (SegmentIntersects(Ax, Ay, Cx, Cy, ((double)Bx), ((double)By),
1491             Dx, Dy)) {
1492          *pdir = ArcDirection(*pcx, *pcy, Ax, Ay, Cx, Cy);
1493       } else {
1494          if (saved_dir == INVALID) {
1495             /* in this case, ArcDirection() gives the opposite direction */
1496             *pdir = !ArcDirection(*pcx, *pcy, Ax, Ay, Cx, Cy);
1497          } else {
1498             /* don't change dir */
1499          }
1500       }
1501    }
1502    return TRUE;
1503 }
1504 
1505 static
HighLightInContinueArc(drawing_arc,OrigX,OrigY,saved_x,saved_y,ltx,lty,pw,ph,angle1,angle2,pdx,pdy,pradius,show_measure_cursor,end_show_measure_cursor,buf)1506 void HighLightInContinueArc(drawing_arc, OrigX, OrigY, saved_x, saved_y,
1507       ltx, lty, pw, ph, angle1, angle2, pdx, pdy, pradius, show_measure_cursor,
1508       end_show_measure_cursor, buf)
1509    int drawing_arc, OrigX, OrigY, saved_x, saved_y, ltx, lty;
1510    int *pw, *ph, angle1, angle2, *pdx, *pdy, *pradius;
1511    int show_measure_cursor, end_show_measure_cursor;
1512    char *buf;
1513 {
1514    char r_buf[80], x_buf[80], y_buf[80];
1515 
1516    if (drawing_arc) {
1517       if (!show_measure_cursor) {
1518          XDrawArc(mainDisplay, drawWindow, drawGC, ltx, lty, *pw, *ph,
1519                angle1, angle2);
1520       }
1521       PixelToMeasurementUnit(r_buf, ABS_SIZE((*pw)>>1));
1522       sprintf(buf, "r=%s\ndegree=%1d", r_buf, abs(angle2>>6));
1523    } else {
1524       char *cl_or_r=(curChoice==DRAWEDGEARC ? "cl" : "r");
1525 
1526       if (!show_measure_cursor) {
1527          XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1528                saved_x, saved_y);
1529       }
1530       *pdx = saved_x - OrigX;
1531       *pdy = saved_y - OrigY;
1532       *pradius = (int)(sqrt((double)(((double)(*pdx))*((double)(*pdx)) +
1533             ((double)(*pdy))*((double)(*pdy)))));
1534       *pw = *ph = ((*pradius)<<1);
1535       PixelToMeasurementUnit(r_buf, ABS_SIZE(*pradius));
1536       PixelToMeasurementUnit(x_buf, ABS_X(saved_x));
1537       PixelToMeasurementUnit(y_buf, ABS_Y(saved_y));
1538       sprintf(buf, "%s=%s\nx=%s\ny=%s", cl_or_r, r_buf, x_buf, y_buf);
1539    }
1540    if (show_measure_cursor) {
1541       ShowMeasureCursor(saved_x, saved_y, buf, TRUE);
1542    }
1543    if (end_show_measure_cursor) {
1544       EndShowMeasureCursor(saved_x, saved_y, buf, TRUE);
1545    }
1546 }
1547 
1548 static
ContinueArc(OrigX,OrigY)1549 void ContinueArc(OrigX, OrigY)
1550    int OrigX, OrigY;
1551 {
1552    int grid_x, grid_y, first_x=0, first_y=0, cx=0, cy=0;
1553    int end_x, end_y, saved_x, saved_y, dx, dy, radius;
1554    int done=FALSE, drawing_arc=FALSE;
1555    int dir=INVALID, ltx, lty, w, h, angle1, angle2=0;
1556    char buf[80], r_buf[80], x_buf[80], y_buf[80];
1557    char *cl_or_r=(curChoice==DRAWEDGEARC ? "cl" : "r");
1558    struct ObjRec *obj_ptr;
1559    XEvent input, ev;
1560 
1561    SetXorDrawGC(xorColorPixels[colorIndex]);
1562 
1563    grid_x = saved_x = OrigX;
1564    grid_y = saved_y = OrigY;
1565    XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, saved_x, saved_y);
1566 
1567    PixelToMeasurementUnit(r_buf, 0);
1568    PixelToMeasurementUnit(x_buf, ABS_X(grid_x));
1569    PixelToMeasurementUnit(y_buf, ABS_Y(grid_y));
1570    sprintf(buf, "%s=%s\nx=%s\ny=%s", cl_or_r, r_buf, x_buf, y_buf);
1571    StartShowMeasureCursor(grid_x, grid_y, buf, TRUE);
1572    if (!debugNoPointerGrab) {
1573       XGrabPointer(mainDisplay, drawWindow, FALSE,
1574             PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1575             GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1576    }
1577    if (curChoice == DRAWEDGEARC) {
1578       Msg(TgLoadCachedString(CSTID_SPECIFY_ARC_END));
1579       SetMouseStatus(TgLoadCachedString(CSTID_SET_ARC_END),
1580             TgLoadCachedString(CSTID_CANCEL), TgLoadCachedString(CSTID_CANCEL));
1581    } else {
1582       Msg(TgLoadCachedString(CSTID_SPECIFY_ARC_START));
1583       SetMouseStatus(TgLoadCachedString(CSTID_SET_ARC_START),
1584             TgLoadCachedString(CSTID_CANCEL), TgLoadCachedString(CSTID_CANCEL));
1585    }
1586    while (!done) {
1587       XNextEvent(mainDisplay, &input);
1588 
1589       if (input.type == Expose || input.type == VisibilityNotify) {
1590          ExposeEventHandler(&input, TRUE);
1591          SetXorDrawGC(xorColorPixels[colorIndex]);
1592       } else if (input.type == ButtonPress) {
1593          if (input.xbutton.button != Button1 || drawing_arc) {
1594             XUngrabPointer(mainDisplay, CurrentTime);
1595             HighLightInContinueArc(drawing_arc, OrigX, OrigY, saved_x,
1596                   saved_y, ltx, lty, &w, &h, angle1, angle2, &dx, &dy, &radius,
1597                   FALSE, TRUE, buf);
1598             done = TRUE;
1599             if (input.xbutton.button != Button1) {
1600                angle2 = 0;
1601             }
1602             Msg("");
1603             break;
1604          }
1605          /* drawing_arc is FALSE here */
1606          HighLightInContinueArc(drawing_arc, OrigX, OrigY, saved_x,
1607                saved_y, ltx, lty, &w, &h, angle1, angle2, &dx, &dy,
1608                &radius, TRUE, FALSE, buf);
1609          XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1610                saved_x, saved_y);
1611          first_x = saved_x;
1612          first_y = saved_y;
1613          drawing_arc = TRUE;
1614          if (OrigX == grid_x && OrigY == grid_y) {
1615             /* fake it as if the 1st point is ok but not the 2nd point */
1616             XUngrabPointer(mainDisplay, CurrentTime);
1617             grid_x = first_x;
1618             grid_y = first_y;
1619             done = TRUE;
1620          }
1621          if (curChoice == DRAWEDGEARC) {
1622             Msg(TgLoadCachedString(CSTID_SPECIFY_ARC_THIRD));
1623             SetMouseStatus(TgLoadCachedString(CSTID_SET_ARC_THIRD),
1624                   TgLoadCachedString(CSTID_CANCEL),
1625                   TgLoadCachedString(CSTID_CANCEL));
1626          } else {
1627             Msg(TgLoadCachedString(CSTID_SPECIFY_ARC_END));
1628             SetMouseStatus(TgLoadCachedString(CSTID_SET_ARC_END),
1629                   TgLoadCachedString(CSTID_CANCEL),
1630                   TgLoadCachedString(CSTID_CANCEL));
1631          }
1632          PixelToMeasurementUnit(r_buf, ABS_SIZE(radius));
1633          sprintf(buf, "r=%s\ndegree=0", r_buf);
1634          ShowMeasureCursor(saved_x, saved_y, buf, TRUE);
1635          if (done) {
1636             PixelToMeasurementUnit(r_buf, ABS_SIZE(radius));
1637             sprintf(buf, "r=%s\ndegree=0", r_buf);
1638             EndShowMeasureCursor(saved_x, saved_y, buf, TRUE);
1639          }
1640       } else if (input.type == MotionNotify || input.type == KeyPress ||
1641             input.type == KeyRelease) {
1642          if (input.type == KeyPress) {
1643             if (KeyPressEventIsEscape(&input.xkey)) {
1644                XUngrabPointer(mainDisplay, CurrentTime);
1645                HighLightInContinueArc(drawing_arc, OrigX, OrigY, saved_x,
1646                      saved_y, ltx, lty, &w, &h, angle1, angle2, &dx, &dy,
1647                      &radius, FALSE, TRUE, buf);
1648                done = TRUE;
1649                angle2 = 0;
1650                Msg("");
1651             }
1652          }
1653          if (done) {
1654             break;
1655          }
1656          HighLightInContinueArc(drawing_arc, OrigX, OrigY, saved_x, saved_y,
1657                ltx, lty, &w, &h, angle1, angle2, &dx, &dy, &radius,
1658                TRUE, FALSE, buf);
1659          if (input.type == KeyPress || input.type == KeyRelease) {
1660             end_x = saved_x;
1661             end_y = saved_y;
1662          } else {
1663             end_x = input.xmotion.x;
1664             end_y = input.xmotion.y;
1665          }
1666          if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
1667             if (input.type == KeyRelease) {
1668                end_x = input.xkey.x;
1669                end_y = input.xkey.y;
1670             } else {
1671                DiagGridXY(OrigX, OrigY, &end_x, &end_y);
1672             }
1673          }
1674          GridXY(end_x, end_y, &grid_x, &grid_y);
1675          if (grid_x != saved_x || grid_y != saved_y) {
1676             if (drawing_arc) {
1677                if (curChoice == DRAWEDGEARC) {
1678                   /* finished with the endpoints of the arc */
1679                   if (dir != INVALID) {
1680                      XDrawArc(mainDisplay, drawWindow, drawGC, ltx, lty, w, h,
1681                            angle1, angle2);
1682                   }
1683                   saved_x = grid_x;
1684                   saved_y = grid_y;
1685                   if (!GetCenter(OrigX, OrigY, first_x, first_y, grid_x, grid_y,
1686                         &cx, &cy, &dir)) {
1687                      dir = INVALID;
1688                   } else {
1689                      ltx = cx; lty = cy; w = 0; h = 0; angle1 = angle2 = 0;
1690                      PointsToArc(cx, cy, OrigX, OrigY, first_x, first_y,
1691                            dir, TRUE, &ltx, &lty, &w, &h, &angle1, &angle2);
1692                      XDrawArc(mainDisplay, drawWindow, drawGC, ltx, lty, w, h,
1693                            angle1, angle2);
1694                   }
1695                } else {
1696                   /* finished with the center and the first point on the arc */
1697                   if (dir == INVALID) {
1698                      dir = ArcDirection(OrigX, OrigY, first_x, first_y,
1699                            grid_x, grid_y);
1700                      ltx = OrigX; lty = OrigY; w = 0; h = 0;
1701                      angle1 = angle2 = 0;
1702                      if (dir == ARC_CW) {
1703                         Msg(TgLoadCachedString(CSTID_SPECIFY_ARC_END_CW));
1704                      } else {
1705                         Msg(TgLoadCachedString(CSTID_SPECIFY_ARC_END_CCW));
1706                      }
1707                   }
1708                   XDrawArc(mainDisplay, drawWindow, drawGC, ltx, lty, w, h,
1709                         angle1, angle2);
1710                   saved_x = grid_x;
1711                   saved_y = grid_y;
1712                   PointsToArc(OrigX, OrigY, first_x, first_y, saved_x, saved_y,
1713                         dir, TRUE, &ltx, &lty, &w, &h, &angle1, &angle2);
1714                   XDrawArc(mainDisplay, drawWindow, drawGC, ltx, lty, w, h,
1715                         angle1, angle2);
1716                }
1717             } else {
1718                /* looking for the first point on the arc */
1719                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1720                      saved_x, saved_y);
1721                saved_x = grid_x;
1722                saved_y = grid_y;
1723                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1724                      saved_x, saved_y);
1725             }
1726          }
1727          HighLightInContinueArc(drawing_arc, OrigX, OrigY, saved_x, saved_y,
1728                ltx, lty, &w, &h, angle1, angle2, &dx, &dy, &radius,
1729                TRUE, FALSE, buf);
1730          MarkRulers(grid_x, grid_y);
1731          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1732       }
1733    }
1734    SetMouseStatus(NULL, NULL, NULL);
1735    if (angle2 == 0 || dir == INVALID) {
1736       Msg(TgLoadString(STID_NO_ARC_CREATED));
1737    } else {
1738       if (curChoice == DRAWEDGEARC) {
1739          obj_ptr = CreateArcObj(cx, cy, OrigX, OrigY, first_x, first_y,
1740                dir, ltx, lty, w, h, angle1, angle2, FALSE);
1741       } else {
1742          obj_ptr = CreateArcObj(OrigX, OrigY, first_x, first_y, saved_x,
1743                saved_y, dir, ltx, lty, w, h, angle1, angle2, FALSE);
1744       }
1745       RecordNewObjCmd();
1746       DrawArcObj(drawWindow, drawOrigX, drawOrigY, topObj);
1747       arcDrawn = TRUE;
1748       SetFileModified(TRUE);
1749    }
1750    XSync(mainDisplay, False);
1751 }
1752 
DrawArc(input)1753 void DrawArc(input)
1754    XEvent *input;
1755 {
1756    XButtonEvent *button_ev;
1757    int mouse_x, mouse_y, grid_x, grid_y;
1758 
1759    if (input->type != ButtonPress) return;
1760 
1761    button_ev = &(input->xbutton);
1762    if (button_ev->button == Button1) {
1763       mouse_x = button_ev->x;
1764       mouse_y = button_ev->y;
1765       GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
1766       SaveStatusStrings();
1767       ContinueArc(grid_x, grid_y);
1768       RestoreStatusStrings();
1769    }
1770 }
1771 
SaveArcObj(FP,ObjPtr)1772 void SaveArcObj(FP, ObjPtr)
1773    FILE *FP;
1774    register struct ObjRec *ObjPtr;
1775 {
1776    register struct ArcRec *arc_ptr=ObjPtr->detail.a;
1777 
1778    if (fprintf(FP, "arc('%s','',", colorMenuItems[ObjPtr->color]) == EOF) {
1779       writeFileFailed = TRUE;
1780    }
1781    if (fprintf(FP,
1782          "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,",
1783          arc_ptr->fill, arc_ptr->width, arc_ptr->pen, arc_ptr->dash,
1784          arc_ptr->ltx, arc_ptr->lty, arc_ptr->xc, arc_ptr->yc,
1785          arc_ptr->x1, arc_ptr->y1, arc_ptr->x2, arc_ptr->y2,
1786          arc_ptr->dir, arc_ptr->w, arc_ptr->h,
1787          arc_ptr->angle1, arc_ptr->angle2) == EOF) {
1788       writeFileFailed = TRUE;
1789    }
1790    if (fprintf(FP,
1791          "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,'%s','%s','%s',%1d,",
1792          ObjPtr->id, ObjPtr->rotation, arc_ptr->style, arc_ptr->aw,
1793          arc_ptr->ah, ObjPtr->locked, ObjPtr->ctm!=NULL,
1794          ObjPtr->invisible, arc_ptr->width_spec, arc_ptr->aw_spec,
1795          arc_ptr->ah_spec, ObjPtr->trans_pat) == EOF) {
1796       writeFileFailed = TRUE;
1797    }
1798    if (ObjPtr->ctm != NULL && fprintf(FP,
1799          "[\n    %1d,%1d,%1d,%1d,%1d,%1d,%g,%g,%g,%g,%1d,%1d],",
1800          ObjPtr->x, ObjPtr->y,
1801          ObjPtr->orig_obbox.ltx, ObjPtr->orig_obbox.lty,
1802          ObjPtr->orig_obbox.rbx, ObjPtr->orig_obbox.rby,
1803          ObjPtr->ctm->m[CTM_SX], ObjPtr->ctm->m[CTM_SIN],
1804          ObjPtr->ctm->m[CTM_MSIN], ObjPtr->ctm->m[CTM_SY],
1805          ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY]) == EOF) {
1806       writeFileFailed = TRUE;
1807    }
1808    if (serializingFile) SaveCreatorID(FP, ObjPtr, "    ");
1809    SaveAttrs(FP, ObjPtr->lattr);
1810    if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
1811 }
1812 
ReadArcObj(FP,Inbuf,ObjPtr)1813 void ReadArcObj(FP, Inbuf, ObjPtr)
1814    FILE *FP;
1815    char *Inbuf;
1816    struct ObjRec **ObjPtr;
1817 {
1818    register struct ArcRec *arc_ptr;
1819    char color_str[40], bg_color_str[40], * s;
1820    char width_spec[40], aw_spec[40], ah_spec[40];
1821    int fill, trans_pat=FALSE, width=0, pen, dash, ltx, lty, w, h, id=0;
1822    int rotation, new_alloc, style, locked=FALSE;
1823    int aw=origArrowHeadW[0], ah=origArrowHeadH[0];
1824    int xc, yc, x1, y1, x2, y2, dir, angle1, angle2;
1825    int invisible=FALSE, transformed=FALSE;
1826 
1827    *ObjPtr = NULL;
1828 
1829    s = FindChar((int)'(', Inbuf);
1830    s = ParseStr(s, (int)',', color_str, sizeof(color_str));
1831    if (fileVersion >= 37) {
1832       s = ParseStr(s, (int)',', bg_color_str, sizeof(bg_color_str));
1833    }
1834    InitScan(s, ", \t\n");
1835 
1836    style = LS_PLAIN;
1837    rotation = 0;
1838    *width_spec = *aw_spec = *ah_spec = '\0';
1839    if (fileVersion <= 8) {
1840       *ObjPtr = NULL;
1841       sprintf(gszMsgBox, TgLoadString(STID_INVALID_ARC_VERSION), fileVersion);
1842       if (PRTGIF) {
1843          fprintf(stderr, "%s\n", gszMsgBox);
1844       } else {
1845          Msg(gszMsgBox);
1846       }
1847       return;
1848    } else if (fileVersion <= 13) {
1849       if (GETINT("arc", fill,   "fill") == INVALID ||
1850           GETINT("arc", width,  "width") == INVALID ||
1851           GETINT("arc", pen,    "pen") == INVALID ||
1852           GETINT("arc", dash,   "dash") == INVALID ||
1853           GETINT("arc", ltx,    "ltx") == INVALID ||
1854           GETINT("arc", lty,    "lty") == INVALID ||
1855           GETINT("arc", xc,     "xc") == INVALID ||
1856           GETINT("arc", yc,     "yc") == INVALID ||
1857           GETINT("arc", x1,     "x1") == INVALID ||
1858           GETINT("arc", y1,     "y1") == INVALID ||
1859           GETINT("arc", x2,     "x2") == INVALID ||
1860           GETINT("arc", y2,     "y2") == INVALID ||
1861           GETINT("arc", dir,    "direction") == INVALID ||
1862           GETINT("arc", w,      "width") == INVALID ||
1863           GETINT("arc", h,      "height") == INVALID ||
1864           GETINT("arc", angle1, "angle1") == INVALID ||
1865           GETINT("arc", angle2, "angle2") == INVALID ||
1866           GETINT("arc", id,     "id") == INVALID) {
1867          return;
1868       }
1869       if (id >= objId) objId = id+1;
1870    } else if (fileVersion <= 15) {
1871       if (GETINT("arc", fill,     "fill") == INVALID ||
1872           GETINT("arc", width,    "width") == INVALID ||
1873           GETINT("arc", pen,      "pen") == INVALID ||
1874           GETINT("arc", dash,     "dash") == INVALID ||
1875           GETINT("arc", ltx,      "ltx") == INVALID ||
1876           GETINT("arc", lty,      "lty") == INVALID ||
1877           GETINT("arc", xc,       "xc") == INVALID ||
1878           GETINT("arc", yc,       "yc") == INVALID ||
1879           GETINT("arc", x1,       "x1") == INVALID ||
1880           GETINT("arc", y1,       "y1") == INVALID ||
1881           GETINT("arc", x2,       "x2") == INVALID ||
1882           GETINT("arc", y2,       "y2") == INVALID ||
1883           GETINT("arc", dir,      "direction") == INVALID ||
1884           GETINT("arc", w,        "width") == INVALID ||
1885           GETINT("arc", h,        "height") == INVALID ||
1886           GETINT("arc", angle1,   "angle1") == INVALID ||
1887           GETINT("arc", angle2,   "angle2") == INVALID ||
1888           GETINT("arc", id,       "id") == INVALID ||
1889           GETINT("arc", rotation, "rotation") == INVALID) {
1890          return;
1891       }
1892       if (id >= objId) objId = id+1;
1893    } else if (fileVersion <= 16) {
1894       if (GETINT("arc", fill,     "fill") == INVALID ||
1895           GETINT("arc", width,    "width") == INVALID ||
1896           GETINT("arc", pen,      "pen") == INVALID ||
1897           GETINT("arc", dash,     "dash") == INVALID ||
1898           GETINT("arc", ltx,      "ltx") == INVALID ||
1899           GETINT("arc", lty,      "lty") == INVALID ||
1900           GETINT("arc", xc,       "xc") == INVALID ||
1901           GETINT("arc", yc,       "yc") == INVALID ||
1902           GETINT("arc", x1,       "x1") == INVALID ||
1903           GETINT("arc", y1,       "y1") == INVALID ||
1904           GETINT("arc", x2,       "x2") == INVALID ||
1905           GETINT("arc", y2,       "y2") == INVALID ||
1906           GETINT("arc", dir,      "direction") == INVALID ||
1907           GETINT("arc", w,        "width") == INVALID ||
1908           GETINT("arc", h,        "height") == INVALID ||
1909           GETINT("arc", angle1,   "angle1") == INVALID ||
1910           GETINT("arc", angle2,   "angle2") == INVALID ||
1911           GETINT("arc", id,       "id") == INVALID ||
1912           GETINT("arc", rotation, "rotation") == INVALID ||
1913           GETINT("arc", style,    "style") == INVALID) {
1914          return;
1915       }
1916       if (id >= objId) objId = id+1;
1917    } else if (fileVersion <= 25) {
1918       if (GETINT("arc", fill,     "fill") == INVALID ||
1919           GETINT("arc", width,    "width") == INVALID ||
1920           GETINT("arc", pen,      "pen") == INVALID ||
1921           GETINT("arc", dash,     "dash") == INVALID ||
1922           GETINT("arc", ltx,      "ltx") == INVALID ||
1923           GETINT("arc", lty,      "lty") == INVALID ||
1924           GETINT("arc", xc,       "xc") == INVALID ||
1925           GETINT("arc", yc,       "yc") == INVALID ||
1926           GETINT("arc", x1,       "x1") == INVALID ||
1927           GETINT("arc", y1,       "y1") == INVALID ||
1928           GETINT("arc", x2,       "x2") == INVALID ||
1929           GETINT("arc", y2,       "y2") == INVALID ||
1930           GETINT("arc", dir,      "direction") == INVALID ||
1931           GETINT("arc", w,        "width") == INVALID ||
1932           GETINT("arc", h,        "height") == INVALID ||
1933           GETINT("arc", angle1,   "angle1") == INVALID ||
1934           GETINT("arc", angle2,   "angle2") == INVALID ||
1935           GETINT("arc", id,       "id") == INVALID ||
1936           GETINT("arc", rotation, "rotation") == INVALID ||
1937           GETINT("arc", style,    "style") == INVALID ||
1938           GETINT("arc", aw,       "arrow head w") == INVALID ||
1939           GETINT("arc", ah,       "arrow head h") == INVALID) {
1940          return;
1941       }
1942       if (id >= objId) objId = id+1;
1943    } else if (fileVersion <= 32) {
1944       if (GETINT("arc", fill,     "fill") == INVALID ||
1945           GETINT("arc", width,    "width") == INVALID ||
1946           GETINT("arc", pen,      "pen") == INVALID ||
1947           GETINT("arc", dash,     "dash") == INVALID ||
1948           GETINT("arc", ltx,      "ltx") == INVALID ||
1949           GETINT("arc", lty,      "lty") == INVALID ||
1950           GETINT("arc", xc,       "xc") == INVALID ||
1951           GETINT("arc", yc,       "yc") == INVALID ||
1952           GETINT("arc", x1,       "x1") == INVALID ||
1953           GETINT("arc", y1,       "y1") == INVALID ||
1954           GETINT("arc", x2,       "x2") == INVALID ||
1955           GETINT("arc", y2,       "y2") == INVALID ||
1956           GETINT("arc", dir,      "direction") == INVALID ||
1957           GETINT("arc", w,        "width") == INVALID ||
1958           GETINT("arc", h,        "height") == INVALID ||
1959           GETINT("arc", angle1,   "angle1") == INVALID ||
1960           GETINT("arc", angle2,   "angle2") == INVALID ||
1961           GETINT("arc", id,       "id") == INVALID ||
1962           GETINT("arc", rotation, "rotation") == INVALID ||
1963           GETINT("arc", style,    "style") == INVALID ||
1964           GETINT("arc", aw,       "arrow head w") == INVALID ||
1965           GETINT("arc", ah,       "arrow head h") == INVALID ||
1966           GETINT("arc", locked,   "locked") == INVALID) {
1967          return;
1968       }
1969       if (id >= objId) objId = id+1;
1970    } else if (fileVersion <= 34) {
1971       if (GETINT("arc", fill,        "fill") == INVALID ||
1972           GETINT("arc", width,       "width") == INVALID ||
1973           GETINT("arc", pen,         "pen") == INVALID ||
1974           GETINT("arc", dash,        "dash") == INVALID ||
1975           GETINT("arc", ltx,         "ltx") == INVALID ||
1976           GETINT("arc", lty,         "lty") == INVALID ||
1977           GETINT("arc", xc,          "xc") == INVALID ||
1978           GETINT("arc", yc,          "yc") == INVALID ||
1979           GETINT("arc", x1,          "x1") == INVALID ||
1980           GETINT("arc", y1,          "y1") == INVALID ||
1981           GETINT("arc", x2,          "x2") == INVALID ||
1982           GETINT("arc", y2,          "y2") == INVALID ||
1983           GETINT("arc", dir,         "direction") == INVALID ||
1984           GETINT("arc", w,           "width") == INVALID ||
1985           GETINT("arc", h,           "height") == INVALID ||
1986           GETINT("arc", angle1,      "angle1") == INVALID ||
1987           GETINT("arc", angle2,      "angle2") == INVALID ||
1988           GETINT("arc", id,          "id") == INVALID ||
1989           GETINT("arc", rotation,    "rotation") == INVALID ||
1990           GETINT("arc", style,       "style") == INVALID ||
1991           GETINT("arc", aw,          "arrow head w") == INVALID ||
1992           GETINT("arc", ah,          "arrow head h") == INVALID ||
1993           GETINT("arc", locked,      "locked") == INVALID ||
1994           GETINT("arc", transformed, "transformed") == INVALID ||
1995           GETINT("arc", invisible,   "invisible") == INVALID ||
1996           GETSTR("arc", width_spec,  "width_spec") == INVALID ||
1997           GETSTR("arc", aw_spec,     "aw_spec") == INVALID ||
1998           GETSTR("arc", ah_spec,     "ah_spec") == INVALID) {
1999          return;
2000       }
2001       if (id >= objId) objId = id+1;
2002       UtilRemoveQuotes(width_spec);
2003       UtilRemoveQuotes(aw_spec);
2004       UtilRemoveQuotes(ah_spec);
2005    } else {
2006       if (GETINT("arc", fill,        "fill") == INVALID ||
2007           GETINT("arc", width,       "width") == INVALID ||
2008           GETINT("arc", pen,         "pen") == INVALID ||
2009           GETINT("arc", dash,        "dash") == INVALID ||
2010           GETINT("arc", ltx,         "ltx") == INVALID ||
2011           GETINT("arc", lty,         "lty") == INVALID ||
2012           GETINT("arc", xc,          "xc") == INVALID ||
2013           GETINT("arc", yc,          "yc") == INVALID ||
2014           GETINT("arc", x1,          "x1") == INVALID ||
2015           GETINT("arc", y1,          "y1") == INVALID ||
2016           GETINT("arc", x2,          "x2") == INVALID ||
2017           GETINT("arc", y2,          "y2") == INVALID ||
2018           GETINT("arc", dir,         "direction") == INVALID ||
2019           GETINT("arc", w,           "width") == INVALID ||
2020           GETINT("arc", h,           "height") == INVALID ||
2021           GETINT("arc", angle1,      "angle1") == INVALID ||
2022           GETINT("arc", angle2,      "angle2") == INVALID ||
2023           GETINT("arc", id,          "id") == INVALID ||
2024           GETINT("arc", rotation,    "rotation") == INVALID ||
2025           GETINT("arc", style,       "style") == INVALID ||
2026           GETINT("arc", aw,          "arrow head w") == INVALID ||
2027           GETINT("arc", ah,          "arrow head h") == INVALID ||
2028           GETINT("arc", locked,      "locked") == INVALID ||
2029           GETINT("arc", transformed, "transformed") == INVALID ||
2030           GETINT("arc", invisible,   "invisible") == INVALID ||
2031           GETSTR("arc", width_spec,  "width_spec") == INVALID ||
2032           GETSTR("arc", aw_spec,     "aw_spec") == INVALID ||
2033           GETSTR("arc", ah_spec,     "ah_spec") == INVALID ||
2034           GETINT("arc", trans_pat,   "trans_pat") == INVALID) {
2035          return;
2036       }
2037       if (id >= objId) objId = id+1;
2038       UtilRemoveQuotes(width_spec);
2039       UtilRemoveQuotes(aw_spec);
2040       UtilRemoveQuotes(ah_spec);
2041    }
2042 
2043    if (dir == ARC_CCW && angle2 < 0) {
2044       sprintf(gszMsgBox, TgLoadString(STID_WARN_INCONSIST_ARC_DIR));
2045       if (PRTGIF) {
2046          fprintf(stderr, "%s\n", gszMsgBox);
2047       } else {
2048          Msg(gszMsgBox);
2049       }
2050       SetFileModified(TRUE);
2051       dir = ARC_CW;
2052    } else if (dir == ARC_CW && angle2 > 0) {
2053       sprintf(gszMsgBox, TgLoadString(STID_WARN_INCONSIST_ARC_DIR));
2054       if (PRTGIF) {
2055          fprintf(stderr, "%s\n", gszMsgBox);
2056       } else {
2057          Msg(gszMsgBox);
2058       }
2059       SetFileModified(TRUE);
2060       dir = ARC_CCW;
2061    }
2062 
2063    if (fileVersion <= 16 && width <= 6) {
2064       aw = origArrowHeadW[width];
2065       ah = origArrowHeadH[width];
2066       width = origWidthOfLine[width];
2067    }
2068    if (fileVersion <= 32) {
2069       sprintf(width_spec, "%1d", width);
2070       sprintf(aw_spec, "%1d", aw);
2071       sprintf(ah_spec, "%1d", ah);
2072    }
2073    fill = UpgradePenFill(fill);
2074    pen = UpgradePenFill(pen);
2075 
2076    *ObjPtr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
2077    if (*ObjPtr == NULL) FailAllocMessage();
2078    memset(*ObjPtr, 0, sizeof(struct ObjRec));
2079    arc_ptr = (struct ArcRec *)malloc(sizeof(struct ArcRec));
2080    if (arc_ptr == NULL) FailAllocMessage();
2081    memset(arc_ptr, 0, sizeof(struct ArcRec));
2082 
2083    (*ObjPtr)->trans_pat = trans_pat;
2084    arc_ptr->fill = fill;
2085    arc_ptr->width = width;
2086    arc_ptr->aw = aw;
2087    arc_ptr->ah = ah;
2088    UtilStrCpyN(arc_ptr->width_spec, sizeof(arc_ptr->width_spec), width_spec);
2089    UtilStrCpyN(arc_ptr->aw_spec, sizeof(arc_ptr->aw_spec), aw_spec);
2090    UtilStrCpyN(arc_ptr->ah_spec, sizeof(arc_ptr->ah_spec), ah_spec);
2091    arc_ptr->pen = pen;
2092    arc_ptr->dash = dash;
2093    arc_ptr->style = style;
2094 
2095    arc_ptr->xc = xc;         arc_ptr->yc = yc;
2096    arc_ptr->x1 = x1;         arc_ptr->y1 = y1;
2097    arc_ptr->x2 = x2;         arc_ptr->y2 = y2;
2098    arc_ptr->dir = dir;
2099    arc_ptr->ltx = ltx;       arc_ptr->lty = lty;
2100    arc_ptr->w = w;           arc_ptr->h = h;
2101    arc_ptr->angle1 = arc_ptr->a_angle1 = angle1;
2102    arc_ptr->angle2 = arc_ptr->a_angle2 = angle2;
2103 
2104    arc_ptr->rotated_n = 0;
2105    arc_ptr->rotated_vlist = NULL;
2106    arc_ptr->rotated_asn = 0;
2107    arc_ptr->rotated_asvlist = NULL;
2108 
2109    (*ObjPtr)->detail.a = arc_ptr;
2110 
2111    (*ObjPtr)->type = OBJ_ARC;
2112    (*ObjPtr)->color = QuickFindColorIndex(*ObjPtr, color_str, &new_alloc, TRUE);
2113    UtilStrCpyN((*ObjPtr)->color_str, sizeof((*ObjPtr)->color_str), color_str);
2114    (*ObjPtr)->dirty = FALSE;
2115    (*ObjPtr)->id = id;
2116    (*ObjPtr)->rotation = rotation;
2117    (*ObjPtr)->locked = locked;
2118    (*ObjPtr)->ctm = NULL;
2119    (*ObjPtr)->invisible = invisible;
2120    if (fileVersion >= 33 && transformed) {
2121       int real_x=0, real_y=0;
2122       struct BBRec orig_obbox;
2123       char inbuf[MAXSTRING+1];
2124       struct XfrmMtrxRec *ctm;
2125 
2126       (void)fgets(inbuf, MAXSTRING, FP);
2127       scanLineNum++;
2128       InitScan(inbuf, "\t\n, ");
2129 
2130       ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
2131       if (ctm == NULL) FailAllocMessage();
2132       if (GETINT("arc", real_x,           "real_x") == INVALID ||
2133           GETINT("arc", real_y,           "real_y") == INVALID ||
2134           GETINT("arc", orig_obbox.ltx,   "orig_obbox.ltx") == INVALID ||
2135           GETINT("arc", orig_obbox.lty,   "orig_obbox.lty") == INVALID ||
2136           GETINT("arc", orig_obbox.rbx,   "orig_obbox.rbx") == INVALID ||
2137           GETINT("arc", orig_obbox.rby,   "orig_obbox.rby") == INVALID ||
2138           GETDBL("arc", ctm->m[CTM_SX],   "CTM_SX") == INVALID ||
2139           GETDBL("arc", ctm->m[CTM_SIN],  "CTM_SIN") == INVALID ||
2140           GETDBL("arc", ctm->m[CTM_MSIN], "CTM_MSIN") == INVALID ||
2141           GETDBL("arc", ctm->m[CTM_SY],   "CTM_SY") == INVALID ||
2142           GETINT("arc", ctm->t[CTM_TX],   "CTM_TX") == INVALID ||
2143           GETINT("arc", ctm->t[CTM_TY],   "CTM_TY") == INVALID) {
2144          return;
2145       }
2146       (*ObjPtr)->ctm = ctm;
2147       if (ctm != NULL) {
2148          memcpy(&(*ObjPtr)->orig_obbox, &orig_obbox, sizeof(struct BBRec));
2149          (*ObjPtr)->x = real_x;
2150          (*ObjPtr)->y = real_y;
2151          GetTransformedOBBoxOffsetVs(*ObjPtr, (*ObjPtr)->rotated_obbox);
2152       }
2153    }
2154    AdjObjSplineVs(*ObjPtr);
2155    AdjObjBBox(*ObjPtr);
2156 }
2157 
SetArcPropMask(ObjPtr,plMask,plSkip,pProp)2158 void SetArcPropMask(ObjPtr, plMask, plSkip, pProp)
2159    struct ObjRec *ObjPtr;
2160    long *plMask, *plSkip;
2161    struct PropertiesRec *pProp;
2162 {
2163    struct ArcRec *arc_ptr=ObjPtr->detail.a;
2164 
2165    SetCTMPropertyMask(ObjPtr->ctm, plMask, plSkip, pProp);
2166 
2167    SetIntPropertyMask(PROP_MASK_COLOR, ObjPtr->color,
2168          colorMenuItems[ObjPtr->color], plMask, plSkip, pProp);
2169    SetIntPropertyMask(PROP_MASK_WIDTH, arc_ptr->width, arc_ptr->width_spec,
2170          plMask, plSkip, pProp);
2171    SetIntPropertyMask(PROP_MASK_AW, arc_ptr->aw, arc_ptr->aw_spec,
2172          plMask, plSkip, pProp);
2173    SetIntPropertyMask(PROP_MASK_AH, arc_ptr->ah, arc_ptr->ah_spec,
2174          plMask, plSkip, pProp);
2175 
2176    SetIntPropertyMask(PROP_MASK_TRANSPAT, ObjPtr->trans_pat, NULL,
2177          plMask, plSkip, pProp);
2178    SetIntPropertyMask(PROP_MASK_FILL, arc_ptr->fill, NULL,
2179          plMask, plSkip, pProp);
2180    SetIntPropertyMask(PROP_MASK_PEN, arc_ptr->pen, NULL,
2181          plMask, plSkip, pProp);
2182    SetIntPropertyMask(PROP_MASK_DASH, arc_ptr->dash, NULL,
2183          plMask, plSkip, pProp);
2184    SetIntPropertyMask(PROP_MASK_ARROW_STYLE, arc_ptr->style, NULL,
2185          plMask, plSkip, pProp);
2186 }
2187 
FreeArcObj(ObjPtr)2188 void FreeArcObj(ObjPtr)
2189    struct ObjRec *ObjPtr;
2190 {
2191    if (ObjPtr->detail.a->rotated_vlist != NULL) {
2192       free(ObjPtr->detail.a->rotated_vlist);
2193    }
2194    if (ObjPtr->detail.a->rotated_asvlist != NULL) {
2195       free(ObjPtr->detail.a->rotated_asvlist);
2196    }
2197    free(ObjPtr->detail.a);
2198    free(ObjPtr);
2199 }
2200 
2201 static
ParseArcSpec(spec,seperator,radius,dir,theta1,theta2,error_str)2202 int ParseArcSpec(spec, seperator, radius, dir, theta1, theta2, error_str)
2203    char *spec, *error_str;
2204    int seperator, *radius, *dir, *theta1, *theta2;
2205 {
2206    char *s, buf[MAXSTRING], tmp_buf[MAXSTRING];
2207 
2208    strcpy(tmp_buf, spec);
2209 
2210    s = ParseStr(tmp_buf, seperator, buf, sizeof(buf));
2211    if (*s != '\0') {
2212       UtilTrimBlanks(buf);
2213       if (!GetDimension(buf, TRUE, radius)) *s = '\0';
2214    }
2215    if (*s == '\0') {
2216       strcpy(error_str, TgLoadString(STID_INVALID_ARC_SPEC_RADIUS));
2217       return FALSE;
2218    }
2219    s = ParseStr(s, seperator, buf, sizeof(buf));
2220    UtilTrimBlanks(buf);
2221    switch (*buf) {
2222    case '+': *dir = ARC_CW; break;
2223    case '-': *dir = ARC_CCW; break;
2224    default: *s = '\0'; break;
2225    }
2226    if (*s == '\0') {
2227       strcpy(error_str, TgLoadString(STID_INVALID_ARC_SPEC_DIR));
2228       return FALSE;
2229    }
2230    s = ParseStr(s, seperator, buf, sizeof(buf));
2231    if (*s == '\0') {
2232       strcpy(error_str, TgLoadString(STID_INVALID_ARC_SPEC_THETA1));
2233       return FALSE;
2234    }
2235    UtilTrimBlanks(buf);
2236    UtilTrimBlanks(s);
2237    *theta1 = atoi(buf);
2238    *theta2 = atoi(s);
2239 
2240    return TRUE;
2241 }
2242 
MakePreciseArc()2243 void MakePreciseArc()
2244 {
2245    int r = 0, dir = 0, x1, y1, x2, y2, theta1, theta2, angle2=0;
2246    char spec[MAXSTRING], error_str[MAXSTRING];
2247    double angle_in_radian;
2248    struct ObjRec *obj_ptr;
2249 
2250    *spec = '\0';
2251    Dialog(TgLoadString(STID_ARC_SPEC), NULL, spec);
2252    UtilTrimBlanks(spec);
2253    if (*spec == '\0') return;
2254 
2255    TieLooseEnds();
2256    SetCurChoice(NOTHING);
2257    if (topSel!=NULL) { HighLightReverse(); RemoveAllSel(); }
2258 
2259    if (!ParseArcSpec(spec, (int)',', &r, &dir, &theta1, &theta2, error_str) &&
2260          !ParseArcSpec(spec, (int)' ', &r, &dir, &theta1, &theta2, error_str)) {
2261       sprintf(gszMsgBox, error_str, spec);
2262       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2263       return;
2264    }
2265    if (r < 1) {
2266       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_CREATE_ARC_WITH_RAD1),
2267             TOOL_NAME, r);
2268       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2269       return;
2270    }
2271    switch (dir) {
2272    case ARC_CCW: theta1 += 90;        theta2 += 90;        break;
2273    case ARC_CW:  theta1 = -theta1+90; theta2 = -theta2+90; break;
2274    }
2275 
2276    angle_in_radian = theta1 * M_PI / 180;
2277    x1 = round(r*cos(angle_in_radian));
2278    y1 = -round(r*sin(angle_in_radian));
2279    angle_in_radian = theta2 * M_PI / 180;
2280    x2 = round(r*cos(angle_in_radian));
2281    y2 = -round(r*sin(angle_in_radian));
2282 
2283    while (theta1 < 0) theta1 += 360;
2284    while (theta2 > theta1) theta2 -= 360;
2285    while (theta2 < theta1) theta2 += 360;
2286 
2287    switch (dir) {
2288    case ARC_CCW:
2289       angle2 = theta2-theta1;
2290       if (angle2 == 0) angle2 = 360;
2291       break;
2292    case ARC_CW:
2293       angle2 = theta2-theta1-360;
2294       break;
2295    }
2296    obj_ptr = CreateArcObj(0, 0, x1, y1, x2, y2, dir, -r, -r, r*2, r*2,
2297          theta1*64, angle2*64, FALSE);
2298 
2299    PlaceTopObj(obj_ptr, NULL, NULL);
2300    SelectTopObj();
2301    RecordNewObjCmd();
2302    SetFileModified(TRUE);
2303    justDupped = FALSE;
2304 }
2305 
PreciseRotateAnArc()2306 void PreciseRotateAnArc()
2307 {
2308 }
2309