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