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/polygon.c,v 1.41 2011/06/09 15:55:15 cvsps Exp $
19  */
20 
21 #define _INCLUDE_FROM_POLYGON_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "arc.e"
26 #include "attr.e"
27 #include "auxtext.e"
28 #include "box.e"
29 #include "cmd.e"
30 #include "color.e"
31 #include "choice.e"
32 #include "cursor.e"
33 #include "cutpaste.e"
34 #include "dialog.e"
35 #include "drawing.e"
36 #include "dup.e"
37 #include "grid.e"
38 #include "file.e"
39 #include "mainloop.e"
40 #include "mark.e"
41 #include "msg.e"
42 #include "obj.e"
43 #include "pattern.e"
44 #include "poly.e"
45 #include "polygon.e"
46 #include "ps.e"
47 #include "raster.e"
48 #include "rect.e"
49 #include "ruler.e"
50 #include "select.e"
51 #include "setup.e"
52 #include "spline.e"
53 #include "strtbl.e"
54 #include "util.e"
55 #include "xpixmap.e"
56 
57 int polygonDrawn=FALSE;
58 
MakePolygonVertex(XOff,YOff,NumVs,Vs)59 XPoint *MakePolygonVertex(XOff, YOff, NumVs, Vs)
60    int XOff, YOff, NumVs;
61    register IntPoint *Vs;
62 {
63    register XPoint *v;
64    register int i;
65    int real_x_off, real_y_off;
66 
67    real_x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
68    real_y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
69 
70    v = (XPoint*)malloc((NumVs+1)*sizeof(XPoint));
71    if (v == NULL) FailAllocMessage();
72    for (i = 0; i < NumVs; i++) {
73       v[i].x = (short)ZOOMED_SIZE(Vs[i].x-real_x_off);
74       v[i].y = (short)ZOOMED_SIZE(Vs[i].y-real_y_off);
75    }
76    return v;
77 }
78 
DumpPoints(FP,NumPts,V,Indent)79 void DumpPoints(FP, NumPts, V, Indent)
80    FILE *FP;
81    int NumPts, Indent;
82    IntPoint *V;
83 {
84    register int i, j;
85 
86    for (i=1; i < NumPts; i++) {
87       for (j = 0; j < Indent; j++) fprintf(FP, " ");
88       fprintf(FP, "%1d %1d %s\n", V[i].x, V[i].y, gPsCmd[PS_LINETO]);
89    }
90 }
91 
92 static
DumpJustPolygonPath(FP,Vs,NumPts,Smooth,Curved)93 void DumpJustPolygonPath(FP, Vs, NumPts, Smooth, Curved)
94    FILE *FP;
95    IntPoint *Vs;
96    char *Smooth;
97    int NumPts, Curved;
98 {
99    fprintf(FP, "%s\n", gPsCmd[PS_NEWPATH]);
100    if (Curved == LT_INTSPLINE) {
101       DumpCurvedPolygonPoints(FP, Curved, NumPts, Vs, 3);
102    } else {
103       DumpMultiCurvedPolygonPoints(FP, Smooth, Curved, NumPts, Vs, 3);
104    }
105    fprintf(FP, "%s\n", gPsCmd[PS_CLOSEPATH]);
106 }
107 
108 static
DumpPolygonPath(FP,ObjPtr,Vs,NumPts,Width,Pen,Fill,Dash,TransPat)109 void DumpPolygonPath(FP, ObjPtr, Vs, NumPts, Width, Pen, Fill, Dash, TransPat)
110    FILE *FP;
111    struct ObjRec *ObjPtr;
112    IntPoint *Vs;
113    int NumPts, Width, Pen, Fill, Dash, TransPat;
114 {
115    register int i;
116    int w_is_int=TRUE;
117    char *width_spec=ObjPtr->detail.g->width_spec;
118    double dw=GetWidthInDouble(Width, width_spec, &w_is_int);
119 
120    if (Fill != (-1) && Pen == (-1)) {
121       /* dumping the fill */
122       switch (Fill) {
123       case SOLIDPAT: fprintf(FP, "   %s\n", gPsCmd[PS_EOFILL]); break;
124       case BACKPAT:
125          if (!TransPat) {
126             fprintf(FP, "   1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_EOFILL]);
127          }
128          break;
129       default:
130          if (colorDump || !useGray) {
131             if (preDumpSetup) PSUseColorPattern();
132             fprintf(FP, "   %s %s\n", gPsCmd[PS_EOCLIP], gPsCmd[PS_NEWPATH]);
133             for (i=0; i < 3; i++) fprintf(FP, " ");
134             DumpPatFill(FP, Fill, ObjPtr->bbox, 0, TRUE);
135          } else {
136             GrayCheck(Fill);
137             for (i=0; i < 3; i++) fprintf(FP, " ");
138             fprintf(FP, "%s %s\n", GrayStr(Fill), gPsCmd[PS_SETGRAY]);
139             fprintf(FP, "   %s\n", gPsCmd[PS_EOFILL]);
140          }
141          break;
142       }
143    } else if (Fill == (-1) && Pen != (-1)) {
144       /* dumping the pen */
145       if (ObjPtr->ctm != NULL) {
146          fprintf(FP, "   %s\n", &(gPsCmd[PS_TGIFSETMATRIX])[1]);
147       }
148       if (w_is_int) {
149          if (Width != 1) {
150             fprintf(FP, "   %1d %s\n", Width, gPsCmd[PS_SETLINEWIDTH]);
151          }
152       } else {
153          fprintf(FP, "   %.3f %s\n", dw, gPsCmd[PS_SETLINEWIDTH]);
154       }
155       if (Dash != 0) {
156          fprintf(FP, "   [");
157          for (i = 0; i < dashListLength[Dash]-1; i++) {
158             fprintf(FP, "%1d ", (int)(dashList[Dash][i]));
159          }
160          fprintf(FP, "%1d] 0 %s\n",
161                (int)(dashList[Dash][dashListLength[Dash]-1]),
162                gPsCmd[PS_SETDASH]);
163       }
164       switch (Pen) {
165       case SOLIDPAT: fprintf(FP, "   %s\n", gPsCmd[PS_STROKE]); break;
166       case BACKPAT:
167          if (!TransPat) {
168             fprintf(FP, "   1 %s %s 0 %s\n", gPsCmd[PS_SETGRAY],
169                   gPsCmd[PS_STROKE], gPsCmd[PS_SETGRAY]);
170          }
171          break;
172       default:
173          if (colorDump || !useGray) {
174             if (preDumpSetup) PSUseColorPattern();
175             fprintf(FP, "   %s\n", gPsCmd[PS_FLATTENPATH]);
176             for (i=0; i < 3; i++) fprintf(FP, " ");
177             DumpPatFill(FP, Pen, ObjPtr->bbox, 0, TRUE);
178          } else {
179             GrayCheck(Pen);
180             fprintf(FP, "   %s %s\n", GrayStr(Pen), gPsCmd[PS_SETGRAY]);
181             fprintf(FP, "   %s\n", gPsCmd[PS_STROKE]);
182          }
183          break;
184       }
185    }
186 }
187 
DumpPolygonObj(FP,ObjPtr)188 void DumpPolygonObj(FP, ObjPtr)
189    FILE *FP;
190    struct ObjRec *ObjPtr;
191 {
192    IntPoint *v=NULL, *intv=NULL;
193    int num_pts=0, trans_pat, fill, width, pen, curved, dash, color_index, intn;
194    char *smooth=NULL;
195 
196    trans_pat = ObjPtr->trans_pat;
197    fill = ObjPtr->detail.g->fill;
198    width = ObjPtr->detail.g->width;
199    pen = ObjPtr->detail.g->pen;
200    curved = ObjPtr->detail.g->curved;
201    dash = ObjPtr->detail.g->dash;
202    intv = ObjPtr->detail.g->intvlist;
203    intn = ObjPtr->detail.g->intn;
204    if (curved == LT_STRUCT_SPLINE) {
205       v = ObjPtr->detail.g->ssvlist;
206       num_pts = ObjPtr->detail.g->ssn;
207       smooth = ObjPtr->detail.g->ssmooth;
208    } else {
209       v = ObjPtr->detail.g->vlist;
210       num_pts = ObjPtr->detail.g->n;
211       smooth = ObjPtr->detail.g->smooth;
212    }
213 
214    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
215          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
216       return;
217    }
218    fprintf(FP, "%% POLYGON/CLOSED-SPLINE\n");
219    color_index = ObjPtr->color;
220    DumpRGBColorLine(FP, color_index, 0, TRUE);
221 
222    if (ObjPtr->ctm != NULL) {
223       float m[6];
224 
225       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
226       m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
227       m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
228       m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
229       m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
230       fprintf(FP, "   %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
231             gPsCmd[PS_TRANSLATE]);
232       fprintf(FP, "   [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
233             m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
234             ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
235       fprintf(FP, "   %1d %s %1d %s %s\n",
236             ObjPtr->x, gPsCmd[PS_NEG], ObjPtr->y, gPsCmd[PS_NEG],
237             gPsCmd[PS_TRANSLATE]);
238    }
239    if (curved != LT_INTSPLINE) {
240       DumpJustPolygonPath(FP, v, num_pts, smooth, curved);
241    } else {
242       DumpJustPolygonPath(FP, intv, intn, smooth, curved);
243    }
244    fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
245 
246    if (fill != NONEPAT) {
247       if (curved != LT_INTSPLINE) {
248          if ((colorDump || !useGray) && fill > BACKPAT && !trans_pat) {
249             DumpPolygonPath(FP, ObjPtr, v, num_pts, width, (-1), BACKPAT, 0,
250                   trans_pat);
251             fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
252             fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
253          }
254          DumpPolygonPath(FP, ObjPtr, v, num_pts, width, (-1), fill, 0,
255                   trans_pat);
256       } else {
257          if ((colorDump || !useGray) && fill > BACKPAT && !trans_pat) {
258             DumpPolygonPath(FP, ObjPtr, intv, intn, width, (-1), BACKPAT, 0,
259                   trans_pat);
260             fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
261             fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
262          }
263          DumpPolygonPath(FP, ObjPtr, intv, intn, width, (-1), fill, 0,
264                   trans_pat);
265       }
266    }
267    if (pen != NONEPAT) {
268       fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
269       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
270       if (curved != LT_INTSPLINE) {
271          if ((colorDump || !useGray) && pen > BACKPAT && !trans_pat) {
272             DumpPolygonPath(FP, ObjPtr, v, num_pts, width, BACKPAT, (-1), 0,
273                   trans_pat);
274             fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
275             fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
276          }
277          DumpPolygonPath(FP, ObjPtr, v, num_pts, width, pen, (-1), dash,
278                   trans_pat);
279       } else {
280          if ((colorDump || !useGray) && pen > BACKPAT && !trans_pat) {
281             DumpPolygonPath(FP, ObjPtr, intv, intn, width, BACKPAT, (-1), 0,
282                   trans_pat);
283             fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
284             fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
285          }
286          DumpPolygonPath(FP, ObjPtr, intv, intn, width, pen, (-1), dash,
287                   trans_pat);
288       }
289    }
290    fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
291    if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
292    fprintf(FP, "\n");
293 }
294 
NeedsToCachePolygonObj(ObjPtr)295 int NeedsToCachePolygonObj(ObjPtr)
296    struct ObjRec *ObjPtr;
297 {
298    return (ObjPtr->ctm != NULL);
299 }
300 
301 static
MakeCachedPolygon(ObjPtr)302 void MakeCachedPolygon(ObjPtr)
303    struct ObjRec *ObjPtr;
304 {
305    register int i;
306    struct PolygonRec *polygon_ptr=ObjPtr->detail.g;
307    IntPoint *v=polygon_ptr->vlist, *pv=NULL, *pv1=NULL;
308    int num_pts=polygon_ptr->n, num_pts1=0;
309 
310    if (ObjPtr->ctm == NULL) return;
311 
312    if (polygon_ptr->rotated_vlist != NULL) free(polygon_ptr->rotated_vlist);
313    polygon_ptr->rotated_n = 0;
314    polygon_ptr->rotated_vlist = NULL;
315 
316    if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
317       v = polygon_ptr->ssvlist;
318       num_pts = polygon_ptr->ssn;
319    }
320    pv = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
321    if (pv == NULL) {
322       FailAllocMessage();
323       return;
324    }
325    for (i=0; i < num_pts; i++) {
326       int x, y;
327 
328       TransformPointThroughCTM(v[i].x-ObjPtr->x, v[i].y-ObjPtr->y,
329             ObjPtr->ctm, &x, &y);
330       pv[i].x = x+ObjPtr->x;
331       pv[i].y = y+ObjPtr->y;
332    }
333    switch (polygon_ptr->curved) {
334    case LT_STRAIGHT:
335    case LT_SPLINE:
336       polygon_ptr->rotated_vlist = MakeMultiSplinePolygonVertex(
337             polygon_ptr->curved, &(polygon_ptr->rotated_n),
338             polygon_ptr->smooth, drawOrigX, drawOrigY, num_pts, pv);
339       break;
340    case LT_STRUCT_SPLINE:
341       polygon_ptr->rotated_vlist = MakeMultiSplinePolygonVertex(
342             polygon_ptr->curved, &(polygon_ptr->rotated_n),
343             polygon_ptr->ssmooth, drawOrigX, drawOrigY, num_pts, pv);
344       break;
345    case LT_INTSPLINE:
346       polygon_ptr->rotated_vlist = MakeIntSplinePolygonVertex(
347             &(polygon_ptr->rotated_n), &(num_pts1), &(pv1),
348             drawOrigX, drawOrigY, num_pts, pv);
349       free(pv1);
350       break;
351    }
352    free(pv);
353 }
354 
DrawPolygonObj(Win,XOff,YOff,ObjPtr)355 void DrawPolygonObj(Win, XOff, YOff, ObjPtr)
356    Window Win;
357    int XOff, YOff;
358    struct ObjRec *ObjPtr;
359 {
360    struct PolygonRec *polygon_ptr=ObjPtr->detail.g;
361    XPoint *v;
362    int trans_pat, fill, width, pen, dash, pixel, num_pts;
363    XGCValues values;
364 
365    trans_pat = ObjPtr->trans_pat;
366    fill = polygon_ptr->fill;
367    width = polygon_ptr->width;
368    pen = polygon_ptr->pen;
369    dash = polygon_ptr->dash;
370    pixel = colorPixels[ObjPtr->color];
371 
372    if (NeedsToCachePolygonObj(ObjPtr) && polygon_ptr->rotated_vlist==NULL) {
373       MakeCachedPolygon(ObjPtr);
374    }
375    if (userDisableRedraw) return;
376 
377    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
378          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
379       return;
380    }
381    v = polygon_ptr->svlist;
382    num_pts = polygon_ptr->sn;
383 
384    if (fill != 0) {
385       values.foreground = GetDrawingBgPixel(fill, pixel);
386       values.function = GXcopy;
387       values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
388       values.stipple = patPixmap[fill];
389       XChangeGC(mainDisplay, drawGC,
390             GCForeground | GCFunction | GCFillStyle | GCStipple, &values);
391       if (ObjPtr->ctm == NULL) {
392          XFillPolygon(mainDisplay, Win, drawGC, v, num_pts, Complex,
393                CoordModeOrigin);
394       } else {
395          XFillPolygon(mainDisplay, Win, drawGC, polygon_ptr->rotated_vlist,
396                polygon_ptr->rotated_n, Complex, CoordModeOrigin);
397       }
398    }
399 
400    if (pen == NONEPAT) return;
401 
402    values.foreground = GetDrawingBgPixel(pen, pixel);
403    values.function = GXcopy;
404    values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
405    values.stipple = patPixmap[pen];
406    values.line_width = ZOOMED_SIZE(width);
407 #ifdef NO_THIN_LINE
408    if (values.line_width < 1) values.line_width = 1;
409 #endif
410    values.join_style = JoinBevel;
411    if (dash != 0) {
412       XSetDashes(mainDisplay, drawGC, 0, dashList[dash],
413             dashListLength[dash]);
414       values.line_style = LineOnOffDash;
415    } else {
416       values.line_style = LineSolid;
417    }
418    XChangeGC(mainDisplay, drawGC,
419          GCForeground | GCFunction | GCFillStyle | GCStipple |
420          GCLineWidth | GCLineStyle | GCJoinStyle, &values);
421 
422    if (ObjPtr->ctm == NULL) {
423       XDrawLines(mainDisplay, Win, drawGC, v, num_pts, CoordModeOrigin);
424    } else {
425       XDrawLines(mainDisplay, Win, drawGC, polygon_ptr->rotated_vlist,
426             polygon_ptr->rotated_n, CoordModeOrigin);
427    }
428    values.join_style = JoinMiter;
429    XChangeGC(mainDisplay, drawGC, GCJoinStyle, &values);
430 }
431 
432 #define CREATE_RELATIVE (FALSE)
433 #define CREATE_ABSOLUTE (TRUE)
434 
CreatePolygonObj(NumPts,CreateAbsolute)435 void CreatePolygonObj(NumPts, CreateAbsolute)
436    int NumPts;
437    int CreateAbsolute;
438 {
439    register int i;
440    struct PtRec *pt_ptr=NULL, *next_pt=NULL;
441    struct PolygonRec *polygon_ptr=NULL;
442    struct ObjRec *obj_ptr=NULL;
443    IntPoint *v=NULL;
444    int width, w, ltx, lty, rbx, rby, num_ss_pts=0;
445    char *smooth=NULL;
446    CVListElem *elem=NULL;
447    IntPointTriplet *pipt=NULL;
448 
449    polygon_ptr = (struct PolygonRec *)malloc(sizeof(struct PolygonRec));
450    if (polygon_ptr == NULL) FailAllocMessage();
451    memset(polygon_ptr, 0, sizeof(struct PolygonRec));
452    if (curSpline == LT_STRUCT_SPLINE) {
453       num_ss_pts = ((NumPts-1)*3)+1;
454       polygon_ptr->n = num_ss_pts;
455       v = (IntPoint*)malloc((num_ss_pts+1)*sizeof(IntPoint));
456       if (v == NULL) FailAllocMessage();
457       smooth = (char*)malloc((num_ss_pts+1)*sizeof(char));
458       if (smooth == NULL) FailAllocMessage();
459       elem = ListLast(&gStructSplineList);
460       pipt = (IntPointTriplet*)(elem->obj);
461       ltx = rbx = pipt->hinge_pt.x;
462       lty = rby = pipt->hinge_pt.y;
463 
464       for (i=NumPts-1; i >= 0; i--, elem=ListPrev(&gStructSplineList, elem)) {
465          pipt = (IntPointTriplet*)(elem->obj);
466          if (i == 0) {
467             v[0].x = CreateAbsolute ? pipt->hinge_pt.x :
468                   ABS_X(pipt->hinge_pt.x);
469             v[0].y = CreateAbsolute ? pipt->hinge_pt.y :
470                   ABS_Y(pipt->hinge_pt.y);
471             if (pipt->later_valid) {
472                v[1].x = CreateAbsolute ? pipt->later_smooth_pt.x :
473                      ABS_X(pipt->later_smooth_pt.x);
474                v[1].y = CreateAbsolute ? pipt->later_smooth_pt.y :
475                      ABS_Y(pipt->later_smooth_pt.y);
476                smooth[1] = TRUE;
477             } else {
478                v[1].x = v[0].x;
479                v[1].y = v[0].y;
480                smooth[1] = FALSE;
481             }
482             smooth[0] = FALSE;
483          } else if (i == NumPts-1) {
484             v[num_ss_pts-1].x = CreateAbsolute ? pipt->hinge_pt.x :
485                   ABS_X(pipt->hinge_pt.x);
486             v[num_ss_pts-1].y = CreateAbsolute ? pipt->hinge_pt.y :
487                   ABS_Y(pipt->hinge_pt.y);
488             if (pipt->earlier_valid) {
489                v[num_ss_pts-2].x = CreateAbsolute ? pipt->earlier_smooth_pt.x :
490                      ABS_X(pipt->earlier_smooth_pt.x);
491                v[num_ss_pts-2].y = CreateAbsolute ? pipt->earlier_smooth_pt.y :
492                      ABS_Y(pipt->earlier_smooth_pt.y);
493                smooth[num_ss_pts-2] = TRUE;
494             } else {
495                v[num_ss_pts-2].x = v[num_ss_pts-1].x;
496                v[num_ss_pts-2].y = v[num_ss_pts-1].y;
497                smooth[num_ss_pts-2] = FALSE;
498             }
499             smooth[num_ss_pts-1] = FALSE;
500          } else {
501             int index=3*i;
502 
503             v[index-1].x = CreateAbsolute ? pipt->earlier_smooth_pt.x :
504                   ABS_X(pipt->earlier_smooth_pt.x);
505             v[index-1].y = CreateAbsolute ? pipt->earlier_smooth_pt.y :
506                   ABS_Y(pipt->earlier_smooth_pt.y);
507             v[index].x = CreateAbsolute ? pipt->hinge_pt.x :
508                   ABS_X(pipt->hinge_pt.x);
509             v[index].y = CreateAbsolute ? pipt->hinge_pt.y :
510                   ABS_Y(pipt->hinge_pt.y);
511             v[index+1].x = CreateAbsolute ? pipt->later_smooth_pt.x :
512                   ABS_X(pipt->later_smooth_pt.x);
513             v[index+1].y = CreateAbsolute ? pipt->later_smooth_pt.y :
514                   ABS_Y(pipt->later_smooth_pt.y);
515             smooth[index-1] = pipt->earlier_valid;
516             smooth[index] = FALSE;
517             smooth[index+1] = pipt->later_valid;
518          }
519          free(pipt);
520       }
521       for (i=0; i < num_ss_pts; i++) {
522          if (v[i].x < ltx) ltx = v[i].x;
523          if (v[i].y < lty) lty = v[i].y;
524          if (v[i].x > rbx) rbx = v[i].x;
525          if (v[i].y > rby) rby = v[i].y;
526       }
527       numPtsInPoly = 0;
528       ListUnlinkAll(&gStructSplineList);
529    } else {
530       polygon_ptr->n = NumPts;
531       v = (IntPoint*)malloc((NumPts+1)*sizeof(IntPoint));
532       if (v == NULL) FailAllocMessage();
533       if (curSpline != LT_INTSPLINE) {
534          smooth = (char*)malloc((NumPts+1)*sizeof(char));
535          if (smooth == NULL) FailAllocMessage();
536       }
537       pt_ptr = lastPtPtr;
538       ltx = rbx = pt_ptr->x;
539       lty = rby = pt_ptr->y;
540       for (i=NumPts-1; i >= 0; i--, lastPtPtr = next_pt) {
541          next_pt = lastPtPtr->next;
542          v[i].x = CreateAbsolute ? lastPtPtr->x : ABS_X(lastPtPtr->x);
543          v[i].y = CreateAbsolute ? lastPtPtr->y : ABS_Y(lastPtPtr->y);
544          if (curSpline != LT_INTSPLINE) {
545             if (lastPtPtr->x < ltx) ltx = lastPtPtr->x;
546             if (lastPtPtr->y < lty) lty = lastPtPtr->y;
547             if (lastPtPtr->x > rbx) rbx = lastPtPtr->x;
548             if (lastPtPtr->y > rby) rby = lastPtPtr->y;
549             smooth[i] = (curSpline != LT_STRAIGHT);
550          }
551          free(lastPtPtr);
552       }
553       numPtsInPoly = 0;
554       lastPtPtr = NULL;
555    }
556    polygon_ptr->vlist = v;
557    polygon_ptr->smooth = smooth;
558    polygon_ptr->svlist = NULL;
559    polygon_ptr->intvlist = NULL;
560    polygon_ptr->fill = objFill;
561    polygon_ptr->width = width = curWidthOfLine[lineWidth];
562    UtilStrCpyN(polygon_ptr->width_spec, sizeof(polygon_ptr->width_spec),
563          curWidthOfLineSpec[lineWidth]);
564    polygon_ptr->pen = penPat;
565    polygon_ptr->curved = curSpline;
566    polygon_ptr->dash = curDash;
567    /*
568     * polygon_ptr->tighter = (curSpline == LT_STRUCT_SPLINE) ?
569     *       tighterStructSplines : FALSE;
570     */
571    polygon_ptr->rotated_n = 0;
572    polygon_ptr->rotated_vlist = NULL;
573 
574    obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
575    if (obj_ptr == NULL) FailAllocMessage();
576    memset(obj_ptr, 0, sizeof(struct ObjRec));
577    obj_ptr->detail.g = polygon_ptr;
578 
579    obj_ptr->color = colorIndex;
580    if (mainDisplay != NULL) {
581       UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
582             colorMenuItems[colorIndex]);
583    }
584    obj_ptr->type = OBJ_POLYGON;
585    if (CreateAbsolute) {
586       obj_ptr->bbox.ltx = obj_ptr->obbox.ltx = obj_ptr->x = ltx;
587       obj_ptr->bbox.lty = obj_ptr->obbox.lty = obj_ptr->y = lty;
588       obj_ptr->bbox.rbx = obj_ptr->obbox.rbx = rbx;
589       obj_ptr->bbox.rby = obj_ptr->obbox.rby = rby;
590    } else {
591       obj_ptr->bbox.ltx = obj_ptr->obbox.ltx = obj_ptr->x = ABS_X(ltx);
592       obj_ptr->bbox.lty = obj_ptr->obbox.lty = obj_ptr->y = ABS_Y(lty);
593       obj_ptr->bbox.rbx = obj_ptr->obbox.rbx = ABS_X(rbx);
594       obj_ptr->bbox.rby = obj_ptr->obbox.rby = ABS_Y(rby);
595    }
596    w = HALF_W(width);
597    obj_ptr->bbox.ltx -= w;
598    obj_ptr->bbox.lty -= w;
599    obj_ptr->bbox.rbx += w;
600    obj_ptr->bbox.rby += w;
601    obj_ptr->id = objId++;
602    obj_ptr->dirty = FALSE;
603    obj_ptr->rotation = 0;
604    obj_ptr->locked = FALSE;
605    obj_ptr->fattr = obj_ptr->lattr = NULL;
606    obj_ptr->ctm = NULL;
607    obj_ptr->invisible = FALSE;
608    obj_ptr->trans_pat = transPat;
609 
610    AdjObjSplineVs(obj_ptr);
611    if (curSpline != LT_INTSPLINE) {
612       UpdPolyBBox(obj_ptr, polygon_ptr->n, polygon_ptr->vlist);
613    } else {
614       UpdPolyBBox(obj_ptr, polygon_ptr->intn, polygon_ptr->intvlist);
615    }
616    AdjObjBBox(obj_ptr);
617    AddObj(NULL, topObj, obj_ptr);
618 }
619 
ResetCreatePolygon()620 void ResetCreatePolygon()
621 {
622    numPtsInPoly = 0;
623    lastPtPtr = NULL;
624 }
625 
AddPtToCreatePolygon(AbsX,AbsY)626 void AddPtToCreatePolygon(AbsX, AbsY)
627    int AbsX, AbsY;
628 {
629    struct PtRec *pt_ptr=(struct PtRec *)malloc(sizeof(struct PtRec));
630 
631    if (pt_ptr == NULL) FailAllocMessage();
632    memset(pt_ptr, 0, sizeof(struct PtRec));
633    pt_ptr->next = lastPtPtr;
634    numPtsInPoly++;
635    lastPtPtr = pt_ptr;
636    pt_ptr->x = AbsX;
637    pt_ptr->y = AbsY;
638 }
639 
640 #define POLYGON_DRAW  (FALSE)
641 #define POLYGON_ERASE (TRUE)
642 #define POLYGON_CLICK (FALSE)
643 #define POLYGON_DRAG  (TRUE)
644 
645 #define POLYGON_STARTSHOW 0
646 #define POLYGON_DOSHOW    1
647 #define POLYGON_ENDSHOW   2
648 
649 typedef struct tagPolygonMeasureCursorInfo {
650    IntPoint first_pt;
651    IntPoint prev_prev_pt;
652    IntPoint prev_pt;
653 } PolygonMeasureCursorInfo;
654 
655 static
DoPolygonMeasureCursor(ppmci,start,num_pts,x,y,dx,dy,erase,drag,closed)656 void DoPolygonMeasureCursor(ppmci, start, num_pts, x, y, dx, dy, erase, drag,
657       closed)
658    PolygonMeasureCursorInfo *ppmci;
659    int start, num_pts, x, y, dx, dy, erase, drag, closed;
660 {
661    char buf[80], w_buf[80], h_buf[80], x_buf[80], y_buf[80], a_buf[80];
662    int angle2=0;
663 
664    if (erase == POLYGON_DRAW && drag == POLYGON_CLICK) {
665       if (num_pts == 1) {
666          ppmci->first_pt.x = ppmci->prev_pt.x = ppmci->prev_prev_pt.x = x;
667          ppmci->first_pt.y = ppmci->prev_pt.y = ppmci->prev_prev_pt.y = y;
668       } else {
669          ppmci->prev_prev_pt.x = ppmci->prev_pt.x;
670          ppmci->prev_prev_pt.y = ppmci->prev_pt.y;
671          ppmci->prev_pt.x = x;
672          ppmci->prev_pt.y = y;
673       }
674    }
675    if (x == ppmci->prev_pt.x && y == ppmci->prev_pt.y) {
676       strcpy(a_buf, "0");
677    } else if (num_pts == 1) {
678       PointsToArc(ppmci->prev_pt.x, ppmci->prev_pt.y, ppmci->prev_pt.x+100,
679             ppmci->prev_pt.y, x, y, ARC_CCW, FALSE, NULL, NULL, NULL, NULL,
680             NULL, &angle2);
681       if (angle2 > 180*64) angle2=(360*64)-angle2;
682       FormatAngle(angle2, a_buf);
683    } else if (closed) {
684       if (x == ppmci->first_pt.x && y == ppmci->first_pt.y) {
685          strcpy(a_buf, "0");
686       } else {
687          PointsToArc(x, y, ppmci->first_pt.x, ppmci->first_pt.y,
688                ppmci->prev_pt.x, ppmci->prev_pt.y, ARC_CCW, FALSE, NULL, NULL,
689                NULL, NULL, NULL, &angle2);
690          if (angle2 > 180*64) angle2=(360*64)-angle2;
691          FormatAngle(angle2, a_buf);
692       }
693    } else {
694       PointsToArc(ppmci->prev_pt.x, ppmci->prev_pt.y, ppmci->prev_prev_pt.x,
695             ppmci->prev_prev_pt.y, x, y, ARC_CCW, FALSE, NULL, NULL, NULL, NULL,
696             NULL, &angle2);
697       if (angle2 > 180*64) angle2=(360*64)-angle2;
698       FormatAngle(angle2, a_buf);
699    }
700    PixelToMeasurementUnit(w_buf, dx);
701    PixelToMeasurementUnit(h_buf, dy);
702    PixelToMeasurementUnit(x_buf, x);
703    PixelToMeasurementUnit(y_buf, y);
704    sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s\nangle=%s", w_buf, h_buf, x_buf, y_buf,
705          a_buf);
706 
707    x = OFFSET_X(x);
708    y = OFFSET_Y(y);
709    switch (start) {
710    case POLYGON_STARTSHOW: StartShowMeasureCursor(x, y, buf, TRUE); break;
711    case POLYGON_DOSHOW: ShowMeasureCursor(x, y, buf, TRUE); break;
712    case POLYGON_ENDSHOW: EndShowMeasureCursor(x, y, buf, TRUE); break;
713    }
714 }
715 
716 static
EraseStructSplineLinesForCont(OrigX,OrigY,grid_x,grid_y,sv,sn,sv2,sn2)717 void EraseStructSplineLinesForCont(OrigX, OrigY, grid_x, grid_y, sv, sn, sv2,
718       sn2)
719    int OrigX, OrigY, grid_x, grid_y, sn, sn2;
720    XPoint *sv, *sv2;
721 {
722    if (sv == NULL && sv2 == NULL) {
723       XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, grid_x, grid_y);
724    } else  {
725       if (sv != NULL) {
726          XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn, CoordModeOrigin);
727       }
728       if (sv2 != NULL) {
729          XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2, CoordModeOrigin);
730       }
731    }
732 }
733 
734 static
ContinueForStructSplinePolygonControlPoints(OrigX,OrigY,LastX,LastY,psv,psn,psv2,psn2,pipt_first,pipt_prev,pipt,pn_abort)735 void ContinueForStructSplinePolygonControlPoints(OrigX, OrigY, LastX, LastY,
736       psv, psn, psv2, psn2, pipt_first, pipt_prev, pipt, pn_abort)
737    int OrigX, OrigY, LastX, LastY, *psn, *psn2, *pn_abort;
738    XPoint **psv, **psv2;
739    IntPointTriplet *pipt_first, *pipt_prev, *pipt;
740 {
741    int i=0, done=FALSE, grid_x=0, grid_y=0, end_x=0, end_y=0, n=2;
742    int sn=(*psn), orig_sn=(*psn), sn2=(*psn2), orig_sn2=(*psn2);
743    int num_pts=1, first_time=TRUE;
744    IntPoint v[4];
745    XPoint *sv=NULL, *orig_sv=(*psv), *sv2=NULL, *orig_sv2=(*psv2), dash_vs[2];
746    PolygonMeasureCursorInfo pmci;
747    XGCValues values;
748 
749    *pn_abort = FALSE;
750 
751    if (orig_sv != NULL) {
752       sv = (XPoint*)malloc(orig_sn*sizeof(XPoint));
753       if (sv == NULL) FailAllocMessage();
754       memset(sv, 0, orig_sn*sizeof(XPoint));
755       for (i=0; i < orig_sn; i++) {
756          sv[i].x = orig_sv[i].x;
757          sv[i].y = orig_sv[i].y;
758       }
759       sn = orig_sn;
760    }
761    if (orig_sv2 != NULL) {
762       sv2 = (XPoint*)malloc(orig_sn2*sizeof(XPoint));
763       if (sv2 == NULL) FailAllocMessage();
764       memset(sv2, 0, orig_sn2*sizeof(XPoint));
765       for (i=0; i < orig_sn2; i++) {
766          sv2[i].x = orig_sv2[i].x;
767          sv2[i].y = orig_sv2[i].y;
768       }
769       sn2 = orig_sn2;
770    }
771    memset(pipt, 0, sizeof(IntPointTriplet));
772    pipt->earlier_valid = pipt->later_valid = FALSE;
773    pipt->hinge_pt.x = pipt->earlier_smooth_pt.x = pipt->later_smooth_pt.x =
774          LastX;
775    pipt->hinge_pt.y = pipt->earlier_smooth_pt.y = pipt->later_smooth_pt.y =
776          LastY;
777    pipt->ratio = (double)1;
778 
779    XSetDashes(mainDisplay, revDefaultGC, 0, dashList[8], dashListLength[8]);
780 
781    grid_x = end_x = dash_vs[0].x = dash_vs[1].x = LastX;
782    grid_y = end_y = dash_vs[0].y = dash_vs[1].y = LastY;
783    v[0].x = ABS_X(OrigX);
784    v[0].y = ABS_Y(OrigY);
785    v[1].x = ABS_X(LastX);
786    v[1].y = ABS_Y(LastY);
787    n = 2;
788    MARKHR(drawWindow, revDefaultGC, LastX, LastY);
789 
790    /* the previous curve has already been drawn */
791    /* draw the measure cursor */
792    DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts, ABS_X(grid_x),
793          ABS_Y(grid_y), 0, 0, POLYGON_ERASE, POLYGON_DRAG);
794    while (!done) {
795       XEvent input, ev;
796 
797       XNextEvent(mainDisplay, &input);
798 
799       if (input.type == Expose || input.type == VisibilityNotify) {
800          ExposeEventHandler(&input, TRUE);
801          SetXorDrawGC(colorIndex);
802       } else if (input.type == MotionNotify) {
803          end_x = input.xmotion.x;
804          end_y = input.xmotion.y;
805 
806          /* erase */
807          if (first_time || grid_x != LastX || grid_y != LastY) {
808             EraseStructSplineLinesForCont(OrigX, OrigY, grid_x, grid_y, sv, sn,
809                   sv2, sn2);
810             if (!pipt_first->earlier_valid && sv != NULL && sv2 == NULL) {
811                XDrawLine(mainDisplay, drawWindow, drawGC, grid_x, grid_y,
812                      pipt_first->earlier_smooth_pt.x,
813                      pipt_first->earlier_smooth_pt.y);
814             }
815             first_time = FALSE;
816          } else {
817             if (orig_sv != NULL || orig_sv2 != NULL) {
818                if (orig_sv != NULL) {
819                   XDrawLines(mainDisplay, drawWindow, drawGC, orig_sv, orig_sn,
820                         CoordModeOrigin);
821                }
822                if (orig_sv2 != NULL) {
823                   XDrawLines(mainDisplay, drawWindow, drawGC, orig_sv2,
824                         orig_sn2, CoordModeOrigin);
825                }
826             } else {
827                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, LastX,
828                      LastY);
829             }
830          }
831          DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts, ABS_X(grid_x),
832                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
833                ABS_SIZE(abs(grid_y-LastY)), POLYGON_ERASE, POLYGON_DRAG);
834          MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
835          MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
836          values.line_style = LineOnOffDash;
837          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
838          MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
839          values.line_style = LineSolid;
840          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
841 
842          /* draw */
843          GridXY(end_x, end_y, &grid_x, &grid_y);
844          MarkRulers(grid_x, grid_y);
845          if (grid_x != LastX || grid_y != LastY) {
846             if (sv != NULL) {
847                free(sv);
848                sv = NULL;
849             }
850             if (sv2 != NULL) {
851                free(sv2);
852                sv2 = NULL;
853             }
854             v[0].x = ABS_X(OrigX);
855             v[0].y = ABS_Y(OrigY);
856             if (pipt_prev->later_valid) {
857                v[1].x = ABS_X(pipt_prev->later_smooth_pt.x);
858                v[1].y = ABS_Y(pipt_prev->later_smooth_pt.y);
859                n = 4;
860             } else {
861                n = 3;
862             }
863             v[n-2].x = ABS_X((LastX<<1)-grid_x);
864             v[n-2].y = ABS_Y((LastY<<1)-grid_y);
865             v[n-1].x = ABS_X(LastX);
866             v[n-1].y = ABS_Y(LastY);
867             sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX, drawOrigY,
868                   n, v);
869             XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
870                   CoordModeOrigin);
871 
872             v[0].x = ABS_X(pipt_first->hinge_pt.x);
873             v[0].y = ABS_Y(pipt_first->hinge_pt.y);
874             if (pipt_first->earlier_valid) {
875                v[1].x = ABS_X(pipt_first->earlier_smooth_pt.x);
876                v[1].y = ABS_Y(pipt_first->earlier_smooth_pt.y);
877                n = 4;
878             } else {
879                n = 3;
880             }
881             v[n-2].x = ABS_X(grid_x);
882             v[n-2].y = ABS_Y(grid_y);
883             v[n-1].x = ABS_X(LastX);
884             v[n-1].y = ABS_Y(LastY);
885             sv2 = MakeSplinePolyVertex(0, curSpline, &sn2, drawOrigX, drawOrigY,
886                   n, v);
887             XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2,
888                   CoordModeOrigin);
889          } else {
890             if (orig_sv != NULL || orig_sv2 != NULL) {
891                if (orig_sv != NULL) {
892                   XDrawLines(mainDisplay, drawWindow, drawGC, orig_sv, orig_sn,
893                         CoordModeOrigin);
894                }
895                if (orig_sv2 != NULL) {
896                   XDrawLines(mainDisplay, drawWindow, drawGC, orig_sv2,
897                         orig_sn2, CoordModeOrigin);
898                }
899             } else {
900                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, LastX,
901                      LastY);
902             }
903          }
904          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
905 
906          dash_vs[0].x = grid_x;
907          dash_vs[0].y = grid_y;
908          dash_vs[1].x = (LastX<<1)-grid_x;
909          dash_vs[1].y = (LastY<<1)-grid_y;
910          pipt->later_smooth_pt.x = dash_vs[0].x;
911          pipt->later_smooth_pt.y = dash_vs[0].y;
912          pipt->earlier_smooth_pt.x = dash_vs[1].x;
913          pipt->earlier_smooth_pt.y = dash_vs[1].y;
914          if (grid_x == LastX && grid_y == LastY) {
915             pipt->earlier_valid = pipt->later_valid = FALSE;
916          } else {
917             pipt->earlier_valid = pipt->later_valid = TRUE;
918          }
919          MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
920          MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
921          values.line_style = LineOnOffDash;
922          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
923          MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
924          values.line_style = LineSolid;
925          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
926          DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts, ABS_X(grid_x),
927                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
928                ABS_SIZE(abs(grid_y-LastY)), POLYGON_DRAW, POLYGON_DRAG);
929       } else if (input.type == KeyPress) {
930          if (KeyPressEventIsEscape(&input.xkey)) {
931             /* erase */
932             DoPolygonMeasureCursor(&pmci, POLYGON_ENDSHOW, num_pts,
933                   ABS_X(grid_x), ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
934                   ABS_SIZE(abs(grid_y-LastY)), POLYGON_ERASE, POLYGON_DRAG);
935             MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
936             MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
937             values.line_style = LineOnOffDash;
938             XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
939             MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
940             values.line_style = LineSolid;
941             XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
942             Msg("");
943             *pn_abort = TRUE;
944             done = TRUE;
945          }
946       } else if (input.type == ButtonRelease) {
947          /* erase */
948          DoPolygonMeasureCursor(&pmci, POLYGON_ENDSHOW, num_pts, ABS_X(grid_x),
949                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
950                ABS_SIZE(abs(grid_y-LastY)), POLYGON_ERASE, POLYGON_DRAG);
951          MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
952          MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
953          values.line_style = LineOnOffDash;
954          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
955          MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
956          values.line_style = LineSolid;
957          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
958 
959          GridXY(input.xbutton.x, input.xbutton.y, &grid_x, &grid_y);
960          pipt->later_smooth_pt.x = grid_x;
961          pipt->later_smooth_pt.y = grid_y;
962          pipt->earlier_smooth_pt.x = (LastX<<1)-grid_x;
963          pipt->earlier_smooth_pt.y = (LastY<<1)-grid_y;
964          if (grid_x == LastX && grid_y == LastY) {
965             pipt->earlier_valid = pipt->later_valid = FALSE;
966             if (sv2 != NULL) {
967                free(sv2);
968                sv2 = NULL;
969 
970                v[0].x = ABS_X(pipt_first->hinge_pt.x);
971                v[0].y = ABS_Y(pipt_first->hinge_pt.y);
972                if (pipt_first->earlier_valid) {
973                   v[1].x = ABS_X(pipt_first->earlier_smooth_pt.x);
974                   v[1].y = ABS_Y(pipt_first->earlier_smooth_pt.y);
975                   n = 3;
976                } else {
977                   n = 2;
978                }
979                v[n-1].x = ABS_X(LastX);
980                v[n-1].y = ABS_Y(LastY);
981                if (n > 2) {
982                   sv2 = MakeSplinePolyVertex(0, curSpline, &sn2, drawOrigX,
983                         drawOrigY, n, v);
984                } else {
985                   XDrawLine(mainDisplay, drawWindow, drawGC,
986                         pipt_first->hinge_pt.x, pipt_first->hinge_pt.y,
987                         LastX, LastY);
988                }
989             }
990          } else {
991             pipt->earlier_valid = pipt->later_valid = TRUE;
992          }
993          done = TRUE;
994       }
995    }
996    MARKHR(drawWindow, revDefaultGC, LastX, LastY);
997 
998    *psv = sv;
999    *psn = sn;
1000    *psv2 = sv2;
1001    *psn2 = sn2;
1002 
1003    if (orig_sv != NULL) free(orig_sv);
1004    if (orig_sv2 != NULL) free(orig_sv2);
1005 }
1006 
1007 static
EraseStructSplineLinesForContAndUpdateSvs(OrigX,OrigY,grid_x,grid_y,pev,num_pts,psv,sn,psv2,sn2,pipt_prev,pipt_first)1008 void EraseStructSplineLinesForContAndUpdateSvs(OrigX, OrigY, grid_x, grid_y,
1009       pev, num_pts, psv, sn, psv2, sn2, pipt_prev, pipt_first)
1010    int OrigX, OrigY, grid_x, grid_y, sn, sn2;
1011    XEvent *pev;
1012    XPoint **psv, **psv2;
1013    IntPointTriplet *pipt_prev, *pipt_first;
1014 {
1015    XPoint *sv=(*psv), *sv2=(*psv2);
1016 
1017    /* erase */
1018    if (sv == NULL && sv2 != NULL && !pipt_prev->later_valid) {
1019       /* erase the straight line */
1020       XDrawLine(mainDisplay, drawWindow, drawGC,
1021             pipt_prev->later_smooth_pt.x, pipt_prev->later_smooth_pt.y,
1022             grid_x, grid_y);
1023    }
1024    EraseStructSplineLinesForCont(OrigX, OrigY, grid_x, grid_y, sv, sn, sv2,
1025          sn2);
1026    if ((pev->type == MotionNotify && num_pts > 1) ||
1027          (pev->type == ButtonPress && num_pts > 2)) {
1028       if (pipt_first->earlier_valid) {
1029          /* don't need to do anything here */
1030       } else {
1031          XDrawLine(mainDisplay, drawWindow, drawGC, pipt_first->hinge_pt.x,
1032                pipt_first->hinge_pt.y, grid_x, grid_y);
1033       }
1034    }
1035    if (sv != NULL) free(sv);
1036    if (sv2 != NULL) free(sv2);
1037    *psv = *psv2 = NULL;
1038 }
1039 
1040 static
CountStructuredSplinePolygonVs()1041 int CountStructuredSplinePolygonVs()
1042 {
1043    int i=0, len=ListLength(&gStructSplineList), num_vs=0;
1044    CVListElem *elem=NULL;
1045 
1046    for (i=0, elem=ListFirst(&gStructSplineList); elem != NULL;
1047          i++, elem=ListNext(&gStructSplineList, elem)) {
1048       IntPointTriplet *ipt=(IntPointTriplet*)(elem->obj);
1049 
1050       if (i == 0) {
1051          if (ipt->later_valid) {
1052             num_vs++;
1053          }
1054       } else if (i == len-1) {
1055          if (ipt->earlier_valid) {
1056             num_vs++;
1057          }
1058       } else {
1059          if (ipt->later_valid) {
1060             num_vs++;
1061          }
1062          if (ipt->earlier_valid) {
1063             num_vs++;
1064          }
1065       }
1066       num_vs++;
1067    }
1068    return num_vs;
1069 }
1070 
1071 #ifdef _TGIF_DBG
sync()1072 void sync()
1073 {
1074    XSync(mainDisplay,0);
1075 }
1076 #endif /* _TGIF_DBG */
1077 
1078 static XComposeStatus c_stat;
1079 
1080 static
ContinuePolygon(OrigX,OrigY)1081 void ContinuePolygon(OrigX, OrigY)
1082    int  OrigX, OrigY;
1083    /* OrigX and OrigY are screen coordinates (scaled and translated). */
1084 {
1085    register int i;
1086    XEvent input, ev;
1087    XButtonEvent *button_ev;
1088    XMotionEvent *motion_ev;
1089    KeySym key_sym;
1090    int start_polygon_x=OrigX, start_polygon_y=OrigY;
1091    int end_x, end_y, grid_x, grid_y, done=FALSE;
1092    int saved_x, saved_y, closed=FALSE, abort=FALSE;
1093    int num_pts=1, n=2, sn=0, sn2=0, max_n=40, intn=0, tmp_n=0;
1094    int ltx=OrigX, lty=OrigY, rbx=OrigX, rby=OrigY, nothing_is_drawn=TRUE;
1095    XPoint *sv=NULL, *sv2=NULL;
1096    IntPoint *pv=NULL, *cntrlv=NULL, tmp_vs[4];
1097    IntPointTriplet ipt_prev, ipt, first_ipt;
1098    PolygonMeasureCursorInfo pmci;
1099 
1100    memset(&ipt, 0, sizeof(IntPointTriplet));
1101    memset(&ipt_prev, 0, sizeof(IntPointTriplet));
1102    memset(&first_ipt, 0, sizeof(IntPointTriplet));
1103    memset(&pmci, 0, sizeof(PolygonMeasureCursorInfo));
1104    SetXorDrawGC(xorColorPixels[colorIndex]);
1105 
1106    grid_x = end_x = saved_x = OrigX;
1107    grid_y = end_y = saved_y = OrigY;
1108    if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1109       pv = (IntPoint*)malloc((max_n+1)*sizeof(IntPoint));
1110       if (pv == NULL) FailAllocMessage();
1111       pv[0].x = pv[1].x = pv[2].x = ABS_X(OrigX);
1112       pv[0].y = pv[1].y = pv[2].y = ABS_Y(OrigY);
1113       switch (curSpline) {
1114       case LT_SPLINE:
1115          sv = MakeSplinePolygonVertex(0, curSpline, &sn, drawOrigX, drawOrigY,
1116                n+1, pv);
1117          break;
1118       case LT_INTSPLINE:
1119          sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
1120                drawOrigX, drawOrigY, n+1, pv);
1121          for (i=0; i < sn; i++) {
1122             if (sv[i].x < ltx) ltx = sv[i].x;
1123             if (sv[i].y < lty) lty = sv[i].y;
1124             if (sv[i].x > rbx) rbx = sv[i].x;
1125             if (sv[i].y > rby) rby = sv[i].y;
1126          }
1127          break;
1128       }
1129    } else if (curSpline == LT_STRUCT_SPLINE) {
1130       ipt_prev.earlier_valid = ipt_prev.later_valid = FALSE;
1131       ipt_prev.earlier_smooth_pt.x = ipt_prev.hinge_pt.x =
1132             ipt_prev.later_smooth_pt.x = OrigX;
1133       ipt_prev.earlier_smooth_pt.y = ipt_prev.hinge_pt.y =
1134             ipt_prev.later_smooth_pt.y = OrigY;
1135       memcpy(&first_ipt, &ipt_prev, sizeof(IntPointTriplet));
1136       pv = (IntPoint*)malloc((max_n+1)*sizeof(IntPoint));
1137       if (pv == NULL) FailAllocMessage();
1138       pv[0].x = pv[1].x = pv[2].x = pv[3].x = ABS_X(OrigX);
1139       pv[0].y = pv[1].y = pv[2].y = pv[3].y = ABS_Y(OrigY);
1140       sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX, drawOrigY, n+1,
1141             pv);
1142    }
1143    SaveStatusStrings();
1144    if (curSpline == LT_STRUCT_SPLINE) {
1145       SetMouseStatus(TgLoadCachedString(CSTID_ADD_A_STRUCT_VERTEX),
1146          TgLoadCachedString(CSTID_CLOSE_POLYGON_SPLINE),
1147          TgLoadCachedString(CSTID_CLOSE_POLYGON_SPLINE));
1148    } else {
1149       SetMouseStatus(TgLoadCachedString(CSTID_ADD_A_VERTEX),
1150          TgLoadCachedString(CSTID_CLOSE_POLYGON_SPLINE),
1151          TgLoadCachedString(CSTID_CLOSE_POLYGON_SPLINE));
1152    }
1153    DoPolygonMeasureCursor(&pmci, POLYGON_STARTSHOW, num_pts, ABS_X(grid_x),
1154          ABS_Y(grid_y), 0, 0, POLYGON_DRAW, POLYGON_CLICK, closed);
1155    if (!debugNoPointerGrab) {
1156       XGrabPointer(mainDisplay, drawWindow, FALSE,
1157             PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1158             GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1159    }
1160    if (curSpline == LT_STRUCT_SPLINE) {
1161       DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts, ABS_X(grid_x),
1162             ABS_Y(grid_y), 0, 0, POLYGON_ERASE, POLYGON_DRAG, closed);
1163       ContinueForStructSplinePolygonControlPoints(OrigX, OrigY,
1164             grid_x, grid_y, &sv, &sn, &sv2, &sn2, &first_ipt,
1165             &ipt_prev, &ipt, &abort);
1166       memcpy(&first_ipt, &ipt, sizeof(IntPointTriplet));
1167       memcpy(&ipt_prev, &ipt, sizeof(IntPointTriplet));
1168       if (first_ipt.later_valid) {
1169          grid_x = OFFSET_X(first_ipt.later_smooth_pt.x);
1170          grid_y = OFFSET_Y(first_ipt.later_smooth_pt.y);
1171       }
1172       SetFirstPoint(OrigX, OrigY, &first_ipt);
1173       DoPolygonMeasureCursor(&pmci, POLYGON_STARTSHOW, num_pts, ABS_X(grid_x),
1174             ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1175             ABS_SIZE(abs(grid_y-OrigY)), POLYGON_DRAW,
1176             POLYGON_CLICK, closed);
1177    } else {
1178       SetFirstPoint(OrigX, OrigY, NULL);
1179    }
1180    while (!done && !abort) {
1181       XNextEvent(mainDisplay, &input);
1182 
1183       if (input.type == Expose || input.type == VisibilityNotify) {
1184          ExposeEventHandler(&input, TRUE);
1185          SetXorDrawGC(xorColorPixels[colorIndex]);
1186       } else if ((!(shiftForDiagMouseMove && DiagEventCheck(&input))) &&
1187             (input.type == KeyPress || input.type == KeyRelease)) {
1188          char s[80];
1189          int has_ch=FALSE;
1190 
1191          has_ch = XLookupString(&(input.xkey), s, sizeof(s), &key_sym, &c_stat);
1192          if (num_pts > 1 && !(curSpline != LT_STRAIGHT &&
1193                curSpline != LT_STRUCT_SPLINE) &&
1194                (key_sym == XK_Control_L || key_sym == XK_Control_R)) {
1195             XDrawLine(mainDisplay, drawWindow, drawGC, saved_x, saved_y,
1196                   grid_x, grid_y);
1197             /* erase */
1198             DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts,
1199                   ABS_X(grid_x), ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1200                   ABS_SIZE(abs(grid_y-OrigY)), POLYGON_ERASE, POLYGON_DRAG,
1201                   closed);
1202             if (ControlKeyPressedEvent(&input)) {
1203                closed = TRUE;
1204             } else {
1205                closed = FALSE;
1206             }
1207             /* draw */
1208             DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts,
1209                   ABS_X(grid_x), ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1210                   ABS_SIZE(abs(grid_y-OrigY)), POLYGON_DRAW, POLYGON_DRAG,
1211                   closed);
1212          } else if (CharIsESC(&(input.xkey), s, key_sym, &has_ch)) {
1213             /* erase */
1214             DoPolygonMeasureCursor(&pmci, POLYGON_ENDSHOW, num_pts,
1215                   ABS_X(grid_x), ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1216                   ABS_SIZE(abs(grid_y-OrigY)), POLYGON_ERASE, POLYGON_CLICK,
1217                   closed);
1218             abort = TRUE;
1219             done = TRUE;
1220          }
1221       } else if ((input.type==MotionNotify && input.xany.window==drawWindow) ||
1222             (shiftForDiagMouseMove && DiagEventCheck(&input) &&
1223             (input.type == KeyPress || input.type == KeyRelease))) {
1224          unsigned int event_state=0;
1225 
1226          /* erase */
1227          DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts, ABS_X(grid_x),
1228                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1229                ABS_SIZE(abs(grid_y-OrigY)), POLYGON_ERASE, POLYGON_DRAG,
1230                closed);
1231          if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1232             XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1233                   CoordModeOrigin);
1234          } else if (curSpline == LT_STRUCT_SPLINE) {
1235             if (nothing_is_drawn) {
1236                /* then there is nothing to erase */
1237                nothing_is_drawn = FALSE;
1238             } else {
1239                EraseStructSplineLinesForContAndUpdateSvs(OrigX, OrigY, grid_x,
1240                      grid_y, &input, num_pts, &sv, sn, &sv2, sn2, &ipt_prev,
1241                      &first_ipt);
1242             }
1243          } else {
1244             XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, grid_x,
1245                   grid_y);
1246          }
1247          if (num_pts > 1 && closed) {
1248             XDrawLine(mainDisplay, drawWindow, drawGC, saved_x, saved_y,
1249                   grid_x, grid_y);
1250          }
1251          if (input.type == KeyPress || input.type == KeyRelease) {
1252             end_x = grid_x;
1253             end_y = grid_y;
1254             event_state = input.xkey.state;
1255          } else {
1256             motion_ev = &(input.xmotion);
1257             end_x = motion_ev->x;
1258             end_y = motion_ev->y;
1259             event_state = motion_ev->state;
1260          }
1261          if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
1262             if (input.type == KeyRelease) {
1263                end_x = input.xkey.x;
1264                end_y = input.xkey.y;
1265             } else {
1266                DiagGridXY(OrigX, OrigY, &end_x, &end_y);
1267             }
1268          }
1269          /* draw */
1270          GridXY(end_x, end_y, &grid_x, &grid_y);
1271          MarkRulers(grid_x, grid_y);
1272          if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1273             if (sv != NULL) {
1274                free(sv);
1275                sv = NULL;
1276             }
1277             pv[n-1].x = ABS_X(grid_x);
1278             pv[n-1].y = ABS_Y(grid_y);
1279             switch (curSpline) {
1280             case LT_SPLINE:
1281                sv = MakeSplinePolygonVertex(0, curSpline, &sn, drawOrigX,
1282                      drawOrigY, n+1, pv);
1283                break;
1284             case LT_INTSPLINE:
1285                if (cntrlv != NULL) free(cntrlv);
1286                sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
1287                      drawOrigX, drawOrigY, n+1, pv);
1288                for (i=0; i < sn; i++) {
1289                   if (sv[i].x < ltx) ltx = sv[i].x;
1290                   if (sv[i].y < lty) lty = sv[i].y;
1291                   if (sv[i].x > rbx) rbx = sv[i].x;
1292                   if (sv[i].y > rby) rby = sv[i].y;
1293                }
1294                break;
1295             }
1296             XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1297                   CoordModeOrigin);
1298          } else if (curSpline == LT_STRUCT_SPLINE) {
1299             if (sv != NULL) {
1300                free(sv);
1301                sv = NULL;
1302             }
1303             if (sv2 != NULL) {
1304                free(sv2);
1305                sv2 = NULL;
1306             }
1307             if (ipt_prev.later_valid) {
1308                pv[0].x = ABS_X(OrigX);
1309                pv[0].y = ABS_Y(OrigY);
1310                pv[1].x = ABS_X(ipt_prev.later_smooth_pt.x);
1311                pv[1].y = ABS_Y(ipt_prev.later_smooth_pt.y);
1312                pv[2].x = pv[3].x = ABS_X(grid_x);
1313                pv[2].y = pv[3].y = ABS_Y(grid_y);
1314                n = 3;
1315                sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1316                      drawOrigY, n, pv);
1317                XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1318                      CoordModeOrigin);
1319                if (first_ipt.earlier_valid) {
1320                   tmp_n = 3;
1321                   tmp_vs[0].x = ABS_X(grid_x);
1322                   tmp_vs[0].y = ABS_Y(grid_y);
1323                   tmp_vs[1].x = ABS_X(first_ipt.earlier_smooth_pt.x);
1324                   tmp_vs[1].y = ABS_Y(first_ipt.earlier_smooth_pt.y);
1325                   tmp_vs[2].x = ABS_X(first_ipt.hinge_pt.x);
1326                   tmp_vs[2].y = ABS_Y(first_ipt.hinge_pt.y);
1327                   sv2 = MakeSplinePolyVertex(0, curSpline, &sn2,
1328                         drawOrigX, drawOrigY, tmp_n, tmp_vs);
1329                   XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2,
1330                         CoordModeOrigin);
1331                } else {
1332                   XDrawLine(mainDisplay, drawWindow, drawGC,
1333                         first_ipt.hinge_pt.x, first_ipt.hinge_pt.y,
1334                         grid_x, grid_y);
1335                }
1336             } else {
1337                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1338                      grid_x, grid_y);
1339                if (num_pts > 1) {
1340                   if (first_ipt.earlier_valid) {
1341                      tmp_n = 3;
1342                      tmp_vs[0].x = ABS_X(grid_x);
1343                      tmp_vs[0].y = ABS_Y(grid_y);
1344                      tmp_vs[1].x = ABS_X(first_ipt.earlier_smooth_pt.x);
1345                      tmp_vs[1].y = ABS_Y(first_ipt.earlier_smooth_pt.y);
1346                      tmp_vs[2].x = ABS_X(first_ipt.hinge_pt.x);
1347                      tmp_vs[2].y = ABS_Y(first_ipt.hinge_pt.y);
1348                      sv2 = MakeSplinePolyVertex(0, curSpline, &sn2,
1349                            drawOrigX, drawOrigY, tmp_n, tmp_vs);
1350                      XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2,
1351                            CoordModeOrigin);
1352                   } else {
1353                      XDrawLine(mainDisplay, drawWindow, drawGC,
1354                            first_ipt.hinge_pt.x, first_ipt.hinge_pt.y, grid_x,
1355                            grid_y);
1356                   }
1357                }
1358             }
1359          } else {
1360             if (num_pts > 1) {
1361                if (event_state & ControlMask) {
1362                   XDrawLine(mainDisplay, drawWindow, drawGC, saved_x, saved_y,
1363                         grid_x, grid_y);
1364                   closed = TRUE;
1365                } else {
1366                   closed = FALSE;
1367                }
1368             }
1369             XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, grid_x,
1370                   grid_y);
1371          }
1372          DoPolygonMeasureCursor(&pmci, POLYGON_DOSHOW, num_pts, ABS_X(grid_x),
1373                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1374                ABS_SIZE(abs(grid_y-OrigY)), POLYGON_DRAW, POLYGON_DRAG, closed);
1375          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1376       } else if (input.type == ButtonPress) {
1377          /* erase */
1378          DoPolygonMeasureCursor(&pmci, POLYGON_ENDSHOW, num_pts, ABS_X(grid_x),
1379                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1380                ABS_SIZE(abs(grid_y-OrigY)), POLYGON_ERASE, POLYGON_DRAG,
1381                closed);
1382          button_ev = &(input.xbutton);
1383 
1384          end_x = button_ev->x;
1385          end_y = button_ev->y;
1386 
1387          if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
1388             DiagGridXY(OrigX, OrigY, &end_x, &end_y);
1389          }
1390          GridXY(end_x, end_y, &grid_x, &grid_y);
1391 
1392          if (grid_x == OrigX && grid_y == OrigY) {
1393             if (curSpline == LT_STRUCT_SPLINE) {
1394                if (num_pts == 1) {
1395                   abort = TRUE;
1396                } else {
1397                   /* need to overwrite the previous point */
1398 
1399                   /* erase */
1400 
1401                   /*
1402                    * since we've clicked at the same point, need to pretend
1403                    *       that num_pts is one more
1404                    */
1405                   EraseStructSplineLinesForContAndUpdateSvs(OrigX, OrigY,
1406                         grid_x, grid_y, &input, num_pts+1, &sv, sn, &sv2, sn2,
1407                         &ipt_prev, &first_ipt);
1408                   if (ipt_prev.later_valid) {
1409                      /* erase whole curve */
1410                      DrawAllStructSplinePointsForCont(num_pts);
1411                      ipt_prev.earlier_valid = ipt_prev.later_valid = FALSE;
1412                      ipt_prev.earlier_smooth_pt.x = ipt_prev.later_smooth_pt.x =
1413                            ipt_prev.hinge_pt.x;
1414                      ipt_prev.earlier_smooth_pt.y = ipt_prev.later_smooth_pt.y =
1415                            ipt_prev.hinge_pt.y;
1416                      UpdateLastPointForCont(&ipt_prev);
1417                      /* draw whole curve */
1418                      DrawAllStructSplinePointsForCont(num_pts);
1419                   }
1420                   UpdatePrevToLastPointForCont(&ipt_prev);
1421                   ipt.earlier_valid = ipt.later_valid = FALSE;
1422                   ipt.earlier_smooth_pt.x = ipt.later_smooth_pt.x =
1423                         ipt.hinge_pt.x = grid_x;
1424                   ipt.earlier_smooth_pt.y = ipt.later_smooth_pt.y =
1425                         ipt.hinge_pt.y = grid_y;
1426                   OrigX = ipt_prev.hinge_pt.x;
1427                   OrigY = ipt_prev.hinge_pt.y;
1428                   if (ipt_prev.later_valid) {
1429                      pv[0].x = ABS_X(OrigX);
1430                      pv[0].y = ABS_Y(OrigY);
1431                      pv[1].x = ABS_X(ipt_prev.later_smooth_pt.x);
1432                      pv[1].y = ABS_Y(ipt_prev.later_smooth_pt.y);
1433                      pv[2].x = pv[3].x = ABS_X(grid_x);
1434                      pv[2].y = pv[3].y = ABS_Y(grid_y);
1435                      n = 3;
1436                      sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1437                            drawOrigY, n, pv);
1438                   }
1439                   if (first_ipt.earlier_valid) {
1440                      tmp_n = 3;
1441                      tmp_vs[0].x = ABS_X(grid_x);
1442                      tmp_vs[0].y = ABS_Y(grid_y);
1443                      tmp_vs[1].x = ABS_X(first_ipt.earlier_smooth_pt.x);
1444                      tmp_vs[1].y = ABS_Y(first_ipt.earlier_smooth_pt.y);
1445                      tmp_vs[2].x = ABS_X(first_ipt.hinge_pt.x);
1446                      tmp_vs[2].y = ABS_Y(first_ipt.hinge_pt.y);
1447                      sv2 = MakeSplinePolyVertex(0, curSpline, &sn2,
1448                            drawOrigX, drawOrigY, tmp_n, tmp_vs);
1449                      XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2,
1450                            CoordModeOrigin);
1451                   }
1452                }
1453             }
1454          } else {
1455             num_pts++;
1456             ipt.earlier_valid = ipt.later_valid = FALSE;
1457             ipt.earlier_smooth_pt.x = ipt.later_smooth_pt.x = ipt.hinge_pt.x =
1458                   grid_x;
1459             ipt.earlier_smooth_pt.y = ipt.later_smooth_pt.y = ipt.hinge_pt.y =
1460                   grid_y;
1461             ipt.ratio = (double)1;
1462             AddPointForCont(grid_x, grid_y, &ipt);
1463             if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1464                if (n >= max_n-3) {
1465                   max_n += 40;
1466                   pv = (IntPoint*)realloc(pv, sizeof(IntPoint)*max_n+1);
1467                   if (pv == NULL) FailAllocMessage();
1468                }
1469                /* erase */
1470                XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1471                      CoordModeOrigin);
1472                if (sv != NULL) {
1473                   free(sv);
1474                   sv = NULL;
1475                }
1476                pv[n].x = ABS_X(grid_x);
1477                pv[n].y = ABS_Y(grid_y);
1478                n++;
1479                pv[n].x = pv[0].x;
1480                pv[n].y = pv[0].y;
1481                switch (curSpline) {
1482                case LT_SPLINE:
1483                   sv = MakeSplinePolygonVertex(0, curSpline, &sn, drawOrigX,
1484                         drawOrigY, n+1, pv);
1485                   break;
1486                case LT_INTSPLINE:
1487                   if (cntrlv != NULL) free(cntrlv);
1488                   sv = MakeIntSplinePolygonVertex(&sn, &intn, &cntrlv,
1489                         drawOrigX, drawOrigY, n+1, pv);
1490                   for (i=0; i < sn; i++) {
1491                      if (sv[i].x < ltx) ltx = sv[i].x;
1492                      if (sv[i].y < lty) lty = sv[i].y;
1493                      if (sv[i].x > rbx) rbx = sv[i].x;
1494                      if (sv[i].y > rby) rby = sv[i].y;
1495                   }
1496                   break;
1497                }
1498                /* draw */
1499                XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1500                      CoordModeOrigin);
1501             } else if (curSpline == LT_STRUCT_SPLINE) {
1502                /* erase */
1503                EraseStructSplineLinesForContAndUpdateSvs(OrigX, OrigY, grid_x,
1504                      grid_y, &input, num_pts, &sv, sn, &sv2, sn2, &ipt_prev,
1505                      &first_ipt);
1506                /* draw */
1507                if (ipt_prev.later_valid) {
1508                   pv[0].x = ABS_X(OrigX);
1509                   pv[0].y = ABS_Y(OrigY);
1510                   pv[1].x = ABS_X(ipt_prev.later_smooth_pt.x);
1511                   pv[1].y = ABS_Y(ipt_prev.later_smooth_pt.y);
1512                   pv[2].x = pv[3].x = ABS_X(grid_x);
1513                   pv[2].y = pv[3].y = ABS_Y(grid_y);
1514                   n = 3;
1515                   sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1516                         drawOrigY, n, pv);
1517                   XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1518                         CoordModeOrigin);
1519                   if (first_ipt.earlier_valid) {
1520                      tmp_n = 3;
1521                      tmp_vs[0].x = ABS_X(grid_x);
1522                      tmp_vs[0].y = ABS_Y(grid_y);
1523                      tmp_vs[1].x = ABS_X(first_ipt.earlier_smooth_pt.x);
1524                      tmp_vs[1].y = ABS_Y(first_ipt.earlier_smooth_pt.y);
1525                      tmp_vs[2].x = ABS_X(first_ipt.hinge_pt.x);
1526                      tmp_vs[2].y = ABS_Y(first_ipt.hinge_pt.y);
1527                      sv2 = MakeSplinePolyVertex(0, curSpline, &sn2,
1528                            drawOrigX, drawOrigY, tmp_n, tmp_vs);
1529                      XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2,
1530                            CoordModeOrigin);
1531                   } else {
1532                      XDrawLine(mainDisplay, drawWindow, drawGC,
1533                            first_ipt.hinge_pt.x, first_ipt.hinge_pt.y,
1534                            grid_x, grid_y);
1535                   }
1536                } else {
1537                   XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1538                         grid_x, grid_y);
1539                   if (sv != NULL) {
1540                      free(sv);
1541                      sv = NULL;
1542                   }
1543                }
1544             }
1545          }
1546          if (abort) {
1547             continue;
1548          }
1549          if (num_pts == 2 && closed && button_ev->button == Button1 &&
1550                curSpline == LT_STRAIGHT) {
1551             XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, grid_x,
1552                   grid_y);
1553          }
1554          if (grid_x == start_polygon_x && grid_y == start_polygon_y) {
1555             if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1556                /* erase the whole thing */
1557                XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1558                      CoordModeOrigin);
1559             } else if (curSpline == LT_STRUCT_SPLINE) {
1560                CVListElem *elem=ListFirst(&gStructSplineList);
1561                IntPointTriplet *pipt=(IntPointTriplet*)(elem->obj);
1562 
1563                /* erase the last part */
1564                if (nothing_is_drawn) {
1565                   /* then there is nothing to erase */
1566                   nothing_is_drawn = FALSE;
1567                } else {
1568                   EraseStructSplineLinesForContAndUpdateSvs(OrigX, OrigY,
1569                         grid_x, grid_y, &input, num_pts, &sv, sn, &sv2, sn2,
1570                         &ipt_prev, &first_ipt);
1571                }
1572                /* make the last point identical to the first point */
1573                UpdateLastPointForCont(pipt);
1574             } else {
1575                /* erase the last part */
1576                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1577                      grid_x, grid_y);
1578                if (num_pts > 1 && closed) {
1579                   XDrawLine(mainDisplay, drawWindow, drawGC, saved_x,
1580                         saved_y, grid_x, grid_y);
1581                }
1582                if (num_pts < 4) {
1583                   XDrawLine(mainDisplay, drawWindow, drawGC, saved_x,
1584                         saved_y, OrigX, OrigY);
1585                }
1586             }
1587             done = TRUE;
1588          } else {
1589             switch(button_ev->button) {
1590             case Button1:
1591                if (curSpline == LT_STRUCT_SPLINE) {
1592                   /*
1593                    * if the first point is curved, both the curve "before"
1594                    *       and "after have been drawn at this point
1595                    * if the first point is *not* curved, only the curve "before"
1596                    *       has been drawn, the line "after" is open (not drawn)
1597                    */
1598                   ContinueForStructSplinePolygonControlPoints(OrigX, OrigY,
1599                         grid_x, grid_y, &sv, &sn, &sv2, &sn2, &first_ipt,
1600                         &ipt_prev, &ipt, &abort);
1601                   UpdateLastPointForCont(&ipt);
1602                   /* at this point, the curve has been drawn */
1603                   if (sv != NULL) {
1604                      free(sv);
1605                      sv = NULL;
1606                      if (sv2 == NULL && !first_ipt.earlier_valid) {
1607                         /* erase it */
1608                         XDrawLine(mainDisplay, drawWindow, drawGC,
1609                               first_ipt.hinge_pt.x, first_ipt.hinge_pt.y,
1610                               ipt.hinge_pt.x, ipt.hinge_pt.y);
1611                      }
1612                   }
1613                   if (sv2 != NULL) {
1614                      /* erase it */
1615                      XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2,
1616                            CoordModeOrigin);
1617                      free(sv2);
1618                      sv2 = NULL;
1619                      if (ipt.later_valid) {
1620                         sn = 2;
1621                         sv = (XPoint*)malloc((sn+1)*sizeof(XPoint));
1622                         if (sv == NULL) FailAllocMessage();
1623                         sv[0].x = ABS_X(ipt.later_smooth_pt.x);
1624                         sv[0].y = ABS_Y(ipt.later_smooth_pt.y);
1625                         sv[1].x = ABS_X(ipt.hinge_pt.x);
1626                         sv[1].y = ABS_Y(ipt.hinge_pt.y);
1627                         XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1628                               CoordModeOrigin);
1629                         if (first_ipt.earlier_valid) {
1630                            tmp_n = 3;
1631                            tmp_vs[0].x = ABS_X(ipt.later_smooth_pt.x);
1632                            tmp_vs[0].y = ABS_Y(ipt.later_smooth_pt.y);
1633                            tmp_vs[1].x = ABS_X(first_ipt.earlier_smooth_pt.x);
1634                            tmp_vs[1].y = ABS_Y(first_ipt.earlier_smooth_pt.y);
1635                            tmp_vs[2].x = ABS_X(first_ipt.hinge_pt.x);
1636                            tmp_vs[2].y = ABS_Y(first_ipt.hinge_pt.y);
1637                            sv2 = MakeSplinePolyVertex(0, curSpline, &sn2,
1638                                  drawOrigX, drawOrigY, tmp_n, tmp_vs);
1639                            XDrawLines(mainDisplay, drawWindow, drawGC, sv2, sn2,
1640                                  CoordModeOrigin);
1641                         } else {
1642                            XDrawLine(mainDisplay, drawWindow, drawGC,
1643                                  first_ipt.hinge_pt.x, first_ipt.hinge_pt.y,
1644                                  ipt.later_smooth_pt.x, ipt.later_smooth_pt.y);
1645                         }
1646                      } else {
1647                         nothing_is_drawn = TRUE;
1648                      }
1649                   } else {
1650                      nothing_is_drawn = TRUE;
1651                   }
1652                   if (!abort) {
1653                      CVListElem *elem=ListLast(&gStructSplineList);
1654 
1655                      if (elem != NULL) {
1656                         IntPointTriplet *pipt=(IntPointTriplet*)(elem->obj);
1657 
1658                         memcpy(pipt, &ipt, sizeof(IntPointTriplet));
1659                      }
1660                      memcpy(&ipt_prev, &ipt, sizeof(IntPointTriplet));
1661                      OrigX = ipt.hinge_pt.x;
1662                      OrigY = ipt.hinge_pt.y;
1663                      if (ipt.later_valid) {
1664                         grid_x = ipt.later_smooth_pt.x;
1665                         grid_y = ipt.later_smooth_pt.y;
1666                      } else {
1667                         grid_x = ipt.hinge_pt.x;
1668                         grid_y = ipt.hinge_pt.y;
1669                      }
1670                      DoPolygonMeasureCursor(&pmci, POLYGON_STARTSHOW, num_pts,
1671                            ABS_X(grid_x), ABS_Y(grid_y),
1672                            ABS_SIZE(abs(grid_x-OrigX)),
1673                            ABS_SIZE(abs(grid_y-OrigY)), POLYGON_DRAW,
1674                            POLYGON_CLICK, closed);
1675                   }
1676                } else {
1677                   OrigX = grid_x; OrigY = grid_y;
1678                   /* draw */
1679                   DoPolygonMeasureCursor(&pmci, POLYGON_STARTSHOW, num_pts,
1680                         ABS_X(grid_x), ABS_Y(grid_y), 0, 0, POLYGON_DRAW,
1681                         POLYGON_CLICK, closed);
1682                }
1683                break;
1684             case Button2:
1685             case Button3:
1686                if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1687                   XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn,
1688                         CoordModeOrigin);
1689                   if (num_pts == 1) {
1690                      done = TRUE;
1691                      break;
1692                   }
1693                } else if (curSpline == LT_STRUCT_SPLINE) {
1694                   /*
1695                    * if the first point is curved, both the curve "before"
1696                    *       and "after have been drawn at this point
1697                    * if the first point is *not* curved, only the curve "before"
1698                    *       has been drawn, the line "after" is open (not drawn)
1699                    */
1700                   memset(&ipt, 0, sizeof(IntPointTriplet));
1701                   ipt.earlier_valid = ipt.later_valid = FALSE;
1702                   ipt.hinge_pt.x = ipt.earlier_smooth_pt.x =
1703                         ipt.later_smooth_pt.x = grid_x;
1704                   ipt.hinge_pt.y = ipt.earlier_smooth_pt.y =
1705                         ipt.later_smooth_pt.y = grid_y;
1706                   ipt.ratio = (double)1;
1707                   ContinueForStructSplinePolygonControlPoints(OrigX, OrigY,
1708                         grid_x, grid_y, &sv, &sn, &sv2, &sn2, &first_ipt,
1709                         &ipt_prev, &ipt, &abort);
1710                   UpdateLastPointForCont(&ipt);
1711                   if (num_pts == 1 && !first_ipt.later_valid &&
1712                         !ipt.earlier_valid) {
1713                      done = TRUE;
1714                      break;
1715                   }
1716                } else {
1717                   XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1718                         grid_x, grid_y);
1719                   if (num_pts > 1 && closed) {
1720                      XDrawLine(mainDisplay, drawWindow, drawGC, saved_x,
1721                            saved_y, grid_x, grid_y);
1722                   }
1723                   if (num_pts < 3) {
1724                      XDrawLine(mainDisplay, drawWindow, drawGC, saved_x,
1725                            saved_y, OrigX, OrigY);
1726                   }
1727                   if (num_pts == 1) {
1728                      done = TRUE;
1729                      break;
1730                   }
1731                }
1732                num_pts++;
1733                AddPointForCont(start_polygon_x, start_polygon_y, &first_ipt);
1734                done = TRUE;
1735                break;
1736             }
1737          }
1738       }
1739    }
1740    XUngrabPointer(mainDisplay, CurrentTime);
1741    RestoreStatusStrings();
1742    SetMouseStatus(NULL, NULL, NULL);
1743    Msg("");
1744 
1745    if (pv != NULL) free(pv);
1746    if (sv != NULL) free(sv);
1747    if (cntrlv != NULL) free(cntrlv);
1748 
1749    if (!abort) {
1750       if (curSpline == LT_STRUCT_SPLINE) {
1751          int num_actual_vs=CountStructuredSplinePolygonVs();
1752 
1753          if (num_actual_vs <= 3) {
1754             abort = TRUE;
1755          }
1756       } else if (num_pts <= 3) {
1757          abort = TRUE;
1758       }
1759    }
1760    if (!abort) {
1761       CreatePolygonObj(num_pts, CREATE_RELATIVE);
1762       RecordNewObjCmd();
1763       RedrawAnArea(botObj, topObj->bbox.ltx-GRID_ABS_SIZE(1),
1764             topObj->bbox.lty-GRID_ABS_SIZE(1),
1765             topObj->bbox.rbx+GRID_ABS_SIZE(1),
1766             topObj->bbox.rby+GRID_ABS_SIZE(1));
1767       polygonDrawn = TRUE;
1768       SetFileModified(TRUE);
1769    } else {
1770       if (curSpline != LT_INTSPLINE) {
1771          ltx = rbx = grid_x;
1772          lty = rby = grid_y;
1773       }
1774       FreePointsForCont(&ltx, &lty, &rbx, &rby);
1775       RedrawAnArea(botObj, ABS_X(ltx)-GRID_ABS_SIZE(1),
1776             ABS_Y(lty)-GRID_ABS_SIZE(1), ABS_X(rbx)+GRID_ABS_SIZE(1),
1777             ABS_Y(rby)+GRID_ABS_SIZE(1));
1778       numPtsInPoly = 0;
1779       lastPtPtr = NULL;
1780       polygonDrawn = FALSE;
1781    }
1782 }
1783 
DrawPolygon(input)1784 void DrawPolygon(input)
1785    XEvent *input;
1786 {
1787    XButtonEvent *button_ev;
1788    int mouse_x, mouse_y, grid_x, grid_y;
1789 
1790    if (input->type != ButtonPress) return;
1791 
1792    button_ev = &(input->xbutton);
1793    if (button_ev->button == Button1) {
1794       mouse_x = button_ev->x;
1795       mouse_y = button_ev->y;
1796       GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
1797       ContinuePolygon(grid_x, grid_y);
1798    }
1799 }
1800 
SelectAndHighLightNewObjects(PrevTopObj)1801 void SelectAndHighLightNewObjects(PrevTopObj)
1802    struct ObjRec *PrevTopObj;
1803 {
1804    register struct ObjRec *obj_ptr;
1805    register struct SelRec *sel_ptr;
1806 
1807    if (topSel != NULL) {
1808       HighLightReverse();
1809       RemoveAllSel();
1810    }
1811    for (obj_ptr=topObj; obj_ptr != PrevTopObj; obj_ptr=obj_ptr->next) {
1812       sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
1813       if (sel_ptr == NULL) FailAllocMessage();
1814       sel_ptr->obj = obj_ptr;
1815       sel_ptr->prev = sel_ptr->next = NULL;
1816       AddSel(botSel, NULL, sel_ptr);
1817    }
1818    UpdSelBBox();
1819    HighLightForward();
1820 }
1821 
InputPolygonPts()1822 void InputPolygonPts()
1823 {
1824    char inbuf[MAXSTRING+1];
1825    int more_polygon=FALSE, num_polygons=0;
1826    int started_composite=FALSE;
1827    struct ObjRec *saved_top_obj=topObj;
1828 
1829    MakeQuiescent();
1830    XSync(mainDisplay, False);
1831    do {
1832       int len, ok=TRUE, num_pts=0;
1833       int first_x=0, first_y=0, eof=TRUE;
1834       struct PtRec *pt_ptr;
1835 
1836       more_polygon = FALSE;
1837       numPtsInPoly = 0;
1838       lastPtPtr = NULL;
1839       printf("%s\n", TgLoadString(STID_INPUT_PAIRS_OF_POINTS_POLYGON));
1840       printf("> ");
1841       fflush(stdout);
1842       while (ok && fgets(inbuf, MAXSTRING, stdin) != NULL) {
1843          if (strcmp(inbuf, ";\n") == 0) {
1844             eof = FALSE;
1845             more_polygon = TRUE;
1846             break;
1847          }
1848          if (strcmp(inbuf, ".\n") == 0) {
1849             eof = FALSE;
1850             break;
1851          }
1852          len = strlen(inbuf);
1853          if (len > 0) {
1854             char *c_ptr=strtok(inbuf," ,\t\n"), *c_ptr1=NULL;
1855 
1856             if (c_ptr != NULL) c_ptr1 = strtok(NULL," ,\t\n");
1857             if (c_ptr1 != NULL) while (strchr(" ,\t\n", *c_ptr1)) c_ptr1++;
1858             while (c_ptr != NULL && c_ptr1 != NULL) {
1859                num_pts++;
1860                pt_ptr = (struct PtRec *)malloc(sizeof(struct PtRec));
1861                if (pt_ptr == NULL) FailAllocMessage();
1862                pt_ptr->next = lastPtPtr;
1863                if (sscanf(c_ptr, "%d", &pt_ptr->x) != 1 ||
1864                      sscanf(c_ptr1, "%d", &pt_ptr->y) != 1) {
1865                   ok = FALSE;
1866                   MsgBox(TgLoadString(STID_READ_INT_ERR_FOR_POLYGON_PTS),
1867                         TOOL_NAME, INFO_MB);
1868                   XSync(mainDisplay, False);
1869                   break;
1870                }
1871                if (lastPtPtr == NULL) {
1872                   first_x = pt_ptr->x;
1873                   first_y = pt_ptr->y;
1874                }
1875                lastPtPtr = pt_ptr;
1876                c_ptr = strtok(NULL," ,\t\n");
1877                if (c_ptr != NULL) c_ptr1 = strtok(NULL," ,\t\n");
1878                if (c_ptr1 != NULL) while (strchr(" ,\t\n", *c_ptr1)) c_ptr1++;
1879             }
1880             if (c_ptr != NULL) {
1881                ok = FALSE;
1882                MsgBox(TgLoadString(STID_READ_INT_ERR_FOR_POLYGON_PTS),
1883                      TOOL_NAME, INFO_MB);
1884                XSync(mainDisplay, False);
1885             }
1886          }
1887          printf("> ");
1888          fflush(stdout);
1889       }
1890       printf("\n");
1891       if (eof) rewind(stdin);
1892       if (ok && num_pts > 2) {
1893          num_polygons++;
1894          if (lastPtPtr->x != first_x || lastPtPtr->y != first_y) {
1895             num_pts++;
1896             pt_ptr = (struct PtRec *)malloc(sizeof(struct PtRec));
1897             if (pt_ptr == NULL) FailAllocMessage();
1898             pt_ptr->next = lastPtPtr;
1899             pt_ptr->x = first_x;
1900             pt_ptr->y = first_y;
1901             lastPtPtr = pt_ptr;
1902          }
1903          CreatePolygonObj(num_pts, CREATE_ABSOLUTE);
1904          if (more_polygon || num_polygons > 1) {
1905             if (num_polygons <= 1) {
1906                StartCompositeCmd();
1907                started_composite = TRUE;
1908             }
1909             RecordNewObjCmd();
1910             numRedrawBBox = 0;
1911             topObj->tmp_parent = NULL;
1912             DrawObj(drawWindow, topObj);
1913          } else {
1914             RecordNewObjCmd();
1915             RedrawAnArea(botObj, topObj->bbox.ltx-GRID_ABS_SIZE(1),
1916                   topObj->bbox.lty-GRID_ABS_SIZE(1),
1917                   topObj->bbox.rbx+GRID_ABS_SIZE(1),
1918                   topObj->bbox.rby+GRID_ABS_SIZE(1));
1919             SelectTopObj();
1920             SetFileModified(TRUE);
1921             justDupped = FALSE;
1922          }
1923       }
1924       if (ok && num_pts <= 2) {
1925          MsgBox(TgLoadString(STID_TOO_FEW_POINTERS_ENTERED), TOOL_NAME,
1926                INFO_MB);
1927          XSync(mainDisplay, False);
1928       }
1929       for ( ; lastPtPtr != NULL; lastPtPtr=pt_ptr) {
1930          pt_ptr = lastPtPtr->next;
1931          free(pt_ptr);
1932       }
1933    } while (more_polygon);
1934    if (num_polygons > 1 || started_composite) {
1935       SelectAndHighLightNewObjects(saved_top_obj);
1936       GroupSelObj(TRUE, TRUE, TRUE);
1937       EndCompositeCmd();
1938 
1939       SetFileModified(TRUE);
1940       justDupped = FALSE;
1941    }
1942 }
1943 
1944 static
AddToLastPoint(XOff,YOff)1945 void AddToLastPoint(XOff, YOff)
1946    int XOff, YOff;
1947 {
1948    struct PtRec *pt_ptr=(struct PtRec *)malloc(sizeof(struct PtRec));
1949 
1950    if (pt_ptr == NULL) FailAllocMessage();
1951    pt_ptr->next = lastPtPtr;
1952    numPtsInPoly++;
1953    lastPtPtr = pt_ptr;
1954    pt_ptr->x = XOff;
1955    pt_ptr->y = YOff;
1956 }
1957 
GetBoundingBox()1958 void GetBoundingBox()
1959 {
1960    struct SelRec *sel_ptr, *tmp_top_sel=NULL, *tmp_bot_sel=NULL;
1961    int num_created=0, saved_cur_spline=curSpline;
1962 
1963    if (topSel == NULL) {
1964       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
1965       return;
1966    }
1967    if (curChoice == VERTEXMODE) SetCurChoice(NOTHING);
1968    curSpline = LT_STRAIGHT;
1969 
1970    tmp_top_sel = tmp_bot_sel = NULL;
1971 
1972    HighLightReverse();
1973    StartCompositeCmd();
1974    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1975       struct ObjRec *obj_ptr=sel_ptr->obj;
1976       struct SelRec *new_sel_ptr;
1977 
1978       if (obj_ptr->ctm == NULL) {
1979          struct BBRec *p_obbox=(&obj_ptr->obbox);
1980 
1981          AddToLastPoint(p_obbox->ltx, p_obbox->lty);
1982          AddToLastPoint(p_obbox->ltx, p_obbox->rby);
1983          AddToLastPoint(p_obbox->rbx, p_obbox->rby);
1984          AddToLastPoint(p_obbox->rbx, p_obbox->lty);
1985          AddToLastPoint(p_obbox->ltx, p_obbox->lty);
1986          CreatePolygonObj(5, CREATE_ABSOLUTE);
1987       } else {
1988          int i;
1989 
1990          numPtsInPoly = 0;
1991          lastPtPtr = NULL;
1992          for (i=0; i < 5; i++) {
1993             AddToLastPoint(obj_ptr->rotated_obbox[i].x,
1994                   obj_ptr->rotated_obbox[i].y);
1995          }
1996          CreatePolygonObj(5, CREATE_RELATIVE);
1997       }
1998 
1999       new_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
2000       if (new_sel_ptr == NULL) FailAllocMessage();
2001       new_sel_ptr->obj = topObj;
2002       new_sel_ptr->next = NULL;
2003       new_sel_ptr->prev = NULL;
2004       PrepareToRecord(CMD_NEW, NULL, NULL, 0);
2005       RecordCmd(CMD_NEW, NULL, new_sel_ptr, new_sel_ptr, 1);
2006 
2007       new_sel_ptr->next = tmp_top_sel;
2008       if (tmp_top_sel == NULL) {
2009          tmp_bot_sel = new_sel_ptr;
2010       } else {
2011          tmp_top_sel->prev = new_sel_ptr;
2012       }
2013       tmp_top_sel = new_sel_ptr;
2014       num_created++;
2015    }
2016    EndCompositeCmd();
2017    curSpline = saved_cur_spline;
2018 
2019    RemoveAllSel();
2020    topSel = tmp_top_sel;
2021    botSel = tmp_bot_sel;
2022    UpdSelBBox();
2023    RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2024          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2025    HighLightForward();
2026    justDupped = FALSE;
2027    SetFileModified(TRUE);
2028 }
2029 
SavePolygonObj(FP,ObjPtr)2030 void SavePolygonObj(FP, ObjPtr)
2031    FILE *FP;
2032    struct ObjRec *ObjPtr;
2033 {
2034    register int i, n;
2035    int count;
2036    struct PolygonRec *polygon_ptr=ObjPtr->detail.g;
2037 
2038    n = polygon_ptr->n;
2039    if (fprintf(FP, "polygon('%s','',%1d,[\n\t",
2040          colorMenuItems[ObjPtr->color], polygon_ptr->n) == EOF) {
2041       writeFileFailed = TRUE;
2042    }
2043    for (i=0, count = 0; i < n-1; i++) {
2044       if (fprintf(FP, "%1d,%1d,", polygon_ptr->vlist[i].x,
2045             polygon_ptr->vlist[i].y) == EOF) {
2046          writeFileFailed = TRUE;
2047       }
2048       if (++count == 8) {
2049          count = 0;
2050          if (fprintf(FP, "\n\t") == EOF) writeFileFailed = TRUE;
2051       }
2052    }
2053    if (fprintf(FP, "%1d,%1d],",
2054          polygon_ptr->vlist[n-1].x, polygon_ptr->vlist[n-1].y) == EOF)
2055       writeFileFailed = TRUE;
2056 
2057    if (fprintf(FP,
2058          "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,'%s',%1d,",
2059          polygon_ptr->fill, polygon_ptr->width, polygon_ptr->pen,
2060          polygon_ptr->curved, ObjPtr->id, polygon_ptr->dash, ObjPtr->rotation,
2061          ObjPtr->locked, ObjPtr->ctm!=NULL, ObjPtr->invisible,
2062          polygon_ptr->width_spec, ObjPtr->trans_pat) == EOF) {
2063       writeFileFailed = TRUE;
2064    }
2065    if (fprintf(FP, "\n    \"") == EOF) writeFileFailed = TRUE;
2066    SaveSmoothHinge(FP, polygon_ptr->curved, polygon_ptr->n,
2067          polygon_ptr->smooth);
2068    if (fprintf(FP, "\",") == EOF) writeFileFailed = TRUE;
2069    if (ObjPtr->ctm != NULL && fprintf(FP,
2070          "[\n\t%1d,%1d,%1d,%1d,%1d,%1d,%g,%g,%g,%g,%1d,%1d],",
2071          ObjPtr->x, ObjPtr->y,
2072          ObjPtr->orig_obbox.ltx, ObjPtr->orig_obbox.lty,
2073          ObjPtr->orig_obbox.rbx, ObjPtr->orig_obbox.rby,
2074          ObjPtr->ctm->m[CTM_SX], ObjPtr->ctm->m[CTM_SIN],
2075          ObjPtr->ctm->m[CTM_MSIN], ObjPtr->ctm->m[CTM_SY],
2076          ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY]) == EOF) {
2077       writeFileFailed = TRUE;
2078    }
2079    if (serializingFile) SaveCreatorID(FP, ObjPtr, "    ");
2080    SaveAttrs(FP, ObjPtr->lattr);
2081    if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
2082 }
2083 
ReadPolygonObj(FP,Inbuf,ObjPtr)2084 void ReadPolygonObj(FP, Inbuf, ObjPtr)
2085    FILE *FP;
2086    char *Inbuf;
2087    struct ObjRec **ObjPtr;
2088 {
2089    register int i;
2090    struct PolygonRec *polygon_ptr;
2091    IntPoint *v;
2092    char color_str[40], bg_color_str[40], *s, inbuf[MAXSTRING];
2093    int num_pts, ltx=0, lty=0, rbx=0, rby=0, x, y, id=0;
2094    int trans_pat=FALSE, fill, width, pen, w, new_alloc, locked=FALSE;
2095    int curved, dash, initialized, rotation, count;
2096    int real_x=0, real_y=0, transformed=FALSE, invisible=FALSE;
2097    char *smooth=NULL, width_spec[40];
2098    struct XfrmMtrxRec *ctm=NULL;
2099    struct BBRec orig_obbox;
2100 
2101    *ObjPtr = NULL;
2102 
2103    s = FindChar((int)'(', Inbuf);
2104    s = ParseStr(s, (int)',', color_str, sizeof(color_str));
2105    if (fileVersion >= 37) {
2106       s = ParseStr(s, (int)',', bg_color_str, sizeof(bg_color_str));
2107    }
2108    InitScan(s, "\t\n, []");
2109 
2110    if (GETINT("polygon", num_pts, "number of points") == INVALID) {
2111       return;
2112    }
2113    if (num_pts <= 0) {
2114       (void)sprintf(gszMsgBox, TgLoadString(STID_INVALID_NUM_PTS_IN_POLYGON),
2115             scanFileName, scanLineNum);
2116       if (PRTGIF) {
2117          fprintf(stderr, "%s\n", gszMsgBox);
2118       } else {
2119          Msg(gszMsgBox);
2120       }
2121       return;
2122    }
2123 
2124    *ObjPtr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
2125    if (*ObjPtr == NULL) FailAllocMessage();
2126    memset(*ObjPtr, 0, sizeof(struct ObjRec));
2127    polygon_ptr = (struct PolygonRec *)malloc(sizeof(struct PolygonRec));
2128    if (polygon_ptr == NULL) FailAllocMessage();
2129    memset(polygon_ptr, 0, sizeof(struct PolygonRec));
2130 
2131    if (num_pts < 3) {
2132       v = (IntPoint*)malloc(5*sizeof(IntPoint));
2133       if (v == NULL) FailAllocMessage();
2134       smooth = (char*)malloc(5*sizeof(char));
2135       if (smooth == NULL) FailAllocMessage();
2136    } else {
2137       v = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
2138       if (v == NULL) FailAllocMessage();
2139       smooth = (char*)malloc((num_pts+1)*sizeof(char));
2140       if (smooth == NULL) FailAllocMessage();
2141    }
2142 
2143    initialized = FALSE;
2144 
2145    *width_spec = '\0';
2146    if (fileVersion <= 13) {
2147       for (i=0; i < num_pts; i++) {
2148          if (GETINT("polygon", x, "x") == INVALID ||
2149              GETINT("polygon", y, "y") == INVALID) {
2150             free(*ObjPtr);
2151             free(polygon_ptr);
2152             free(v);
2153             *ObjPtr = NULL;
2154             return;
2155          }
2156          v[i].x = x; v[i].y = y;
2157          if (!initialized) {
2158             initialized = TRUE;
2159             ltx = rbx = x; lty = rby = y;
2160          } else {
2161             if (x < ltx) ltx = x; if (y < lty) lty = y;
2162             if (x > rbx) rbx = x; if (y > rby) rby = y;
2163          }
2164       }
2165    } else {
2166       (void)fgets(inbuf, MAXSTRING, FP);
2167       scanLineNum++;
2168       s = inbuf;
2169       InitScan(s, "\t\n, []");
2170       for (i=0, count = 0; i < num_pts; i++) {
2171          if (GETINT("polygon", x, "x") == INVALID ||
2172              GETINT("polygon", y, "y") == INVALID) {
2173             free(*ObjPtr);
2174             free(polygon_ptr);
2175             free(v);
2176             *ObjPtr = NULL;
2177             return;
2178          }
2179          v[i].x = x; v[i].y = y;
2180          if (!initialized) {
2181             initialized = TRUE;
2182             ltx = rbx = x; lty = rby = y;
2183          } else {
2184             if (x < ltx) ltx = x; if (y < lty) lty = y;
2185             if (x > rbx) rbx = x; if (y > rby) rby = y;
2186          }
2187          if (++count == 8 && i != num_pts-1) {
2188             count = 0;
2189             (void)fgets(inbuf, MAXSTRING, FP);
2190             scanLineNum++;
2191             s = inbuf;
2192             InitScan(s, "\t\n, []");
2193          }
2194       }
2195    }
2196 
2197    switch (num_pts) {
2198    case 1:
2199       sprintf(gszMsgBox, TgLoadCachedString(CSTID_SNGL_PT_POLYGON_CONVERTED),
2200             v[0].x, v[0].y);
2201       if (PRTGIF) {
2202          fprintf(stderr, "%s\n", gszMsgBox);
2203       } else {
2204          Msg(gszMsgBox);
2205       }
2206       v[3].x = v[2].x = v[1].x = v[0].x;
2207       v[3].y = v[2].y = v[1].y = v[0].y;
2208       num_pts = 4;
2209       break;
2210    case 2:
2211       sprintf(gszMsgBox, TgLoadCachedString(CSTID_TWO_PT_POLYGON_CONVERTED),
2212             v[0].x, v[0].y, v[1].x, v[1].y);
2213       if (PRTGIF) {
2214          fprintf(stderr, "%s\n", gszMsgBox);
2215       } else {
2216          Msg(gszMsgBox);
2217       }
2218       v[3].x = v[2].x = v[0].x;
2219       v[3].y = v[2].y = v[0].y;
2220       num_pts = 4;
2221       break;
2222    case 3:
2223       sprintf(gszMsgBox, TgLoadCachedString(CSTID_TWO_PT_POLYGON_CONVERTED),
2224             v[0].x, v[0].y, v[1].x, v[1].y);
2225       if (PRTGIF) {
2226          fprintf(stderr, "%s\n", gszMsgBox);
2227       } else {
2228          Msg(gszMsgBox);
2229       }
2230       v[3].x = v[2].x = v[0].x;
2231       v[3].y = v[2].y = v[0].y;
2232       num_pts = 4;
2233       break;
2234    }
2235 
2236    polygon_ptr->n = num_pts;
2237 
2238    dash = 0;
2239    rotation = 0;
2240    if (fileVersion <= 3) {
2241       if (GETINT("polygon", fill,     "fill") == INVALID ||
2242           GETINT("polygon", width,    "width") == INVALID ||
2243           GETINT("polygon", pen,      "pen") == INVALID) {
2244          free(*ObjPtr);
2245          free(polygon_ptr);
2246          free(v);
2247          *ObjPtr = NULL;
2248          return;
2249       }
2250       if (width == LINE_CURVED) {
2251          width = 0;
2252          curved = TRUE;
2253       } else {
2254          curved = FALSE;
2255       }
2256       switch (width) {
2257       case 1: width = 3; break;
2258       case 2: width = 6; break;
2259       }
2260       id = objId++;
2261    } else if (fileVersion <= 5) {
2262       if (GETINT("polygon", fill,     "fill") == INVALID ||
2263           GETINT("polygon", width,    "width") == INVALID ||
2264           GETINT("polygon", pen,      "pen") == INVALID ||
2265           GETINT("polygon", curved,   "curved") == INVALID) {
2266          free(*ObjPtr);
2267          free(polygon_ptr);
2268          free(v);
2269          *ObjPtr = NULL;
2270          return;
2271       }
2272       switch (width) {
2273       case 1: width = 3; break;
2274       case 2: width = 6; break;
2275       }
2276       id = objId++;
2277    } else if (fileVersion <= 7) {
2278       if (GETINT("polygon", fill,     "fill") == INVALID ||
2279           GETINT("polygon", width,    "width") == INVALID ||
2280           GETINT("polygon", pen,      "pen") == INVALID ||
2281           GETINT("polygon", curved,   "curved") == INVALID) {
2282          free(*ObjPtr);
2283          free(polygon_ptr);
2284          free(v);
2285          *ObjPtr = NULL;
2286          return;
2287       }
2288       id = objId++;
2289    } else if (fileVersion <= 8) {
2290       if (GETINT("polygon", fill,     "fill") == INVALID ||
2291           GETINT("polygon", width,    "width") == INVALID ||
2292           GETINT("polygon", pen,      "pen") == INVALID ||
2293           GETINT("polygon", curved,   "curved") == INVALID ||
2294           GETINT("polygon", id,       "id") == INVALID) {
2295          free(*ObjPtr);
2296          free(polygon_ptr);
2297          free(v);
2298          *ObjPtr = NULL;
2299          return;
2300       }
2301       if (id >= objId) objId = id+1;
2302    } else if (fileVersion <= 13) {
2303       if (GETINT("polygon", fill,     "fill") == INVALID ||
2304           GETINT("polygon", width,    "width") == INVALID ||
2305           GETINT("polygon", pen,      "pen") == INVALID ||
2306           GETINT("polygon", curved,   "curved") == INVALID ||
2307           GETINT("polygon", id,       "id") == INVALID ||
2308           GETINT("polygon", dash,     "dash") == INVALID) {
2309          free(*ObjPtr);
2310          free(polygon_ptr);
2311          free(v);
2312          *ObjPtr = NULL;
2313          return;
2314       }
2315       if (id >= objId) objId = id+1;
2316    } else if (fileVersion <= 25) {
2317       if (GETINT("polygon", fill,     "fill") == INVALID ||
2318           GETINT("polygon", width,    "width") == INVALID ||
2319           GETINT("polygon", pen,      "pen") == INVALID ||
2320           GETINT("polygon", curved,   "curved") == INVALID ||
2321           GETINT("polygon", id,       "id") == INVALID ||
2322           GETINT("polygon", dash,     "dash") == INVALID ||
2323           GETINT("polygon", rotation, "rotation") == INVALID) {
2324          free(*ObjPtr);
2325          free(polygon_ptr);
2326          free(v);
2327          *ObjPtr = NULL;
2328          return;
2329       }
2330       if (id >= objId) objId = id+1;
2331    } else if (fileVersion <= 32) {
2332       if (GETINT("polygon", fill,     "fill") == INVALID ||
2333           GETINT("polygon", width,    "width") == INVALID ||
2334           GETINT("polygon", pen,      "pen") == INVALID ||
2335           GETINT("polygon", curved,   "curved") == INVALID ||
2336           GETINT("polygon", id,       "id") == INVALID ||
2337           GETINT("polygon", dash,     "dash") == INVALID ||
2338           GETINT("polygon", rotation, "rotation") == INVALID ||
2339           GETINT("polygon", locked,   "locked") == INVALID) {
2340          free(*ObjPtr);
2341          free(polygon_ptr);
2342          free(v);
2343          *ObjPtr = NULL;
2344          return;
2345       }
2346       if (id >= objId) objId = id+1;
2347    } else if (fileVersion <= 34) {
2348       if (GETINT("polygon", fill,        "fill") == INVALID ||
2349           GETINT("polygon", width,       "width") == INVALID ||
2350           GETINT("polygon", pen,         "pen") == INVALID ||
2351           GETINT("polygon", curved,      "curved") == INVALID ||
2352           GETINT("polygon", id,          "id") == INVALID ||
2353           GETINT("polygon", dash,        "dash") == INVALID ||
2354           GETINT("polygon", rotation,    "rotation") == INVALID ||
2355           GETINT("polygon", locked,      "locked") == INVALID ||
2356           GETINT("polygon", transformed, "transformed") == INVALID ||
2357           GETINT("polygon", invisible,   "invisible") == INVALID ||
2358           GETSTR("polygon", width_spec,  "width_spec") == INVALID) {
2359          free(*ObjPtr);
2360          free(polygon_ptr);
2361          free(v);
2362          *ObjPtr = NULL;
2363          return;
2364       }
2365       if (id >= objId) objId = id+1;
2366       UtilRemoveQuotes(width_spec);
2367    } else {
2368       if (GETINT("polygon", fill,        "fill") == INVALID ||
2369           GETINT("polygon", width,       "width") == INVALID ||
2370           GETINT("polygon", pen,         "pen") == INVALID ||
2371           GETINT("polygon", curved,      "curved") == INVALID ||
2372           GETINT("polygon", id,          "id") == INVALID ||
2373           GETINT("polygon", dash,        "dash") == INVALID ||
2374           GETINT("polygon", rotation,    "rotation") == INVALID ||
2375           GETINT("polygon", locked,      "locked") == INVALID ||
2376           GETINT("polygon", transformed, "transformed") == INVALID ||
2377           GETINT("polygon", invisible,   "invisible") == INVALID ||
2378           GETSTR("polygon", width_spec,  "width_spec") == INVALID ||
2379           GETINT("polygon", trans_pat,   "trans_pat") == INVALID) {
2380          free(*ObjPtr);
2381          free(polygon_ptr);
2382          free(v);
2383          *ObjPtr = NULL;
2384          return;
2385       }
2386       if (id >= objId) objId = id+1;
2387       UtilRemoveQuotes(width_spec);
2388    }
2389 
2390    if (fileVersion <= 16 && width <= 6) width = origWidthOfLine[width];
2391 
2392    if (fileVersion <= 25 && curved > 1) curved = 0;
2393    if (curved == LT_INTSPLINE && smooth != NULL) {
2394       free(smooth);
2395       smooth = NULL;
2396    }
2397    if (fileVersion <= 30) {
2398       switch (curved) {
2399       case LT_STRAIGHT:
2400          for (i=0; i < num_pts; i++) smooth[i] = FALSE;
2401          break;
2402       case LT_SPLINE:
2403          for (i=0; i < num_pts; i++) smooth[i] = TRUE;
2404          break;
2405       }
2406    } else if (!ReadSmoothHinge(FP, curved, num_pts, smooth)) {
2407       free(*ObjPtr);
2408       free(polygon_ptr);
2409       free(v);
2410       *ObjPtr = NULL;
2411       return;
2412    }
2413    if (fileVersion >= 33 && transformed) {
2414       (void)fgets(inbuf, MAXSTRING, FP);
2415       scanLineNum++;
2416       InitScan(inbuf, "\t\n, ");
2417 
2418       ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
2419       if (ctm == NULL) FailAllocMessage();
2420       if (GETINT("polygon", real_x,           "real_x") == INVALID ||
2421           GETINT("polygon", real_y,           "real_y") == INVALID ||
2422           GETINT("polygon", orig_obbox.ltx,   "orig_obbox.ltx") == INVALID ||
2423           GETINT("polygon", orig_obbox.lty,   "orig_obbox.lty") == INVALID ||
2424           GETINT("polygon", orig_obbox.rbx,   "orig_obbox.rbx") == INVALID ||
2425           GETINT("polygon", orig_obbox.rby,   "orig_obbox.rby") == INVALID ||
2426           GETDBL("polygon", ctm->m[CTM_SX],   "CTM_SX") == INVALID ||
2427           GETDBL("polygon", ctm->m[CTM_SIN],  "CTM_SIN") == INVALID ||
2428           GETDBL("polygon", ctm->m[CTM_MSIN], "CTM_MSIN") == INVALID ||
2429           GETDBL("polygon", ctm->m[CTM_SY],   "CTM_SY") == INVALID ||
2430           GETINT("polygon", ctm->t[CTM_TX],   "CTM_TX") == INVALID ||
2431           GETINT("polygon", ctm->t[CTM_TY],   "CTM_TY") == INVALID) {
2432          free(*ObjPtr);
2433          free(polygon_ptr);
2434          free(v);
2435          *ObjPtr = NULL;
2436          free(ctm);
2437          return;
2438       }
2439    }
2440    if (fileVersion <= 32) {
2441       sprintf(width_spec, "%1d", width);
2442    }
2443 
2444    fill = UpgradePenFill(fill);
2445    pen = UpgradePenFill(pen);
2446 
2447    polygon_ptr->fill = fill;
2448    polygon_ptr->width = width;
2449    UtilStrCpyN(polygon_ptr->width_spec, sizeof(polygon_ptr->width_spec),
2450          width_spec);
2451    polygon_ptr->pen = pen;
2452    polygon_ptr->curved = curved;
2453    polygon_ptr->dash = dash;
2454 
2455    polygon_ptr->vlist = v;
2456    polygon_ptr->smooth = smooth;
2457    polygon_ptr->svlist = NULL;
2458    polygon_ptr->intvlist = NULL;
2459 
2460    polygon_ptr->rotated_n = 0;
2461    polygon_ptr->rotated_vlist = NULL;
2462 
2463    (*ObjPtr)->x = ltx;
2464    (*ObjPtr)->y = lty;
2465    (*ObjPtr)->color = QuickFindColorIndex(*ObjPtr, color_str, &new_alloc, TRUE);
2466    UtilStrCpyN((*ObjPtr)->color_str, sizeof((*ObjPtr)->color_str), color_str);
2467    (*ObjPtr)->dirty = FALSE;
2468    (*ObjPtr)->id = id;
2469    (*ObjPtr)->rotation = rotation;
2470    (*ObjPtr)->locked = locked;
2471    (*ObjPtr)->type = OBJ_POLYGON;
2472    (*ObjPtr)->obbox.ltx = ltx;
2473    (*ObjPtr)->obbox.lty = lty;
2474    (*ObjPtr)->obbox.rbx = rbx;
2475    (*ObjPtr)->obbox.rby = rby;
2476    w = HALF_W(width);
2477    (*ObjPtr)->bbox.ltx = ltx - w;
2478    (*ObjPtr)->bbox.lty = lty - w;
2479    (*ObjPtr)->bbox.rbx = rbx + w;
2480    (*ObjPtr)->bbox.rby = rby + w;
2481    (*ObjPtr)->detail.g = polygon_ptr;
2482    (*ObjPtr)->ctm = ctm;
2483    (*ObjPtr)->invisible = invisible;
2484    (*ObjPtr)->trans_pat = trans_pat;
2485    if (ctm != NULL) {
2486       memcpy(&(*ObjPtr)->orig_obbox, &orig_obbox, sizeof(struct BBRec));
2487       (*ObjPtr)->x = real_x;
2488       (*ObjPtr)->y = real_y;
2489       GetTransformedOBBoxOffsetVs(*ObjPtr, (*ObjPtr)->rotated_obbox);
2490    }
2491    AdjObjCache(*ObjPtr);
2492    AdjObjSplineVs(*ObjPtr);
2493    if (polygon_ptr->curved != LT_INTSPLINE) {
2494       UpdPolyBBox(*ObjPtr, polygon_ptr->n, polygon_ptr->vlist);
2495    } else {
2496       UpdPolyBBox(*ObjPtr, polygon_ptr->intn, polygon_ptr->intvlist);
2497    }
2498 }
2499 
SetPolygonPropMask(ObjPtr,plMask,plSkip,pProp)2500 void SetPolygonPropMask(ObjPtr, plMask, plSkip, pProp)
2501    struct ObjRec *ObjPtr;
2502    long *plMask, *plSkip;
2503    struct PropertiesRec *pProp;
2504 {
2505    struct PolygonRec *polygon_ptr=ObjPtr->detail.g;
2506 
2507    SetCTMPropertyMask(ObjPtr->ctm, plMask, plSkip, pProp);
2508 
2509    SetIntPropertyMask(PROP_MASK_COLOR, ObjPtr->color,
2510          colorMenuItems[ObjPtr->color], plMask, plSkip, pProp);
2511    SetIntPropertyMask(PROP_MASK_WIDTH, polygon_ptr->width,
2512          polygon_ptr->width_spec, plMask, plSkip, pProp);
2513 
2514    SetIntPropertyMask(PROP_MASK_TRANSPAT, ObjPtr->trans_pat, NULL,
2515          plMask, plSkip, pProp);
2516    SetIntPropertyMask(PROP_MASK_FILL, polygon_ptr->fill, NULL,
2517          plMask, plSkip, pProp);
2518    SetIntPropertyMask(PROP_MASK_PEN, polygon_ptr->pen, NULL,
2519          plMask, plSkip, pProp);
2520    SetIntPropertyMask(PROP_MASK_DASH, polygon_ptr->dash, NULL,
2521          plMask, plSkip, pProp);
2522    SetIntPropertyMask(PROP_MASK_CURVED, polygon_ptr->curved, NULL,
2523          plMask, plSkip, pProp);
2524 }
2525 
FreePolygonObj(ObjPtr)2526 void FreePolygonObj(ObjPtr)
2527    struct ObjRec *ObjPtr;
2528 {
2529    if (ObjPtr->detail.g->ssvlist != NULL) free(ObjPtr->detail.g->ssvlist);
2530    if (ObjPtr->detail.g->intvlist != NULL) free(ObjPtr->detail.g->intvlist);
2531    if (ObjPtr->detail.g->svlist != NULL) free(ObjPtr->detail.g->svlist);
2532    if (ObjPtr->detail.g->rotated_vlist != NULL) {
2533       free(ObjPtr->detail.g->rotated_vlist);
2534    }
2535    free(ObjPtr->detail.g->vlist);
2536    if (ObjPtr->detail.g->smooth != NULL) free(ObjPtr->detail.g->smooth);
2537    if (ObjPtr->detail.g->ssmooth != NULL) free(ObjPtr->detail.g->ssmooth);
2538    free(ObjPtr->detail.g);
2539    free(ObjPtr);
2540 }
2541