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, <x, <y, &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, <x, <y, &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