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/rect.c,v 1.6 2011/05/16 16:21:59 william Exp $
19 */
20
21 #define _INCLUDE_FROM_RECT_C_
22
23 #include "tgifdefs.h"
24
25 #include "arc.e"
26 #include "color.e"
27 #include "dialog.e"
28 #include "drawing.e"
29 #include "file.e"
30 #include "msg.e"
31 #include "poly.e"
32 #include "ps.e"
33 #include "rect.e"
34 #include "setup.e"
35 #include "spline.e"
36 #include "strtbl.e"
37
DumpRectPath(FP,LtX,LtY,RbX,RbY,Indent,LastLF)38 void DumpRectPath(FP, LtX, LtY, RbX, RbY, Indent, LastLF)
39 FILE *FP;
40 int LtX, LtY, RbX, RbY, Indent;
41 {
42 register int i;
43
44 if (psUseShortHand) {
45 for (i=0; i < Indent; i++) fprintf(FP, " ");
46 fprintf(FP, "%s %1d %1d %s %1d %1d %s %1d %1d %s %1d %1d %s %s",
47 gPsCmd[PS_NEWPATH],
48 LtX, LtY, gPsCmd[PS_MOVETO], RbX, LtY, gPsCmd[PS_LINETO],
49 RbX, RbY, gPsCmd[PS_LINETO], LtX, RbY, gPsCmd[PS_LINETO],
50 gPsCmd[PS_CLOSEPATH]);
51 } else {
52 for (i=0; i < Indent; i++) fprintf(FP, " ");
53 fprintf(FP, "%s\n", gPsCmd[PS_NEWPATH]);
54 for (i=0; i < Indent; i++) fprintf(FP, " ");
55 fprintf(FP, " %1d %1d %s ", LtX, LtY, gPsCmd[PS_MOVETO]);
56 fprintf(FP, "%1d %1d %s ", RbX, LtY, gPsCmd[PS_LINETO]);
57 fprintf(FP, "%1d %1d %s ", RbX, RbY, gPsCmd[PS_LINETO]);
58 fprintf(FP, "%1d %1d %s\n", LtX, RbY, gPsCmd[PS_LINETO]);
59 for (i=0; i < Indent; i++) fprintf(FP, " ");
60 fprintf(FP, "%s", gPsCmd[PS_CLOSEPATH]);
61 }
62 fprintf(FP, "%s", (LastLF ? "\n" : " "));
63 }
64
SetPoint(pt,x,y)65 void SetPoint(pt, x, y)
66 IntPoint *pt;
67 int x, y;
68 {
69 pt->x = x;
70 pt->y = y;
71 }
72
ClipRect(bbox,w,h)73 void ClipRect(bbox, w, h)
74 struct BBRec *bbox;
75 int w, h;
76 {
77 if (bbox->ltx < 0) {
78 bbox->rbx += bbox->ltx;
79 bbox->ltx = 0;
80 }
81 if (bbox->lty < 0) {
82 bbox->rby += bbox->lty;
83 bbox->lty = 0;
84 }
85 if (bbox->rbx >= w) {
86 bbox->rbx = w - 1;
87 }
88 if (bbox->rby >= h) {
89 bbox->rby = h - 1;
90 }
91 }
92
CompareRect(pBBox1,pBBox2)93 int CompareRect(pBBox1, pBBox2)
94 struct BBRec *pBBox1, *pBBox2;
95 {
96 return memcmp(pBBox1, pBBox2, sizeof(struct BBRec));
97 }
98
SetRotateVs(vs,ltx,lty,rbx,rby)99 void SetRotateVs(vs, ltx, lty, rbx, rby)
100 XPoint *vs; /* array of 5 points */
101 int ltx, lty, rbx, rby;
102 {
103 vs[0].x = vs[4].x = ltx; vs[0].y = vs[4].y = lty;
104 vs[1].x = rbx; vs[1].y = lty;
105 vs[2].x = rbx; vs[2].y = rby;
106 vs[3].x = ltx; vs[3].y = rby;
107 }
108
SetBBRec(bbox,ltx,lty,rbx,rby)109 void SetBBRec(bbox, ltx, lty, rbx, rby)
110 struct BBRec *bbox;
111 int ltx, lty, rbx, rby;
112 {
113 if (ltx <= rbx) {
114 bbox->ltx = ltx;
115 bbox->rbx = rbx;
116 } else {
117 bbox->ltx = rbx;
118 bbox->rbx = ltx;
119 }
120 if (lty <= rby) {
121 bbox->lty = lty;
122 bbox->rby = rby;
123 } else {
124 bbox->lty = rby;
125 bbox->rby = lty;
126 }
127 }
128
ConcatCTM(ctm,orig_ctm,new_ctm)129 void ConcatCTM(ctm, orig_ctm, new_ctm)
130 struct XfrmMtrxRec *ctm, *orig_ctm, *new_ctm;
131 /* Note: CTM_SX, CTM_SIN, CTM_MSIN, and CTM_SY are scaled 1000 times */
132 /* while CTM_TX and CTM_TY are not scaled */
133 {
134 new_ctm->m[0] = ((double)(ctm->m[0]*orig_ctm->m[0] +
135 ctm->m[1]*orig_ctm->m[2]))/1000.0;
136 new_ctm->m[1] = ((double)(ctm->m[0]*orig_ctm->m[1] +
137 ctm->m[1]*orig_ctm->m[3]))/1000.0;
138 new_ctm->m[2] = ((double)(ctm->m[2]*orig_ctm->m[0] +
139 ctm->m[3]*orig_ctm->m[2]))/1000.0;
140 new_ctm->m[3] = ((double)(ctm->m[2]*orig_ctm->m[1] +
141 ctm->m[3]*orig_ctm->m[3]))/1000.0;
142 new_ctm->t[CTM_TX] = round(((double)(ctm->t[CTM_TX]*orig_ctm->m[0] +
143 ctm->t[CTM_TY]*orig_ctm->m[2]))/1000.0) + orig_ctm->t[CTM_TX];
144 new_ctm->t[CTM_TY] = round(((double)(ctm->t[CTM_TX]*orig_ctm->m[1] +
145 ctm->t[CTM_TY]*orig_ctm->m[3]))/1000.0) + orig_ctm->t[CTM_TY];
146 }
147
TransformDoublePointThroughCTM(X,Y,ctm,NewX,NewY)148 void TransformDoublePointThroughCTM(X, Y, ctm, NewX, NewY)
149 double X, Y, *NewX, *NewY;
150 struct XfrmMtrxRec *ctm;
151 {
152 *NewX = (X*((double)ctm->m[0]) + Y*((double)ctm->m[2]))/1000.0 +
153 (double)ctm->t[CTM_TX];
154 *NewY = (X*((double)ctm->m[1]) + Y*((double)ctm->m[3]))/1000.0 +
155 (double)ctm->t[CTM_TY];
156 }
157
TransformPointThroughCTM(X,Y,ctm,NewX,NewY)158 void TransformPointThroughCTM(X, Y, ctm, NewX, NewY)
159 int X, Y, *NewX, *NewY;
160 struct XfrmMtrxRec *ctm;
161 {
162 double x=(double)0, y=(double)0;
163
164 x = ((double)(((double)X)*ctm->m[0]+((double)Y)*ctm->m[2])) / 1000.0 +
165 (double)(ctm->t[CTM_TX]);
166 y = ((double)(((double)X)*ctm->m[1]+((double)Y)*ctm->m[3])) / 1000.0 +
167 (double)(ctm->t[CTM_TY]);
168 *NewX = round(x);
169 *NewY = round(y);
170 }
171
ReverseTransformDoublePointThroughCTM(X,Y,ctm,NewDx,NewDy)172 void ReverseTransformDoublePointThroughCTM(X, Y, ctm, NewDx, NewDy)
173 double X, Y, *NewDx, *NewDy;
174 struct XfrmMtrxRec *ctm;
175 /*
176 * [ a b 0 ]
177 * Let ctm = [ c d 0 ]
178 * [ e f 1 ]
179 *
180 * d(X-e) - c(Y-f)
181 * *NewX = -----------------
182 * ad - bc
183 *
184 * b(X-e) - a(Y-f)
185 * *NewY = -----------------
186 * bc - ad
187 */
188 {
189 double ad_bc=ctm->m[0]*ctm->m[3]-ctm->m[1]*ctm->m[2];
190 double term_1=X-((double)(ctm->t[CTM_TX]));
191 double term_2=Y-((double)(ctm->t[CTM_TY]));
192
193 *NewDx = ((double)1000.0) *
194 ((double)(ctm->m[3]*term_1 - ctm->m[2]*term_2)) / ((double)ad_bc);
195 *NewDy = ((double)1000.0) *
196 ((double)(ctm->m[0]*term_2 - ctm->m[1]*term_1)) / ((double)(ad_bc));
197 }
198
ReverseTransformPointThroughCTM(X,Y,ctm,NewX,NewY)199 void ReverseTransformPointThroughCTM(X, Y, ctm, NewX, NewY)
200 int X, Y, *NewX, *NewY;
201 struct XfrmMtrxRec *ctm;
202 {
203 double x=(double)0, y=(double)0;
204
205 ReverseTransformDoublePointThroughCTM(((double)X), ((double)Y), ctm, &x, &y);
206 *NewX = round(x);
207 *NewY = round(y);
208 }
209
TransformObjectV(ObjPtr,VIn,VOut)210 void TransformObjectV(ObjPtr, VIn, VOut)
211 struct ObjRec *ObjPtr;
212 IntPoint *VIn, *VOut;
213 {
214 int x, y;
215
216 TransformPointThroughCTM(VIn->x-ObjPtr->x, VIn->y-ObjPtr->y, ObjPtr->ctm,
217 &x, &y);
218 VOut->x = x + ObjPtr->x;
219 VOut->y = y + ObjPtr->y;
220 }
221
ReversedTransformObjectV(ObjPtr,VIn,VOut)222 void ReversedTransformObjectV(ObjPtr, VIn, VOut)
223 struct ObjRec *ObjPtr;
224 IntPoint *VIn, *VOut;
225 {
226 int x, y;
227
228 ReverseTransformPointThroughCTM(VIn->x-ObjPtr->x, VIn->y-ObjPtr->y,
229 ObjPtr->ctm, &x, &y);
230 VOut->x = x + ObjPtr->x;
231 VOut->y = y + ObjPtr->y;
232 }
233
TransformOffsetBBoxThroughCTM(bbox,ctm,vs)234 void TransformOffsetBBoxThroughCTM(bbox, ctm, vs)
235 struct BBRec *bbox;
236 struct XfrmMtrxRec *ctm;
237 IntPoint *vs; /* array of 5 points */
238 {
239 int x, y;
240
241 TransformPointThroughCTM(bbox->ltx, bbox->lty, ctm, &x, &y);
242 vs[0].x = vs[4].x = x; vs[0].y = vs[4].y = y;
243 TransformPointThroughCTM(bbox->rbx, bbox->lty, ctm, &x, &y);
244 vs[1].x = x; vs[1].y = y;
245 TransformPointThroughCTM(bbox->rbx, bbox->rby, ctm, &x, &y);
246 vs[2].x = x; vs[2].y = y;
247 TransformPointThroughCTM(bbox->ltx, bbox->rby, ctm, &x, &y);
248 vs[3].x = x; vs[3].y = y;
249 }
250
GetTransformedOBBoxOffsetVs(ObjPtr,Vs)251 void GetTransformedOBBoxOffsetVs(ObjPtr, Vs)
252 struct ObjRec *ObjPtr;
253 XPoint *Vs; /* array of 5 points */
254 {
255 int x, y;
256 struct BBRec obbox;
257 IntPoint vs[5];
258
259 if (ObjPtr->ctm == NULL) return;
260
261 obbox.ltx = ObjPtr->orig_obbox.ltx - ObjPtr->x;
262 obbox.lty = ObjPtr->orig_obbox.lty - ObjPtr->y;
263 obbox.rbx = ObjPtr->orig_obbox.rbx - ObjPtr->x;
264 obbox.rby = ObjPtr->orig_obbox.rby - ObjPtr->y;
265 TransformOffsetBBoxThroughCTM(&obbox, ObjPtr->ctm, vs);
266 x = OFFSET_X(vs[0].x + ObjPtr->x);
267 y = OFFSET_Y(vs[0].y + ObjPtr->y);
268 Vs[0].x = Vs[4].x = x; Vs[0].y = Vs[4].y = y;
269 x = OFFSET_X(vs[1].x + ObjPtr->x);
270 y = OFFSET_Y(vs[1].y + ObjPtr->y);
271 Vs[1].x = x; Vs[1].y = y;
272 x = OFFSET_X(vs[2].x + ObjPtr->x);
273 y = OFFSET_Y(vs[2].y + ObjPtr->y);
274 Vs[2].x = x; Vs[2].y = y;
275 x = OFFSET_X(vs[3].x + ObjPtr->x);
276 y = OFFSET_Y(vs[3].y + ObjPtr->y);
277 Vs[3].x = x; Vs[3].y = y;
278 }
279
GetTransformedOBBoxAbsVs(ObjPtr,Vs)280 void GetTransformedOBBoxAbsVs(ObjPtr, Vs)
281 struct ObjRec *ObjPtr;
282 IntPoint *Vs; /* array of 5 points */
283 {
284 int x, y;
285 struct BBRec obbox;
286 IntPoint vs[5];
287
288 if (ObjPtr->ctm == NULL) return;
289
290 obbox.ltx = ObjPtr->orig_obbox.ltx - ObjPtr->x;
291 obbox.lty = ObjPtr->orig_obbox.lty - ObjPtr->y;
292 obbox.rbx = ObjPtr->orig_obbox.rbx - ObjPtr->x;
293 obbox.rby = ObjPtr->orig_obbox.rby - ObjPtr->y;
294 TransformOffsetBBoxThroughCTM(&obbox, ObjPtr->ctm, vs);
295 x = vs[0].x + ObjPtr->x; y = vs[0].y + ObjPtr->y;
296 Vs[0].x = Vs[4].x = x; Vs[0].y = Vs[4].y = y;
297 x = vs[1].x + ObjPtr->x; y = vs[1].y + ObjPtr->y;
298 Vs[1].x = x; Vs[1].y = y;
299 x = vs[2].x + ObjPtr->x; y = vs[2].y + ObjPtr->y;
300 Vs[2].x = x; Vs[2].y = y;
301 x = vs[3].x + ObjPtr->x; y = vs[3].y + ObjPtr->y;
302 Vs[3].x = x; Vs[3].y = y;
303 }
304
SetCTM(ObjPtr,ctm)305 void SetCTM(ObjPtr, ctm)
306 struct ObjRec *ObjPtr;
307 struct XfrmMtrxRec *ctm;
308 /* ObjPtr->ctm must be NULL */
309 {
310 IntPoint abs_obj_obbox_vs[5];
311 struct XfrmMtrxRec new_ctm;
312 int ltx, lty, rbx, rby;
313
314 if (ObjPtr->ctm != NULL) {
315 MsgBox(TgLoadString(STID_ERR_SETCTM_CALLED_CTM_NONNULL), TOOL_NAME,
316 INFO_MB);
317 free(ObjPtr->ctm);
318 }
319 memcpy(&ObjPtr->orig_obbox, &ObjPtr->obbox, sizeof(struct BBRec));
320 if (ObjPtr->type == OBJ_TEXT) {
321 memcpy(&ObjPtr->detail.t->orig_bbox, &ObjPtr->bbox,
322 sizeof(struct BBRec));
323 }
324 ObjPtr->ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
325 if (ObjPtr->ctm == NULL) FailAllocMessage();
326 ObjPtr->ctm->m[CTM_SX] = ObjPtr->ctm->m[CTM_SY] = (double)1000;
327 ObjPtr->ctm->m[CTM_SIN] = ObjPtr->ctm->m[CTM_MSIN] = (double)0;
328 ObjPtr->ctm->t[CTM_TX] = ObjPtr->ctm->t[CTM_TY] = 0;
329 ConcatCTM(ObjPtr->ctm, ctm, &new_ctm);
330 memcpy(ObjPtr->ctm, &new_ctm, sizeof(struct XfrmMtrxRec));
331
332 GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
333
334 ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
335 min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
336 rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
337 max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
338 lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
339 min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
340 rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
341 max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
342
343 ObjPtr->obbox.ltx = ltx; ObjPtr->obbox.lty = lty;
344 ObjPtr->obbox.rbx = rbx; ObjPtr->obbox.rby = rby;
345 GetTransformedOBBoxOffsetVs(ObjPtr, ObjPtr->rotated_obbox);
346 }
347
ExpandExtents(pBBox,pnLtX,pnLtY,pnRbX,pnRbY)348 void ExpandExtents(pBBox, pnLtX, pnLtY, pnRbX, pnRbY)
349 struct BBRec *pBBox;
350 int *pnLtX, *pnLtY, *pnRbX, *pnRbY;
351 {
352 if (pBBox->ltx < (*pnLtX)) (*pnLtX) = pBBox->ltx;
353 if (pBBox->lty < (*pnLtY)) (*pnLtY) = pBBox->lty;
354 if (pBBox->rbx > (*pnRbX)) (*pnRbX) = pBBox->rbx;
355 if (pBBox->rby > (*pnRbY)) (*pnRbY) = pBBox->rby;
356 }
357
ExpandBBox(pBBox,pBBoxToExpand)358 void ExpandBBox(pBBox, pBBoxToExpand)
359 struct BBRec *pBBox, *pBBoxToExpand;
360 {
361 if (pBBox->ltx < pBBoxToExpand->ltx) pBBoxToExpand->ltx = pBBox->ltx;
362 if (pBBox->lty < pBBoxToExpand->lty) pBBoxToExpand->lty = pBBox->lty;
363 if (pBBox->rbx > pBBoxToExpand->rbx) pBBoxToExpand->rbx = pBBox->rbx;
364 if (pBBox->rby > pBBoxToExpand->rby) pBBoxToExpand->rby = pBBox->rby;
365 }
366
InflateBBox(pBBoxIn,dx,dy,pBBoxOut)367 void InflateBBox(pBBoxIn, dx, dy, pBBoxOut)
368 struct BBRec *pBBoxIn, *pBBoxOut;
369 int dx, dy;
370 {
371 int ltx=pBBoxIn->ltx+dx, lty=pBBoxIn->lty+dy;
372 int rbx=pBBoxIn->rbx-dx, rby=pBBoxIn->rby-dy;
373
374 SetBBRec(pBBoxOut, ltx, lty, rbx, rby);
375 }
376
OffsetBBox(pBBoxIn,dx,dy,pBBoxOut)377 void OffsetBBox(pBBoxIn, dx, dy, pBBoxOut)
378 struct BBRec *pBBoxIn, *pBBoxOut;
379 int dx, dy;
380 {
381 int ltx=pBBoxIn->ltx+dx, lty=pBBoxIn->lty+dy;
382 int rbx=pBBoxIn->rbx+dx, rby=pBBoxIn->rby+dy;
383
384 SetBBRec(pBBoxOut, ltx, lty, rbx, rby);
385 }
386
BBoxIntersect(Rect1,Rect2)387 int BBoxIntersect(Rect1, Rect2)
388 struct BBRec Rect1, Rect2;
389 {
390 if (Rect1.ltx < Rect2.ltx) {
391 if (Rect1.lty < Rect2.lty) {
392 return (Rect1.rbx >= Rect2.ltx && Rect1.rby >= Rect2.lty);
393 } else {
394 return (Rect1.rbx >= Rect2.ltx && Rect1.lty <= Rect2.rby);
395 }
396 } else {
397 if (Rect1.lty < Rect2.lty) {
398 return (Rect1.ltx <= Rect2.rbx && Rect1.rby >= Rect2.lty);
399 } else {
400 return (Rect1.ltx <= Rect2.rbx && Rect1.lty <= Rect2.rby);
401 }
402 }
403 }
404
IntersectRect(BBox1,BBox2,BBox3)405 int IntersectRect(BBox1, BBox2, BBox3)
406 struct BBRec BBox1, BBox2, *BBox3;
407 /* returns the intersection of BBox1 and BBox2 in BBox3 */
408 {
409 if (BBoxIntersect(BBox1, BBox2)) {
410 BBox3->ltx = max(BBox1.ltx,BBox2.ltx);
411 BBox3->lty = max(BBox1.lty,BBox2.lty);
412 BBox3->rbx = min(BBox1.rbx,BBox2.rbx);
413 BBox3->rby = min(BBox1.rby,BBox2.rby);
414 return TRUE;
415 }
416 return FALSE;
417 }
418
UnionRect(p_bbox1,p_bbox2,p_union_bbox)419 void UnionRect(p_bbox1, p_bbox2, p_union_bbox)
420 struct BBRec *p_bbox1, *p_bbox2, *p_union_bbox;
421 {
422 p_union_bbox->ltx = min(p_bbox1->ltx, p_bbox2->ltx);
423 p_union_bbox->lty = min(p_bbox1->lty, p_bbox2->lty);
424 p_union_bbox->rbx = max(p_bbox1->rbx, p_bbox2->rbx);
425 p_union_bbox->rby = max(p_bbox1->rby, p_bbox2->rby);
426 }
427
Inside(BBox1,BBox2)428 int Inside(BBox1, BBox2)
429 struct BBRec BBox1, BBox2;
430 /* returns TRUE if BBox1 is inside BBox2 */
431 {
432 return (BBox1.ltx >= BBox2.ltx && BBox1.lty >= BBox2.lty &&
433 BBox1.rbx <= BBox2.rbx && BBox1.rby <= BBox2.rby);
434 }
435
PointInBBox(X,Y,Rect)436 int PointInBBox(X, Y, Rect)
437 int X, Y;
438 struct BBRec Rect;
439 {
440 return (X >= Rect.ltx && Y >= Rect.lty && X <= Rect.rbx && Y <= Rect.rby);
441 }
442
PointInIntPolygon(X,Y,NumPts,IV)443 int PointInIntPolygon(X, Y, NumPts, IV)
444 int X, Y, NumPts;
445 IntPoint *IV;
446 {
447 register double x1, x2, y1, y2;
448 double m, y_int;
449 int n, count=0;
450
451 x2 = (double)IV[0].x;
452 y2 = (double)IV[0].y;
453 for (n=0; n < NumPts-1; n++) {
454 x1 = x2;
455 y1 = y2;
456 x2 = (double)(IV[n+1].x);
457 y2 = (double)(IV[n+1].y);
458 if (x2 == x1) {
459 if (X == x1 && Y >= min(y1,y2) && Y <= max(y1,y2)) count++;
460 continue;
461 }
462 if (x2 > x1) {
463 if (X >= x2 || X < x1) continue;
464 } else {
465 if (X > x1 || X <= x2) continue;
466 }
467 m = (y1 - y2) / (x1 - x2);
468 y_int = m * X + (y1 - m * x1);
469 if (Y <= y_int) {
470 if (fabs(X-x1) < INT_TOL) {
471 double x3=(double)((n == 0) ? IV[NumPts-2].x : IV[n-1].x);
472
473 if ((x2 > X && X > x3) || (x3 > X && X > x2)) count++;
474 } else {
475 count++;
476 }
477 }
478 }
479 return (count & 0x1);
480 }
481
PointInPolygon(X,Y,NumPts,V)482 int PointInPolygon(X, Y, NumPts, V)
483 int X, Y, NumPts;
484 XPoint *V;
485 {
486 register double x1, x2, y1, y2;
487 double m, y_int;
488 int n, count=0;
489
490 x2 = (double)V[0].x;
491 y2 = (double)V[0].y;
492 for (n=0; n < NumPts-1; n++) {
493 x1 = x2;
494 y1 = y2;
495 x2 = (double)(V[n+1].x);
496 y2 = (double)(V[n+1].y);
497 if (x2 == x1) {
498 if (X == x1 && Y >= min(y1,y2) && Y <= max(y1,y2)) count++;
499 continue;
500 }
501 if (x2 > x1) {
502 if (X >= x2 || X < x1) continue;
503 } else {
504 if (X > x1 || X <= x2) continue;
505 }
506 m = (y1 - y2) / (x1 - x2);
507 y_int = m * X + (y1 - m * x1);
508 if (Y <= y_int) {
509 if (fabs(X-x1) < INT_TOL) {
510 double x3=(double)((n == 0) ? V[NumPts-2].x : V[n-1].x);
511
512 if ((x2 > X && X > x3) || (x3 > X && X > x2)) count++;
513 } else {
514 count++;
515 }
516 }
517 }
518 return (count & 0x1);
519 }
520
PointOnPoly(X,Y,NumPts,V,W)521 int PointOnPoly(X, Y, NumPts, V, W)
522 int X, Y, NumPts, W;
523 XPoint *V;
524 {
525 register double x1, x2, y1, y2;
526 double x_int, y_int, dx, dy, abs_dx, abs_dy, real_w;
527 int n, horizontal;
528
529 x2 = (double)V[0].x;
530 y2 = (double)V[0].y;
531 for (n=0; n < NumPts-1; n++) {
532 x1 = x2;
533 y1 = y2;
534 x2 = (double)(V[n+1].x);
535 y2 = (double)(V[n+1].y);
536
537 if (V[n].x==V[n+1].x && V[n].y==V[n+1].y) continue;
538
539 dx = x2 - x1; abs_dx = fabs(dx);
540 dy = y2 - y1; abs_dy = fabs(dy);
541 horizontal = (abs_dx >= abs_dy);
542
543 if (horizontal) {
544 if (x2 >= x1) {
545 if (X < x1 || X > x2) continue;
546 } else {
547 if (X < x2 || X > x1) continue;
548 }
549 real_w = (double)sqrt(abs_dx*abs_dx+abs_dy*abs_dy)*((double)W)/abs_dx;
550 } else {
551 if (y2 >= y1) {
552 if (Y < y1 || Y > y2) continue;
553 } else {
554 if (Y < y2 || Y > y1) continue;
555 }
556 real_w = (double)sqrt(abs_dx*abs_dx+abs_dy*abs_dy)*((double)W)/abs_dy;
557 }
558
559 if (abs_dx >= abs_dy) {
560 /* kind of a horizontal segment */
561 y_int = y1+(((double)X)-x1)*dy/dx;
562 if ((double)fabs((double)Y-y_int) <= (real_w+4)) return TRUE;
563 } else {
564 /* kind of a vertical segment */
565 x_int = x1+(((double)Y)-y1)*dx/dy;
566 if ((double)fabs((double)X-x_int) <= (real_w+4)) return TRUE;
567 }
568 }
569 return FALSE;
570 }
571
FindGoodText(XOff,YOff,TextObj)572 int FindGoodText(XOff, YOff, TextObj)
573 int XOff, YOff;
574 struct ObjRec *TextObj;
575 /* XOff and YOff are screen offsets */
576 {
577 if (colorLayers && TextObj->tmp_parent == NULL &&
578 !ObjInVisibleLayer(TextObj)) {
579 return FALSE;
580 }
581 if (TextObj->ctm == NULL) {
582 return TRUE;
583 } else {
584 return PointInPolygon(XOff, YOff, 5, TextObj->rotated_obbox);
585 }
586 }
587
FindGoodXBm(XOff,YOff,XBmObj)588 int FindGoodXBm(XOff, YOff, XBmObj)
589 int XOff, YOff;
590 struct ObjRec *XBmObj;
591 /* XOff and YOff are screen offsets */
592 {
593 struct BBRec bbox;
594
595 if (colorLayers && XBmObj->tmp_parent == NULL &&
596 !ObjInVisibleLayer(XBmObj)) {
597 return FALSE;
598 }
599 bbox.ltx = OFFSET_X(XBmObj->obbox.ltx)-3;
600 bbox.lty = OFFSET_Y(XBmObj->obbox.lty)-3;
601 bbox.rbx = OFFSET_X(XBmObj->obbox.rbx)+3;
602 bbox.rby = OFFSET_Y(XBmObj->obbox.rby)+3;
603 if (XBmObj->ctm == NULL) {
604 return PointInBBox(XOff, YOff, bbox);
605 } else {
606 return PointInPolygon(XOff, YOff, 5, XBmObj->rotated_obbox);
607 }
608 }
609
FindGoodXPm(XOff,YOff,XPmObj)610 int FindGoodXPm(XOff, YOff, XPmObj)
611 int XOff, YOff;
612 struct ObjRec *XPmObj;
613 /* XOff and YOff are screen offsets */
614 {
615 struct BBRec bbox;
616
617 if (colorLayers && XPmObj->tmp_parent == NULL &&
618 !ObjInVisibleLayer(XPmObj)) {
619 return FALSE;
620 }
621 bbox.ltx = OFFSET_X(XPmObj->obbox.ltx)-3;
622 bbox.lty = OFFSET_Y(XPmObj->obbox.lty)-3;
623 bbox.rbx = OFFSET_X(XPmObj->obbox.rbx)+3;
624 bbox.rby = OFFSET_Y(XPmObj->obbox.rby)+3;
625 if (XPmObj->ctm == NULL) {
626 return PointInBBox(XOff, YOff, bbox);
627 } else {
628 return PointInPolygon(XOff, YOff, 5, XPmObj->rotated_obbox);
629 }
630 }
631
FindGoodBox(XOff,YOff,BoxObj)632 int FindGoodBox(XOff, YOff, BoxObj)
633 int XOff, YOff;
634 struct ObjRec *BoxObj;
635 /* XOff and YOff are screen offsets */
636 {
637 struct BBRec bbox;
638 int w;
639
640 if (colorLayers && BoxObj->tmp_parent == NULL &&
641 !ObjInVisibleLayer(BoxObj)) {
642 return FALSE;
643 }
644 bbox.ltx = OFFSET_X(BoxObj->obbox.ltx)-3;
645 bbox.lty = OFFSET_Y(BoxObj->obbox.lty)-3;
646 bbox.rbx = OFFSET_X(BoxObj->obbox.rbx)+3;
647 bbox.rby = OFFSET_Y(BoxObj->obbox.rby)+3;
648 if (!PointInBBox(XOff, YOff, bbox)) return FALSE;
649
650 if (BoxObj->ctm == NULL) {
651 if (!(BoxObj->detail.b->fill == NONEPAT ||
652 (BoxObj->detail.b->fill == BACKPAT && BoxObj->trans_pat))) {
653 return TRUE;
654 }
655 w = HALF_W(BoxObj->detail.b->width);
656 bbox.ltx = OFFSET_X(BoxObj->obbox.ltx+w)+3;
657 bbox.lty = OFFSET_Y(BoxObj->obbox.lty+w)+3;
658 bbox.rbx = OFFSET_X(BoxObj->obbox.rbx-w)-3;
659 bbox.rby = OFFSET_Y(BoxObj->obbox.rby-w)-3;
660 return (!PointInBBox(XOff, YOff, bbox));
661 } else {
662 if (!(BoxObj->detail.b->fill == NONEPAT ||
663 (BoxObj->detail.b->fill == BACKPAT && BoxObj->trans_pat))) {
664 if (PointInPolygon(XOff, YOff, 5, BoxObj->rotated_obbox)) {
665 return TRUE;
666 }
667 }
668 return PointOnPoly(XOff, YOff, 5, BoxObj->rotated_obbox,
669 ZOOMED_HALF_W(BoxObj->detail.b->width));
670 }
671 }
672
FindGoodRCBox(XOff,YOff,RCBoxObj)673 int FindGoodRCBox(XOff, YOff, RCBoxObj)
674 int XOff, YOff;
675 struct ObjRec *RCBoxObj;
676 /* XOff and YOff are screen offsets */
677 {
678 struct RCBoxRec *rcbox_ptr=RCBoxObj->detail.rcb;
679 int fill=rcbox_ptr->fill, trans_pat=RCBoxObj->trans_pat;
680
681 if (colorLayers && RCBoxObj->tmp_parent == NULL &&
682 !ObjInVisibleLayer(RCBoxObj)) {
683 return FALSE;
684 }
685 if (RCBoxObj->ctm == NULL) {
686 register struct BBRec *obbox;
687 register struct BBRec bbox;
688 int w, r;
689
690 obbox = &(RCBoxObj->obbox);
691
692 bbox.ltx = OFFSET_X(obbox->ltx)-3;
693 bbox.lty = OFFSET_Y(obbox->lty)-3;
694 bbox.rbx = OFFSET_X(obbox->rbx)+3;
695 bbox.rby = OFFSET_Y(obbox->rby)+3;
696 if (!PointInBBox(XOff, YOff, bbox)) return FALSE;
697
698 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
699 return TRUE;
700 }
701 r = rcbox_ptr->radius;
702 w = HALF_W(rcbox_ptr->width);
703
704 bbox.ltx = OFFSET_X(obbox->ltx+w)+3; bbox.lty = OFFSET_Y(obbox->lty+r)+3;
705 bbox.rbx = OFFSET_X(obbox->rbx-w)-3; bbox.rby = OFFSET_Y(obbox->rby-r)-3;
706
707 if (PointInBBox(XOff, YOff, bbox)) {
708 return FALSE;
709 } else {
710 bbox.ltx = OFFSET_X(obbox->ltx+r)+3;
711 bbox.lty = OFFSET_Y(obbox->lty+w)+3;
712 bbox.rbx = OFFSET_X(obbox->rbx-r)-3;
713 bbox.rby = OFFSET_Y(obbox->rby-w)-3;
714 return (!PointInBBox(XOff, YOff, bbox));
715 }
716 } else if (rcbox_ptr->rotated_vlist != NULL) {
717 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
718 if (PointInPolygon(XOff, YOff, rcbox_ptr->rotated_n,
719 rcbox_ptr->rotated_vlist)) {
720 return TRUE;
721 }
722 }
723 return PointOnPoly(XOff, YOff, rcbox_ptr->rotated_n,
724 rcbox_ptr->rotated_vlist, ZOOMED_HALF_W(rcbox_ptr->width));
725 }
726 return FALSE;
727 }
728
FindGoodOval(XOff,YOff,OvalObj)729 int FindGoodOval(XOff, YOff, OvalObj)
730 int XOff, YOff;
731 struct ObjRec *OvalObj;
732 /* XOff and YOff are screen offsets */
733 {
734 struct OvalRec *oval_ptr=OvalObj->detail.o;
735 int w, ltx, lty, rbx, rby, fill=oval_ptr->fill, trans_pat=OvalObj->trans_pat;
736
737 if (colorLayers && OvalObj->tmp_parent == NULL &&
738 !ObjInVisibleLayer(OvalObj)) {
739 return FALSE;
740 }
741 ltx = OFFSET_X(OvalObj->obbox.ltx); lty = OFFSET_Y(OvalObj->obbox.lty);
742 rbx = OFFSET_X(OvalObj->obbox.rbx); rby = OFFSET_Y(OvalObj->obbox.rby);
743
744 if (ltx==rbx && lty==rby) return FALSE;
745
746 if (OvalObj->ctm == NULL) {
747 double cx, cy, rx, ry, tmp_x, tmp_y, x1=0.0, x2=0.0, y1=0.0, y2=0.0;
748
749 cx = ((double)(ltx+rbx)/2.0); cy = ((double)(lty+rby)/2.0);
750 rx = ((double)(rbx-ltx)/2.0); ry = ((double)(rby-lty)/2.0);
751
752 if (rx >= ry) {
753 /* flat oval */
754 tmp_y = (double)sqrt(fabs((double)(ry*ry*(1 -
755 (((double)XOff)-cx)*(((double)XOff)-cx)/rx/rx))));
756 y1 = cy - tmp_y;
757 y2 = cy + tmp_y;
758 } else {
759 /* tall oval */
760 tmp_x = (double)sqrt(fabs((double)(rx*rx*(1 -
761 (((double)YOff)-cy)*(((double)YOff)-cy)/ry/ry))));
762 x1 = cx - tmp_x;
763 x2 = cx + tmp_x;
764 }
765
766 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
767 if (rx >= ry) {
768 /* flat oval */
769 if (YOff >= y1-4 && y2+4 >= YOff) return TRUE;
770 } else {
771 /* tall oval */
772 if (XOff >= x1-4 && x2+4 >= XOff) return TRUE;
773 }
774 }
775 w = ZOOMED_HALF_W(oval_ptr->width)+4;
776 if (rx >= ry) {
777 return ((fabs((double)(YOff-y1))<=w) || (fabs((double)(YOff-y2))<=w));
778 } else {
779 return ((fabs((double)(XOff-x1))<=w) || (fabs((double)(XOff-x2))<=w));
780 }
781 } else if (oval_ptr->rotated_vlist != NULL) {
782 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
783 if (PointInPolygon(XOff, YOff, oval_ptr->rotated_n,
784 oval_ptr->rotated_vlist)) {
785 return TRUE;
786 }
787 }
788 return PointOnPoly(XOff, YOff, oval_ptr->rotated_n,
789 oval_ptr->rotated_vlist, ZOOMED_HALF_W(oval_ptr->width));
790 }
791 return FALSE;
792 }
793
FindGoodPoly(XOff,YOff,PolyObj)794 int FindGoodPoly(XOff, YOff, PolyObj)
795 int XOff, YOff;
796 struct ObjRec *PolyObj;
797 /* XOff and YOff are screen offsets */
798 {
799 double len, sin, cos, aw, ah;
800 XPoint tmp_v[4], *sv=NULL;
801 struct PolyRec *poly_ptr=PolyObj->detail.p;
802 int sn=0, dx, dy, fill=poly_ptr->fill, trans_pat=PolyObj->trans_pat;
803
804 if (colorLayers && PolyObj->tmp_parent == NULL &&
805 !ObjInVisibleLayer(PolyObj)) {
806 return FALSE;
807 }
808 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
809 if (PolyObj->ctm == NULL) {
810 sn = poly_ptr->sn;
811 sv = poly_ptr->svlist;
812 sv[sn].x = sv[0].x; sv[sn].y = sv[0].y;
813 if (PointInPolygon(XOff, YOff, sn+1, sv)) return TRUE;
814 } else if (poly_ptr->rotated_vlist != NULL) {
815 sn = poly_ptr->rotated_n;
816 sv = poly_ptr->rotated_vlist;
817 sv[sn].x = sv[0].x; sv[sn].y = sv[0].y;
818 if (PointInPolygon(XOff, YOff, sn+1, sv)) return TRUE;
819 }
820 }
821 if (poly_ptr->style == LS_PLAIN) {
822 if (PolyObj->ctm == NULL) {
823 if (PointOnPoly(XOff, YOff, poly_ptr->sn, poly_ptr->svlist,
824 ZOOMED_HALF_W(poly_ptr->width)))
825 return TRUE;
826 } else if (poly_ptr->rotated_vlist != NULL) {
827 if (PointOnPoly(XOff, YOff, poly_ptr->rotated_n,
828 poly_ptr->rotated_vlist, ZOOMED_HALF_W(poly_ptr->width)))
829 return TRUE;
830 }
831 } else {
832 if (PolyObj->ctm == NULL) {
833 if (PointOnPoly(XOff, YOff, poly_ptr->asn, poly_ptr->asvlist,
834 ZOOMED_HALF_W(poly_ptr->width)))
835 return TRUE;
836 } else if (poly_ptr->rotated_vlist != NULL) {
837 if (PointOnPoly(XOff, YOff, poly_ptr->rotated_n,
838 poly_ptr->rotated_vlist, ZOOMED_HALF_W(poly_ptr->width)))
839 return TRUE;
840 }
841 }
842 if (PolyObj->ctm == NULL) {
843 sv = poly_ptr->svlist;
844 sn = poly_ptr->sn;
845 } else if (poly_ptr->rotated_vlist == NULL) {
846 return FALSE;
847 } else {
848 sv = poly_ptr->rotated_vlist;
849 sn = poly_ptr->rotated_n;
850 }
851 aw = poly_ptr->aw;
852 ah = poly_ptr->ah;
853
854 dx = (int)(sv[1].x - sv[0].x);
855 dy = (int)(sv[1].y - sv[0].y);
856
857 if ((poly_ptr->style & LS_LEFT) && (dx != 0 || dy != 0)) {
858 len = (double)sqrt((double)(((double)dx)*((double)dx) +
859 ((double)dy)*((double)dy)));
860 sin = ((double)dy) / len;
861 cos = ((double)dx) / len;
862
863 tmp_v[0].x = tmp_v[3].x = OFFSET_X(sv[0].x);
864 tmp_v[0].y = tmp_v[3].y = OFFSET_Y(sv[0].y);
865 tmp_v[1].x = OFFSET_X(round(sv[0].x+aw*cos-ah*sin));
866 tmp_v[1].y = OFFSET_Y(round(sv[0].y+aw*sin+ah*cos));
867 tmp_v[2].x = OFFSET_X(round(sv[0].x+aw*cos+ah*sin));
868 tmp_v[2].y = OFFSET_Y(round(sv[0].y+aw*sin-ah*cos));
869
870 if (PointInPolygon(XOff, YOff, 4, tmp_v)) return TRUE;
871 }
872 dx = (int)(sv[sn-1].x - sv[sn-2].x);
873 dy = (int)(sv[sn-1].y - sv[sn-2].y);
874 if ((poly_ptr->style & LS_RIGHT) && (dx != 0 || dy != 0)) {
875 len = (double)sqrt((double)(((double)dx)*((double)dx) +
876 ((double)dy)*((double)dy)));
877 sin = ((double)dy) / len;
878 cos = ((double)dx) / len;
879
880 tmp_v[0].x = tmp_v[3].x = OFFSET_X(sv[sn-1].x);
881 tmp_v[0].y = tmp_v[3].y = OFFSET_Y(sv[sn-1].y);
882 tmp_v[1].x = OFFSET_X(round(sv[sn-1].x-aw*cos+ah*sin));
883 tmp_v[1].y = OFFSET_Y(round(sv[sn-1].y-aw*sin-ah*cos));
884 tmp_v[2].x = OFFSET_X(round(sv[sn-1].x-aw*cos-ah*sin));
885 tmp_v[2].y = OFFSET_Y(round(sv[sn-1].y-aw*sin+ah*cos));
886
887 if (PointInPolygon(XOff, YOff, 4, tmp_v)) return TRUE;
888 }
889 return FALSE;
890 }
891
FindGoodPolygon(XOff,YOff,PolygonObj)892 int FindGoodPolygon(XOff, YOff, PolygonObj)
893 int XOff, YOff;
894 struct ObjRec *PolygonObj;
895 /* XOff and YOff are screen offsets */
896 {
897 struct PolygonRec *polygon_ptr=PolygonObj->detail.g;
898 int fill=polygon_ptr->fill, trans_pat=PolygonObj->trans_pat;
899
900 if (colorLayers && PolygonObj->tmp_parent == NULL &&
901 !ObjInVisibleLayer(PolygonObj)) {
902 return FALSE;
903 }
904 if (PolygonObj->ctm == NULL) {
905 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
906 if (PointInPolygon(XOff, YOff, polygon_ptr->sn, polygon_ptr->svlist)) {
907 return TRUE;
908 }
909 }
910 return PointOnPoly(XOff, YOff, polygon_ptr->sn, polygon_ptr->svlist,
911 ZOOMED_HALF_W(polygon_ptr->width));
912 } else if (polygon_ptr->rotated_vlist != NULL) {
913 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
914 if (PointInPolygon(XOff, YOff, polygon_ptr->rotated_n,
915 polygon_ptr->rotated_vlist)) {
916 return TRUE;
917 }
918 }
919 return PointOnPoly(XOff, YOff, polygon_ptr->rotated_n,
920 polygon_ptr->rotated_vlist, ZOOMED_HALF_W(polygon_ptr->width));
921 }
922 return FALSE;
923 }
924
925 static
PointInFlatPie(Y,dir,angle,ov_int_y1,ov_int_y2,rad_int_y1,rad_int_y2)926 int PointInFlatPie(Y,dir,angle,ov_int_y1,ov_int_y2,rad_int_y1,rad_int_y2)
927 int Y, dir, angle;
928 double ov_int_y1, ov_int_y2, rad_int_y1, rad_int_y2;
929 {
930 switch (dir) {
931 case ARC_CCW:
932 switch ((angle+360)%360) {
933 case 0:
934 if (ov_int_y2 > rad_int_y1) {
935 if (Y>=rad_int_y2 && rad_int_y1>=Y) return TRUE;
936 } else if (ov_int_y2 > rad_int_y2) {
937 if (Y>=rad_int_y2 && ov_int_y2>=Y) return TRUE;
938 }
939 break;
940 case 90:
941 if (ov_int_y1 < rad_int_y2) {
942 if (Y>=rad_int_y2 && rad_int_y1>=Y) return TRUE;
943 } else if (ov_int_y1 < rad_int_y1) {
944 if (Y>=ov_int_y1 && rad_int_y1>=Y) return TRUE;
945 }
946 break;
947 case 180:
948 if (ov_int_y1 < rad_int_y1) {
949 if (Y>=rad_int_y1 && rad_int_y2>=Y) return TRUE;
950 } else if (ov_int_y1 < rad_int_y2) {
951 if (Y>=ov_int_y1 && rad_int_y2>=Y) return TRUE;
952 }
953 break;
954 case 270:
955 if (ov_int_y2 > rad_int_y2) {
956 if (Y>=rad_int_y1 && rad_int_y2>=Y) return TRUE;
957 } else if (ov_int_y2 > rad_int_y1) {
958 if (Y>=rad_int_y1 && ov_int_y2>=Y) return TRUE;
959 }
960 break;
961 }
962 break;
963 case ARC_CW:
964 switch ((angle+360)%360) {
965 case 0:
966 if (ov_int_y1 < rad_int_y1) {
967 if (Y>=rad_int_y1 && rad_int_y2>=Y) return TRUE;
968 } else if (ov_int_y1 < rad_int_y2) {
969 if (Y>=ov_int_y1 && rad_int_y2>=Y) return TRUE;
970 }
971 break;
972 case 90:
973 if (ov_int_y1 < rad_int_y2) {
974 if (Y>=rad_int_y2 && rad_int_y1>=Y) return TRUE;
975 } else if (ov_int_y1 < rad_int_y1) {
976 if (Y>=ov_int_y1 && rad_int_y1>=Y) return TRUE;
977 }
978 break;
979 case 180:
980 if (ov_int_y2 > rad_int_y1) {
981 if (Y>=rad_int_y2 && rad_int_y1>=Y) return TRUE;
982 } else if (ov_int_y2 > rad_int_y2) {
983 if (Y>=rad_int_y2 && ov_int_y2>=Y) return TRUE;
984 }
985 break;
986 case 270:
987 if (ov_int_y2 > rad_int_y2) {
988 if (Y>=rad_int_y1 && rad_int_y2>=Y) return TRUE;
989 } else if (ov_int_y2 > rad_int_y1) {
990 if (Y>=rad_int_y1 && ov_int_y2>=Y) return TRUE;
991 }
992 break;
993 }
994 break;
995 }
996 return FALSE;
997 }
998
999 static
PointInTallPie(X,dir,angle,ov_int_x1,ov_int_x2,rad_int_x1,rad_int_x2)1000 int PointInTallPie(X,dir,angle,ov_int_x1,ov_int_x2,rad_int_x1,rad_int_x2)
1001 int X, dir, angle;
1002 double ov_int_x1, ov_int_x2, rad_int_x1, rad_int_x2;
1003 {
1004 switch (dir) {
1005 case ARC_CCW:
1006 switch ((angle+360)%360) {
1007 case 0:
1008 if (ov_int_x2 > rad_int_x2) {
1009 if (X>=rad_int_x1 && rad_int_x2>=X) return TRUE;
1010 } else if (ov_int_x2 > rad_int_x1) {
1011 if (X>=rad_int_x1 && ov_int_x2>=X) return TRUE;
1012 }
1013 break;
1014 case 90:
1015 if (ov_int_x2 > rad_int_x1) {
1016 if (X>=rad_int_x2 && rad_int_x1>=X) return TRUE;
1017 } else if (ov_int_x2 > rad_int_x2) {
1018 if (X>=rad_int_x2 && ov_int_x2>=X) return TRUE;
1019 }
1020 break;
1021 case 180:
1022 if (ov_int_x1 < rad_int_x2) {
1023 if (X>=rad_int_x2 && rad_int_x1>=X) return TRUE;
1024 } else if (ov_int_x1 < rad_int_x1) {
1025 if (X>=ov_int_x1 && rad_int_x1>=X) return TRUE;
1026 }
1027 break;
1028 case 270:
1029 if (ov_int_x1 < rad_int_x1) {
1030 if (X>=rad_int_x1 && rad_int_x2>=X) return TRUE;
1031 } else if (ov_int_x1 < rad_int_x2) {
1032 if (X>=ov_int_x1 && rad_int_x2>=X) return TRUE;
1033 }
1034 break;
1035 }
1036 break;
1037 case ARC_CW:
1038 switch ((angle+360)%360) {
1039 case 0:
1040 if (ov_int_x2 > rad_int_x2) {
1041 if (X>=rad_int_x1 && rad_int_x2>=X) return TRUE;
1042 } else if (ov_int_x2 > rad_int_x1) {
1043 if (X>=rad_int_x1 && ov_int_x2>=X) return TRUE;
1044 }
1045 break;
1046 case 90:
1047 if (ov_int_x1 < rad_int_x1) {
1048 if (X>=rad_int_x1 && rad_int_x2>=X) return TRUE;
1049 } else if (ov_int_x1 < rad_int_x2) {
1050 if (X>=ov_int_x1 && rad_int_x2>=X) return TRUE;
1051 }
1052 break;
1053 case 180:
1054 if (ov_int_x1 < rad_int_x2) {
1055 if (X>=rad_int_x2 && rad_int_x1>=X) return TRUE;
1056 } else if (ov_int_x1 < rad_int_x1) {
1057 if (X>=ov_int_x1 && rad_int_x1>=X) return TRUE;
1058 }
1059 break;
1060 case 270:
1061 if (ov_int_x2 > rad_int_x1) {
1062 if (X>=rad_int_x2 && rad_int_x1>=X) return TRUE;
1063 } else if (ov_int_x2 > rad_int_x2) {
1064 if (X>=rad_int_x2 && ov_int_x2>=X) return TRUE;
1065 }
1066 break;
1067 }
1068 break;
1069 }
1070 return FALSE;
1071 }
1072
1073 static
XInPieRange(X,dir,angle,cx,rx)1074 int XInPieRange(X, dir, angle, cx, rx)
1075 int X, dir, angle;
1076 double cx, rx;
1077 {
1078 switch (dir) {
1079 case ARC_CCW:
1080 switch ((angle+360)%360) {
1081 case 0:
1082 case 90: return (X>=cx && cx+rx>=X);
1083
1084 case 180:
1085 case 270: return (X>=cx-rx && cx>=X);
1086 }
1087 break;
1088 case ARC_CW:
1089 switch ((angle+360)%360) {
1090 case 0:
1091 case 270: return (X>=cx && cx+rx>=X);
1092
1093 case 90:
1094 case 180: return (X>=cx-rx && cx>=X);
1095 }
1096 break;
1097 }
1098 return FALSE;
1099 }
1100
1101 static
YInPieRange(Y,dir,angle,cy,ry)1102 int YInPieRange(Y, dir, angle, cy, ry)
1103 int Y, dir, angle;
1104 double cy, ry;
1105 {
1106 switch (dir) {
1107 case ARC_CCW:
1108 switch ((angle+360)%360) {
1109 case 0:
1110 case 270: return (Y>=cy && cy+ry>=Y);
1111
1112 case 90:
1113 case 180: return (Y>=cy-ry && cy>=Y);
1114 }
1115 break;
1116 case ARC_CW:
1117 switch ((angle+360)%360) {
1118 case 0:
1119 case 90: return (Y>=cy-ry && cy>=Y);
1120
1121 case 180:
1122 case 270: return (Y>=cy && cy+ry>=Y);
1123 }
1124 break;
1125 }
1126 return FALSE;
1127 }
1128
FindGoodArc(XOff,YOff,ArcObj)1129 int FindGoodArc(XOff, YOff, ArcObj)
1130 int XOff, YOff;
1131 struct ObjRec *ArcObj;
1132 /* XOff and YOff are screen offsets */
1133 {
1134 struct ArcRec *arc_ptr=ArcObj->detail.a;
1135 int w, h, ltx, lty, rbx, rby, aw, ah, dx, dy, theta=0;
1136 double cx, cy, rx, ry, tmp_x, tmp_y, x=0.0, y=0.0;
1137 double ov_int_x1=0.0, ov_int_x2=0.0;
1138 double ov_int_y1=0.0, ov_int_y2=0.0;
1139 double rad_int_x1=0.0, rad_int_x2=0.0;
1140 double rad_int_y1=0.0, rad_int_y2=0.0;
1141 double len, sine, cosine;
1142 int fill=arc_ptr->fill, angle1, angle2, trans_pat=ArcObj->trans_pat;
1143 int arc_x1, arc_y1, arc_x2, arc_y2, theta1, theta2;
1144 int pass_theta1, just_pass_theta1, angle, dir, full_circle;
1145 XPoint tmp_v[4];
1146
1147 if (colorLayers && ArcObj->tmp_parent == NULL &&
1148 !ObjInVisibleLayer(ArcObj)) {
1149 return FALSE;
1150 }
1151 if (ArcObj->ctm != NULL) {
1152 if (arc_ptr->rotated_vlist == NULL) {
1153 return FALSE;
1154 }
1155 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1156 if (PointInPolygon(XOff, YOff, arc_ptr->rotated_n+2,
1157 arc_ptr->rotated_vlist)) {
1158 return TRUE;
1159 }
1160 }
1161 return PointOnPoly(XOff, YOff, arc_ptr->rotated_n,
1162 arc_ptr->rotated_vlist, ZOOMED_HALF_W(arc_ptr->width));
1163 }
1164
1165 ltx = OFFSET_X(arc_ptr->ltx);
1166 lty = OFFSET_Y(arc_ptr->lty);
1167 rbx = OFFSET_X(arc_ptr->ltx+arc_ptr->w);
1168 rby = OFFSET_Y(arc_ptr->lty+arc_ptr->h);
1169
1170 if (ltx==rbx && lty==rby) return FALSE;
1171
1172 rx = (rbx-ltx)/2; ry = (rby-lty)/2;
1173 cx = (double)(OFFSET_X(arc_ptr->xc)); cy = (double)(OFFSET_Y(arc_ptr->yc));
1174 arc_x1 = OFFSET_X(arc_ptr->x1); arc_y1 = OFFSET_Y(arc_ptr->y1);
1175 dir = arc_ptr->dir;
1176
1177 theta1 = (int)(arc_ptr->angle1)/64;
1178 theta2 = theta1 + (int)(arc_ptr->angle2)/64;
1179
1180 ArcRealX2Y2 (arc_ptr, &arc_x2, &arc_y2);
1181 arc_x2 = OFFSET_X(arc_x2); arc_y2 = OFFSET_Y(arc_y2);
1182
1183 if (theta2 < -180) theta2 += 360;
1184 if (theta2 > 180) theta2 -= 360;
1185
1186 if (theta1 < 0) theta1 += 360;
1187 if (theta2 <= 0) theta2 += 360;
1188
1189 angle1 = arc_ptr->angle1;
1190 angle2 = arc_ptr->angle2;
1191
1192 full_circle = (abs(angle2) == 64*360);
1193
1194 if (rx >= ry) {
1195 /* flat oval */
1196 tmp_y = (double)sqrt(fabs((double)(ry*ry*(1 -
1197 (((double)XOff)-cx)*(((double)XOff)-cx)/rx/rx))));
1198 ov_int_y1 = cy - tmp_y;
1199 ov_int_y2 = cy + tmp_y;
1200 } else {
1201 /* tall oval */
1202 tmp_x = (double)sqrt(fabs((double)(rx*rx*(1 -
1203 (((double)YOff)-cy)*(((double)YOff)-cy)/ry/ry))));
1204 ov_int_x1 = cx - tmp_x;
1205 ov_int_x2 = cx + tmp_x;
1206 }
1207
1208 w = ZOOMED_HALF_W(arc_ptr->width)+4;
1209 if (rx >= ry) {
1210 /* flat oval */
1211 if (fabs(arc_x1-cx) < INT_TOL) {
1212 switch (theta1) {
1213 case 90: rad_int_y1 = cy - 1/INT_TOL; break;
1214 case 270: rad_int_y1 = cy + 1/INT_TOL; break;
1215 default: fprintf(stderr, "theta1 = %1d (flat)\n", theta1); break;
1216 }
1217 } else {
1218 rad_int_y1 = cy + (XOff-cx)*(arc_y1-cy)/(arc_x1-cx);
1219 }
1220 if (fabs(arc_x2-cx) < INT_TOL) {
1221 switch (theta2) {
1222 case 90: rad_int_y2 = cy - 1/INT_TOL; break;
1223 case 270: rad_int_y2 = cy + 1/INT_TOL; break;
1224 default: fprintf(stderr, "theta2 = %1d (flat)\n", theta2); break;
1225 }
1226 } else {
1227 rad_int_y2 = cy + (XOff-cx)*(arc_y2-cy)/(arc_x2-cx);
1228 }
1229 } else {
1230 /* tall oval */
1231 if (fabs(arc_y1-cy) < INT_TOL) {
1232 switch (theta1) {
1233 case 0:
1234 case 360: rad_int_x1 = cx + 1/INT_TOL; break;
1235 case 180: rad_int_x1 = cx - 1/INT_TOL; break;
1236 default: fprintf(stderr, "theta1 = %1d (tall)\n", theta1); break;
1237 }
1238 } else {
1239 rad_int_x1 = cx + (YOff-cy)*(arc_x1-cx)/(arc_y1-cy);
1240 }
1241 if (fabs(arc_y2-cy) < INT_TOL) {
1242 switch (theta2) {
1243 case 0:
1244 case 360: rad_int_x2 = cx + 1/INT_TOL; break;
1245 case 180: rad_int_x2 = cx - 1/INT_TOL; break;
1246 default: fprintf(stderr, "theta2 = %1d (tall)\n", theta2); break;
1247 }
1248 } else {
1249 rad_int_x2 = cx + (YOff-cy)*(arc_x2-cx)/(arc_y2-cy);
1250 }
1251 }
1252 if (dir == ARC_CCW) {
1253 angle = 0;
1254 pass_theta1 = FALSE;
1255 just_pass_theta1 = FALSE;
1256 while (angle < theta2 || !pass_theta1) {
1257 if (angle >= theta1 && !pass_theta1) {
1258 pass_theta1 = TRUE;
1259 just_pass_theta1 = TRUE;
1260 if (theta2 > theta1 && angle >= theta2 && !full_circle) {
1261 /* theta1 and theta2 are in the same quadrant */
1262 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1263 if (rx >= ry) {
1264 /* flat oval */
1265 if (PointInFlatPie(YOff, dir, angle, ov_int_y1,
1266 ov_int_y2, rad_int_y1, rad_int_y2)) {
1267 return TRUE;
1268 }
1269 } else {
1270 /* tall oval */
1271 if (PointInTallPie(XOff, dir, angle, ov_int_x1,
1272 ov_int_x2, rad_int_x1, rad_int_x2)) {
1273 return TRUE;
1274 }
1275 }
1276 }
1277 if (rx >= ry) {
1278 /* flat oval */
1279 switch ((angle+360)%360) {
1280 case 0:
1281 case 270:
1282 return (XOff>=arc_x1 && arc_x2>=XOff &&
1283 (fabs((double)(YOff-ov_int_y2)) <= w));
1284 case 90:
1285 case 180:
1286 return (XOff>=arc_x2 && arc_x1>=XOff &&
1287 (fabs((double)(YOff-ov_int_y1)) <= w));
1288 }
1289 } else {
1290 /* tall oval */
1291 switch ((angle+360)%360) {
1292 case 0:
1293 case 90:
1294 return (YOff>=arc_y2 && arc_y1>=YOff &&
1295 (fabs((double)(XOff-ov_int_x2)) <= w));
1296 case 180:
1297 case 270:
1298 return (YOff>=arc_y1 && arc_y2>=YOff &&
1299 (fabs((double)(XOff-ov_int_x1)) <= w));
1300 }
1301 }
1302 }
1303 if (theta2 <= theta1) angle -= 360;
1304 if (angle > theta2) angle -= 360;
1305 }
1306 if (just_pass_theta1) {
1307 just_pass_theta1 = FALSE;
1308 if (rx >= ry) {
1309 /* flat oval */
1310 switch ((angle+360)%360) {
1311 case 0: y = cy; break;
1312 case 90: y = cy-ry; break;
1313 case 180: y = cy; break;
1314 case 270: y = cy+ry; break;
1315 }
1316 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1317 if (XInPieRange(XOff, dir, angle, cx, rx) &&
1318 PointInFlatPie (YOff, dir, angle, ov_int_y1,
1319 ov_int_y2, rad_int_y1, y)) {
1320 return TRUE;
1321 }
1322 }
1323 switch ((angle+360)%360) {
1324 case 0:
1325 if (XOff>=arc_x1 && cx+rx>=XOff &&
1326 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1327 return TRUE;
1328 }
1329 break;
1330 case 90:
1331 if (XOff>=cx && arc_x1>=XOff &&
1332 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1333 return TRUE;
1334 }
1335 break;
1336 case 180:
1337 if (XOff>=cx-rx && arc_x1>=XOff &&
1338 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1339 return TRUE;
1340 }
1341 break;
1342 case 270:
1343 if (XOff>=arc_x1 && cx>=XOff &&
1344 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1345 return TRUE;
1346 }
1347 break;
1348 }
1349 } else {
1350 /* tall oval */
1351 switch ((angle+360)%360) {
1352 case 0: x = cx+rx; break;
1353 case 90: x = cx; break;
1354 case 180: x = cx-rx; break;
1355 case 270: x = cx; break;
1356 }
1357 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1358 if (YInPieRange(YOff, dir, angle, cy, ry) &&
1359 PointInTallPie(XOff, dir, angle, ov_int_x1,
1360 ov_int_x2, rad_int_x1, x)) {
1361 return TRUE;
1362 }
1363 }
1364 switch ((angle+360)%360) {
1365 case 0:
1366 if (YOff>=cy && arc_y1>=YOff &&
1367 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1368 return TRUE;
1369 }
1370 break;
1371 case 90:
1372 if (YOff>=cy-ry && arc_y1>=YOff &&
1373 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1374 return TRUE;
1375 }
1376 break;
1377 case 180:
1378 if (YOff>=arc_y1 && cy>=YOff &&
1379 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1380 return TRUE;
1381 }
1382 break;
1383 case 270:
1384 if (YOff>=arc_y1 && cy+ry>=YOff &&
1385 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1386 return TRUE;
1387 }
1388 break;
1389 }
1390 }
1391 } else if (pass_theta1) {
1392 /* see if point is in the quadrant */
1393 if (rx >= ry) {
1394 /* flat oval */
1395 if (XInPieRange(XOff, dir, angle, cx, rx)) {
1396 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1397 switch ((angle+360)%360) {
1398 case 90:
1399 case 180:
1400 if (YOff>=ov_int_y1 && cy>=YOff) return TRUE;
1401 break;
1402
1403 case 0:
1404 case 270:
1405 if (YOff>=cy && ov_int_y2>=YOff) return TRUE;
1406 break;
1407 }
1408 }
1409 switch ((angle+360)%360) {
1410 case 0:
1411 case 270:
1412 if (fabs((double)(YOff-ov_int_y2)) <= w) return TRUE;
1413 break;
1414 case 90:
1415 case 180:
1416 if (fabs((double)(YOff-ov_int_y1)) <= w) return TRUE;
1417 break;
1418 }
1419 }
1420 } else {
1421 /* tall oval */
1422 if (YInPieRange(YOff, dir, angle, cy, ry)) {
1423 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1424 switch ((angle+360)%360) {
1425 case 0:
1426 case 90:
1427 if (XOff>=cx && ov_int_x2>=XOff) return TRUE;
1428 break;
1429
1430 case 180:
1431 case 270:
1432 if (XOff>=ov_int_x1 && cx>=XOff) return TRUE;
1433 break;
1434 }
1435 }
1436 switch ((angle+360)%360) {
1437 case 0:
1438 case 90:
1439 if (fabs((double)(XOff-ov_int_x2)) <= w) return TRUE;
1440 break;
1441
1442 case 180:
1443 case 270:
1444 if (fabs((double)(XOff-ov_int_x1)) <= w) return TRUE;
1445 break;
1446 }
1447 }
1448 }
1449 }
1450 angle = (angle == 360) ? 0 : (angle+90);
1451 }
1452 if (rx >= ry) {
1453 /* flat oval */
1454 switch ((angle+360)%360) {
1455 case 0: y = cy+ry; break;
1456 case 180: y = cy-ry; break;
1457
1458 case 90:
1459 case 270: y = cy; break;
1460 }
1461 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1462 if (XInPieRange(XOff, dir, angle, cx, rx) &&
1463 PointInFlatPie(YOff, dir, angle, ov_int_y1, ov_int_y2,
1464 y, rad_int_y2)) {
1465 return TRUE;
1466 }
1467 }
1468 switch ((angle+360)%360) {
1469 case 0:
1470 if (XOff>=cx && arc_x2>=XOff &&
1471 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1472 return TRUE;
1473 }
1474 break;
1475 case 90:
1476 if (XOff>=arc_x2 && cx+rx>=XOff &&
1477 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1478 return TRUE;
1479 }
1480 break;
1481 case 180:
1482 if (XOff>=arc_x2 && cx>=XOff &&
1483 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1484 return TRUE;
1485 }
1486 break;
1487 case 270:
1488 if (XOff>=cx-rx && arc_x2>=XOff &&
1489 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1490 return TRUE;
1491 }
1492 break;
1493 }
1494 } else {
1495 /* tall oval */
1496 switch ((angle+360)%360) {
1497 case 0:
1498 case 180: x = cx; break;
1499
1500 case 90: x = cx+rx; break;
1501 case 270: x = cx-rx; break;
1502 }
1503 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1504 if (YInPieRange(YOff, dir, angle, cy, ry) &&
1505 PointInTallPie(XOff, dir, angle, ov_int_x1, ov_int_x2,
1506 x, rad_int_x2)) {
1507 return TRUE;
1508 }
1509 }
1510 switch ((angle+360)%360) {
1511 case 0:
1512 if (YOff>=arc_y2 && cy+ry>=YOff &&
1513 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1514 return TRUE;
1515 }
1516 break;
1517 case 90:
1518 if (YOff>=arc_y2 && cy>=YOff &&
1519 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1520 return TRUE;
1521 }
1522 break;
1523 case 180:
1524 if (YOff>=cy-ry && arc_y2>=YOff &&
1525 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1526 return TRUE;
1527 }
1528 break;
1529 case 270:
1530 if (YOff>=cy && arc_y2>=YOff &&
1531 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1532 return TRUE;
1533 }
1534 break;
1535 }
1536 }
1537 } else {
1538 angle = 360;
1539 pass_theta1 = FALSE;
1540 just_pass_theta1 = FALSE;
1541 while (angle > theta2 || !pass_theta1) {
1542 if (angle <= theta1 && !pass_theta1) {
1543 pass_theta1 = TRUE;
1544 just_pass_theta1 = TRUE;
1545 if (theta2 < theta1 && angle <= theta2 && !full_circle) {
1546 /* theta1 and theta2 are in the same quadrant */
1547 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1548 if (rx >= ry) {
1549 if (PointInFlatPie(YOff, dir, angle, ov_int_y1,
1550 ov_int_y2, rad_int_y1, rad_int_y2)) {
1551 return TRUE;
1552 }
1553 } else {
1554 if (PointInTallPie(XOff, dir, angle, ov_int_x1,
1555 ov_int_x2, rad_int_x1, rad_int_x2)) {
1556 return TRUE;
1557 }
1558 }
1559 }
1560 if (rx >= ry) {
1561 /* flat oval */
1562 switch ((angle+360)%360) {
1563 case 0:
1564 case 90:
1565 return (XOff>=arc_x1 && arc_x2>=XOff &&
1566 (fabs((double)(YOff-ov_int_y1)) <= w));
1567 case 180:
1568 case 270:
1569 return (XOff>=arc_x2 && arc_x1>=XOff &&
1570 (fabs((double)(YOff-ov_int_y2)) <= w));
1571 }
1572 } else {
1573 /* tall oval */
1574 switch ((angle+360)%360) {
1575 case 0:
1576 case 270:
1577 return (YOff>=arc_y1 && arc_y2>=YOff &&
1578 (fabs((double)(XOff-ov_int_x2)) <= w));
1579 case 90:
1580 case 180:
1581 return (YOff>=arc_y2 && arc_y1>=YOff &&
1582 (fabs((double)(XOff-ov_int_x1)) <= w));
1583 }
1584 }
1585 }
1586 if (theta2 >= theta1) angle += 360;
1587 if (angle <= theta2) angle += 360;
1588 }
1589 if (just_pass_theta1) {
1590 just_pass_theta1 = FALSE;
1591 if (rx >= ry) {
1592 /* flat oval */
1593 switch ((angle+360)%360) {
1594 case 0: y = cy; break;
1595 case 90: y = cy-ry; break;
1596 case 180: y = cy; break;
1597 case 270: y = cy+ry; break;
1598 }
1599 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1600 if (XInPieRange(XOff, dir, angle, cx, rx) &&
1601 PointInFlatPie(YOff, dir, angle, ov_int_y1,
1602 ov_int_y2, rad_int_y1, y)) {
1603 return TRUE;
1604 }
1605 }
1606 switch ((angle+360)%360) {
1607 case 0:
1608 if (XOff>=arc_x1 && cx+rx>=XOff &&
1609 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1610 return TRUE;
1611 }
1612 break;
1613 case 90:
1614 if (XOff>=arc_x1 && cx>=XOff &&
1615 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1616 return TRUE;
1617 }
1618 break;
1619 case 180:
1620 if (XOff>=cx-rx && arc_x1>=XOff &&
1621 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1622 return TRUE;
1623 }
1624 break;
1625 case 270:
1626 if (XOff>=cx && arc_x1>=XOff &&
1627 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1628 return TRUE;
1629 }
1630 break;
1631 }
1632 } else {
1633 /* tall oval */
1634 switch ((angle+360)%360) {
1635 case 0: x = cx+rx; break;
1636 case 90: x = cx; break;
1637 case 180: x = cx-rx; break;
1638 case 270: x = cx; break;
1639 }
1640 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1641 if (YInPieRange(YOff, dir, angle, cy, ry) &&
1642 PointInTallPie(XOff, dir, angle, ov_int_x1,
1643 ov_int_x2, rad_int_x1, x)) {
1644 return TRUE;
1645 }
1646 }
1647 switch ((angle+360)%360) {
1648 case 0:
1649 if (YOff>=arc_y1 && cy>=YOff &&
1650 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1651 return TRUE;
1652 }
1653 break;
1654 case 90:
1655 if (YOff>=cy-ry && arc_y1>=YOff &&
1656 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1657 return TRUE;
1658 }
1659 break;
1660 case 180:
1661 if (YOff>=cy && arc_y1>=YOff &&
1662 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1663 return TRUE;
1664 }
1665 break;
1666 case 270:
1667 if (YOff>=arc_y1 && cy+ry>=YOff &&
1668 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1669 return TRUE;
1670 }
1671 break;
1672 }
1673 }
1674 } else if (pass_theta1) {
1675 /* see if point is in the quadrant */
1676 if (rx >= ry) {
1677 /* flat oval */
1678 if (XInPieRange(XOff, dir, angle, cx, rx)) {
1679 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1680 switch ((angle+360)%360) {
1681 case 0:
1682 case 90:
1683 if (YOff>=ov_int_y1 && cy>=YOff) return TRUE;
1684 break;
1685
1686 case 180:
1687 case 270:
1688 if (YOff>=cy && ov_int_y2>=YOff) return TRUE;
1689 break;
1690 }
1691 }
1692 switch ((angle+360)%360) {
1693 case 0:
1694 case 90:
1695 if (fabs((double)(YOff-ov_int_y1)) <= w) return TRUE;
1696 break;
1697 case 180:
1698 case 270:
1699 if (fabs((double)(YOff-ov_int_y2)) <= w) return TRUE;
1700 break;
1701 }
1702 }
1703 } else {
1704 /* tall oval */
1705 if (YInPieRange(YOff, dir, angle, cy, ry)) {
1706 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1707 switch ((angle+360)%360) {
1708 case 0:
1709 case 270:
1710 if (XOff>=cx && ov_int_x2>=XOff) return TRUE;
1711 break;
1712 case 90:
1713 case 180:
1714 if (XOff>=ov_int_x1 && cx>=XOff) return TRUE;
1715 break;
1716 }
1717 }
1718 switch ((angle+360)%360) {
1719 case 0:
1720 case 270:
1721 if (fabs((double)(XOff-ov_int_x2)) <= w) return TRUE;
1722 break;
1723 case 90:
1724 case 180:
1725 if (fabs((double)(XOff-ov_int_x1)) <= w) return TRUE;
1726 break;
1727 }
1728 }
1729 }
1730 }
1731 angle = (angle == 0) ? 360 : (angle-90);
1732 }
1733 if (rx >= ry) {
1734 /* flat oval */
1735 switch ((angle+360)%360) {
1736 case 0: y = cy-ry; break;
1737 case 180: y = cy+ry; break;
1738
1739 case 90:
1740 case 270: y = cy; break;
1741 }
1742 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1743 if (XInPieRange(XOff, dir, angle, cx, rx) &&
1744 PointInFlatPie(YOff, dir, angle, ov_int_y1, ov_int_y2,
1745 y, rad_int_y2)) {
1746 return TRUE;
1747 }
1748 }
1749 switch ((angle+360)%360) {
1750 case 0:
1751 if (XOff>=cx && arc_x2>=XOff &&
1752 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1753 return TRUE;
1754 }
1755 break;
1756 case 90:
1757 if (XOff>=cx-rx && arc_x2>=XOff &&
1758 (fabs((double)(YOff-ov_int_y1)) <= w)) {
1759 return TRUE;
1760 }
1761 break;
1762 case 180:
1763 if (XOff>=arc_x2 && cx>=XOff &&
1764 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1765 return TRUE;
1766 }
1767 break;
1768 case 270:
1769 if (XOff>=arc_x2 && cx+rx>=XOff &&
1770 (fabs((double)(YOff-ov_int_y2)) <= w)) {
1771 return TRUE;
1772 }
1773 break;
1774 }
1775 } else {
1776 /* tall oval */
1777 switch ((angle+360)%360) {
1778 case 0:
1779 case 180: x = cx; break;
1780
1781 case 90: x = cx-rx; break;
1782 case 270: x = cx+rx; break;
1783 }
1784 if (!(fill == NONEPAT || (fill == BACKPAT && trans_pat))) {
1785 if (YInPieRange(YOff, dir, angle, cy, ry) &&
1786 PointInTallPie(XOff, dir, angle, ov_int_x1, ov_int_x2,
1787 x, rad_int_x2)) {
1788 return TRUE;
1789 }
1790 }
1791 switch ((angle+360)%360) {
1792 case 0:
1793 if (YOff>=cy-ry && arc_y2>=YOff &&
1794 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1795 return TRUE;
1796 }
1797 break;
1798 case 90:
1799 if (YOff>=arc_y2 && cy>=YOff &&
1800 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1801 return TRUE;
1802 }
1803 break;
1804 case 180:
1805 if (YOff>=arc_y2 && cy+ry>=YOff &&
1806 (fabs((double)(XOff-ov_int_x1)) <= w)) {
1807 return TRUE;
1808 }
1809 break;
1810 case 270:
1811 if (YOff>=cy && arc_y2>=YOff &&
1812 (fabs((double)(XOff-ov_int_x2)) <= w)) {
1813 return TRUE;
1814 }
1815 break;
1816 }
1817 }
1818 }
1819
1820 w = ZOOMED_SIZE(arc_ptr->w);
1821 h = ZOOMED_SIZE(arc_ptr->h);
1822 aw = ZOOMED_SIZE(arc_ptr->aw); if (aw == 0) aw = 1;
1823 ah = ZOOMED_SIZE(arc_ptr->ah); if (ah == 0) ah = 1;
1824
1825 if ((arc_ptr->style & LS_LEFT) && (angle2%(360<<6) != 0)) {
1826 /* the arrow should appear at angle1 */
1827 switch (dir) {
1828 case ARC_CCW: theta = (int)(angle1/64)-90; break;
1829 case ARC_CW: theta = (int)(angle1/64)+90; break;
1830 }
1831 dx = -round(w*cos(((double)theta)*M_PI/180.0));
1832 dy = round(h*sin(((double)theta)*M_PI/180.0));
1833 if (dx == 0 && dy == 0) {
1834 sine = cosine = ((double)0.0);
1835
1836 tmp_v[0].x = tmp_v[1].x = tmp_v[2].x = tmp_v[3].x = arc_x1;
1837 tmp_v[0].y = tmp_v[1].y = tmp_v[2].y = tmp_v[3].y = arc_y1;
1838 } else {
1839 len = (double)sqrt((double)(((double)dx)*((double)dx) +
1840 ((double)dy)*((double)dy)));
1841 sine = dy/len;
1842 cosine = dx/len;
1843
1844 tmp_v[0].x = tmp_v[3].x = arc_x1;
1845 tmp_v[0].y = tmp_v[3].y = arc_y1;
1846 tmp_v[1].x = round(arc_x1 + aw*cosine - ah*sine);
1847 tmp_v[1].y = round(arc_y1 + aw*sine + ah*cosine);
1848 tmp_v[2].x = round(arc_x1 + aw*cosine + ah*sine);
1849 tmp_v[2].y = round(arc_y1 + aw*sine - ah*cosine);
1850 }
1851
1852 if (PointInPolygon(XOff, YOff, 4, tmp_v)) return TRUE;
1853 }
1854 if ((arc_ptr->style & LS_RIGHT) && (angle2%(360<<6) != 0)) {
1855 switch (dir) {
1856 case ARC_CCW: theta = (int)((angle1+angle2)/64)-90; break;
1857 case ARC_CW: theta = (int)((angle1+angle2)/64)+90; break;
1858 }
1859 dx = -round(w*cos(((double)theta)*M_PI/180.0));
1860 dy = round(h*sin(((double)theta)*M_PI/180.0));
1861 if (dx == 0 && dy == 0) {
1862 sine = cosine = ((double)0.0);
1863
1864 tmp_v[0].x = tmp_v[1].x = tmp_v[2].x = tmp_v[3].x = arc_x2;
1865 tmp_v[0].y = tmp_v[1].y = tmp_v[2].y = tmp_v[3].y = arc_y2;
1866 } else {
1867 len = (double)sqrt((double)(((double)dx)*((double)dx) +
1868 ((double)dy)*((double)dy)));
1869 sine = dy/len;
1870 cosine = dx/len;
1871
1872 tmp_v[0].x = tmp_v[3].x = arc_x2;
1873 tmp_v[0].y = tmp_v[3].y = arc_y2;
1874 tmp_v[1].x = round(arc_x2 - aw*cosine + ah*sine);
1875 tmp_v[1].y = round(arc_y2 - aw*sine - ah*cosine);
1876 tmp_v[2].x = round(arc_x2 - aw*cosine - ah*sine);
1877 tmp_v[2].y = round(arc_y2 - aw*sine + ah*cosine);
1878 }
1879
1880 if (PointInPolygon(XOff, YOff, 4, tmp_v)) return TRUE;
1881 }
1882 return FALSE;
1883 }
1884
FindGoodObj(XOff,YOff,FirstObj,SubObj,ImmediateChildObj)1885 int FindGoodObj(XOff, YOff, FirstObj, SubObj, ImmediateChildObj)
1886 int XOff, YOff;
1887 struct ObjRec *FirstObj, **SubObj, **ImmediateChildObj;
1888 /* XOff and YOff are screen offsets */
1889 {
1890 register struct ObjRec *obj_ptr;
1891 register struct AttrRec *attr_ptr;
1892
1893 *SubObj = NULL;
1894
1895 for (obj_ptr=FirstObj; obj_ptr != NULL; obj_ptr=obj_ptr->next) {
1896 obj_ptr->tmp_child = NULL;
1897 if (ImmediateChildObj != NULL) *ImmediateChildObj = obj_ptr;
1898 if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1899 continue;
1900 }
1901 for (attr_ptr=obj_ptr->fattr; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
1902 if (attr_ptr->shown &&
1903 XOff >= OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
1904 YOff >= OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
1905 XOff <= OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
1906 YOff <= OFFSET_Y(attr_ptr->obj->bbox.rby)+3) {
1907 *SubObj = attr_ptr->obj;
1908 return TRUE;
1909 }
1910 }
1911 if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1912 YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1913 XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1914 YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1915 struct ObjRec *next_level_child=NULL, *visible_obj=NULL;
1916
1917 switch (obj_ptr->type) {
1918 case OBJ_TEXT:
1919 if (FindGoodText(XOff, YOff, obj_ptr)) return TRUE;
1920 break;
1921 case OBJ_XBM:
1922 if (FindGoodXBm(XOff, YOff, obj_ptr)) return TRUE;
1923 break;
1924 case OBJ_XPM:
1925 if (FindGoodXPm(XOff, YOff, obj_ptr)) return TRUE;
1926 break;
1927 case OBJ_BOX:
1928 if (FindGoodBox(XOff, YOff, obj_ptr)) return TRUE;
1929 break;
1930 case OBJ_RCBOX:
1931 if (FindGoodRCBox(XOff, YOff, obj_ptr)) return TRUE;
1932 break;
1933 case OBJ_OVAL:
1934 if (FindGoodOval(XOff, YOff, obj_ptr)) return TRUE;
1935 break;
1936 case OBJ_POLY:
1937 if (FindGoodPoly(XOff, YOff, obj_ptr)) return TRUE;
1938 break;
1939 case OBJ_POLYGON:
1940 if (FindGoodPolygon(XOff, YOff, obj_ptr)) return TRUE;
1941 break;
1942 case OBJ_ARC:
1943 if (FindGoodArc(XOff, YOff, obj_ptr)) return TRUE;
1944 break;
1945
1946 case OBJ_GROUP:
1947 case OBJ_SYM:
1948 case OBJ_ICON:
1949 if (colorLayers) {
1950 struct ObjRec *tmp_obj;
1951
1952 for (tmp_obj=obj_ptr->detail.r->first; tmp_obj != NULL;
1953 tmp_obj=tmp_obj->next) {
1954 tmp_obj->tmp_parent = obj_ptr;
1955 }
1956 }
1957 if (FindGoodObj(XOff, YOff, obj_ptr->detail.r->first, SubObj,
1958 &next_level_child)) {
1959 obj_ptr->tmp_child = next_level_child;
1960 return TRUE;
1961 }
1962 break;
1963 case OBJ_PIN:
1964 visible_obj = GetPinObj(obj_ptr);
1965 if (colorLayers) {
1966 struct ObjRec *tmp_obj;
1967
1968 visible_obj->tmp_parent = obj_ptr;
1969 for (tmp_obj=visible_obj->detail.r->first; tmp_obj != NULL;
1970 tmp_obj=tmp_obj->next) {
1971 tmp_obj->tmp_parent = visible_obj;
1972 }
1973 }
1974 obj_ptr->tmp_child = visible_obj;
1975 if (FindGoodObj(XOff, YOff, visible_obj->detail.r->first,
1976 SubObj, &next_level_child)) {
1977 visible_obj->tmp_child = next_level_child;
1978 return TRUE;
1979 }
1980 break;
1981 }
1982 }
1983 }
1984 if (ImmediateChildObj != NULL) *ImmediateChildObj = NULL;
1985 return FALSE;
1986 }
1987