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/poly.c,v 1.69 2011/05/16 16:21:59 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_POLY_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "arc.e"
26 #include "attr.e"
27 #include "auxtext.e"
28 #include "choice.e"
29 #include "cmd.e"
30 #include "color.e"
31 #include "cursor.e"
32 #include "cutpaste.e"
33 #include "dialog.e"
34 #include "drawing.e"
35 #include "dup.e"
36 #include "file.e"
37 #include "grid.e"
38 #include "list.e"
39 #include "mainloop.e"
40 #include "mark.e"
41 #include "msg.e"
42 #include "obj.e"
43 #include "page.e"
44 #include "pattern.e"
45 #include "pin.e"
46 #include "poly.e"
47 #include "polygon.e"
48 #include "ps.e"
49 #include "raster.e"
50 #include "rect.e"
51 #include "ruler.e"
52 #include "select.e"
53 #include "setup.e"
54 #include "special.e"
55 #include "spline.e"
56 #include "stretch.e"
57 #include "strtbl.e"
58 #include "util.e"
59 #include "xpixmap.e"
60 
61 #define RETREAT (0.8)
62 
63 WiringInfo gstWiringInfo;
64 
65 int polyDrawn=FALSE;
66 int queryPolyNameOnConnect=TRUE;
67 
68 /* short widthOfLine[] = { 0, 3,  6,  0 }; */
69 /* short arrowHeadH[]  = { 3, 5,  10, 3 }; */
70 /* short arrowHeadW[]  = { 8, 12, 22, 8 }; */
71 
72 short origWidthOfLine[] = { 1, 2,  3,  4,  5,  6,  7 };
73 short origArrowHeadH[]  = { 3, 4,  5,  6,  7,  8,  9 };
74 short origArrowHeadW[]  = { 8, 10, 12, 14, 18, 20, 22 };
75 
76 short *curWidthOfLine=NULL;
77 short *curArrowHeadH=NULL;
78 short *curArrowHeadW=NULL;
79 
80 char **curWidthOfLineSpec=NULL;
81 char **curArrowHeadHSpec=NULL;
82 char **curArrowHeadWSpec=NULL;
83 
84 int numPtsInPoly=0;
85 CVList gStructSplineList;
86 
87 struct PtRec *lastPtPtr=NULL;
88 struct ObjRec *drawPolyHighlightedNode=NULL;
89 
GetPolyOrPolygonAbsVs(pn_return,pn_allocated,ObjPtr)90 IntPoint *GetPolyOrPolygonAbsVs(pn_return, pn_allocated, ObjPtr)
91    int *pn_return, *pn_allocated;
92    struct ObjRec *ObjPtr;
93 {
94    int i=0, n=0;
95    struct PolyRec *poly_ptr=NULL;
96    struct PolygonRec *polygon_ptr=NULL;
97    IntPoint *vs=NULL, *return_vs=NULL;
98 
99    switch (ObjPtr->type) {
100    case OBJ_POLY:
101       poly_ptr = ObjPtr->detail.p;
102       if (poly_ptr->curved == LT_STRUCT_SPLINE) {
103          n = poly_ptr->ssn;
104          vs = poly_ptr->ssvlist;
105       } else {
106          n = poly_ptr->n;
107          vs = poly_ptr->vlist;
108       }
109       break;
110    case OBJ_POLYGON:
111       polygon_ptr = ObjPtr->detail.g;
112       if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
113          n = polygon_ptr->ssn;
114          vs = polygon_ptr->ssvlist;
115       } else {
116          n = polygon_ptr->n;
117          vs = polygon_ptr->vlist;
118       }
119       break;
120    }
121    *pn_return = n;
122    if (ObjPtr->ctm == NULL) {
123       *pn_allocated = FALSE;
124       return vs;
125    }
126    *pn_allocated = TRUE;
127 
128    return_vs = (IntPoint*)malloc(n*sizeof(IntPoint));
129    if (return_vs == NULL) FailAllocMessage();
130    memset(return_vs, 0, n*sizeof(IntPoint));
131 
132    for (i=0; i < n; i++) {
133       int x_off=0, y_off=0;
134 
135       TransformPointThroughCTM(vs[i].x-ObjPtr->x, vs[i].y-ObjPtr->y,
136             ObjPtr->ctm, &x_off, &y_off);
137       return_vs[i].x = ObjPtr->x + x_off;
138       return_vs[i].y = ObjPtr->y + y_off;
139    }
140    return return_vs;
141 }
142 
MakePolyVertex(XOff,YOff,NumVs,Vs)143 XPoint *MakePolyVertex(XOff, YOff, NumVs, Vs)
144    int XOff, YOff, NumVs;
145    register IntPoint *Vs;
146 {
147    register XPoint *v;
148    register int i;
149    int real_x_off, real_y_off;
150 
151    real_x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
152    real_y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
153 
154    v = (XPoint*)malloc((NumVs+1)*sizeof(XPoint));
155    if (v == NULL) FailAllocMessage();
156    for (i = 0; i < NumVs; i++) {
157       v[i].x = (short)ZOOMED_SIZE(Vs[i].x-real_x_off);
158       v[i].y = (short)ZOOMED_SIZE(Vs[i].y-real_y_off);
159    }
160    return v;
161 }
162 
CalcPolyBBox(ObjPtr)163 void CalcPolyBBox(ObjPtr)
164    struct ObjRec *ObjPtr;
165 {
166    register int x, y;
167    struct PolyRec *poly_ptr=ObjPtr->detail.p;
168    int style=poly_ptr->style, width=poly_ptr->width;
169    int aw=poly_ptr->aw, ah=poly_ptr->ah;
170    int ltx=ObjPtr->obbox.ltx, lty=ObjPtr->obbox.lty;
171    int rbx=ObjPtr->obbox.rbx, rby=ObjPtr->obbox.rby;
172    int dx=0, dy=0, tmp_x=0, tmp_y=0, num_pts=0;
173    double len, sin, cos, w, h;
174    IntPoint *v=NULL;
175    int retracted_arrow=(RetractedArrowAttr(ObjPtr) ||
176          AutoRetractedArrowAttr(ObjPtr, TRUE));
177 
178    switch (poly_ptr->curved) {
179    case LT_STRAIGHT:
180    case LT_SPLINE:
181       num_pts = poly_ptr->n;
182       v = poly_ptr->vlist;
183       break;
184    case LT_STRUCT_SPLINE:
185       num_pts = poly_ptr->ssn;
186       v = poly_ptr->ssvlist;
187       break;
188    case LT_INTSPLINE:
189       num_pts = poly_ptr->intn;
190       v = poly_ptr->intvlist;
191       break;
192    }
193    dx = v[1].x - v[0].x;
194    dy = v[1].y - v[0].y;
195    if ((style & LS_LEFT) && (dx != 0 || dy != 0)) {
196       len = (double)sqrt((double)(((double)dx)*((double)dx) +
197             ((double)dy)*((double)dy)));
198       sin = ((double)dy) / len;
199       cos = ((double)dx) / len;
200 
201       w = (double)aw; h = (double)max(ah,(width>>1));
202 
203       x = round(v[0].x + w*cos - h*sin);
204       y = round(v[0].y + w*sin + h*cos);
205       if (ObjPtr->ctm != NULL) {
206          TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm,
207                &tmp_x, &tmp_y);
208          x = tmp_x+ObjPtr->x;
209          y = tmp_y+ObjPtr->y;
210       }
211       if (x < ltx) ltx = x; if (y < lty) lty = y;
212       if (x > rbx) rbx = x; if (y > rby) rby = y;
213 
214       x = round(v[0].x + w*cos + h*sin);
215       y = round(v[0].y + w*sin - h*cos);
216       if (ObjPtr->ctm != NULL) {
217          TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm,
218                &tmp_x, &tmp_y);
219          x = tmp_x+ObjPtr->x;
220          y = tmp_y+ObjPtr->y;
221       }
222       if (x < ltx) ltx = x; if (y < lty) lty = y;
223       if (x > rbx) rbx = x; if (y > rby) rby = y;
224    }
225    dx = v[num_pts-1].x - v[num_pts-2].x;
226    dy = v[num_pts-1].y - v[num_pts-2].y;
227    if ((style & LS_RIGHT) && (dx != 0 || dy != 0)) {
228       len = (double)sqrt((double)(((double)dx)*((double)dx) +
229             ((double)dy)*((double)dy)));
230       sin = ((double)dy) / len;
231       cos = ((double)dx) / len;
232 
233       w = (double)aw; h = (double)max(ah,(width>>1));
234 
235       x = round(v[num_pts-1].x - w*cos + h*sin);
236       y = round(v[num_pts-1].y - w*sin - h*cos);
237       if (ObjPtr->ctm != NULL) {
238          TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm,
239                &tmp_x, &tmp_y);
240          x = tmp_x+ObjPtr->x;
241          y = tmp_y+ObjPtr->y;
242       }
243       if (x < ltx) ltx = x; if (y < lty) lty = y;
244       if (x > rbx) rbx = x; if (y > rby) rby = y;
245 
246       x = round(v[num_pts-1].x - w*cos - h*sin);
247       y = round(v[num_pts-1].y - w*sin + h*cos);
248       if (ObjPtr->ctm != NULL) {
249          TransformPointThroughCTM(x-ObjPtr->x, y-ObjPtr->y, ObjPtr->ctm,
250                &tmp_x, &tmp_y);
251          x = tmp_x+ObjPtr->x;
252          y = tmp_y+ObjPtr->y;
253       }
254       if (x < ltx) ltx = x; if (y < lty) lty = y;
255       if (x > rbx) rbx = x; if (y > rby) rby = y;
256    }
257    if (retracted_arrow) {
258       int i;
259 
260       for (i=1; i < num_pts; i++) {
261          x = v[i].x; y = v[i].y;
262          if (x-ah < ltx) ltx = x-ah; if (y-ah < lty) lty = y-ah;
263          if (x+ah > rbx) rbx = x+ah; if (y+ah > rby) rby = y+ah;
264       }
265    }
266    ObjPtr->bbox.ltx = min(ltx, ObjPtr->obbox.ltx-(width>>1));
267    ObjPtr->bbox.lty = min(lty, ObjPtr->obbox.lty-(width>>1));
268    ObjPtr->bbox.rbx = max(rbx, ObjPtr->obbox.rbx+(width>>1));
269    ObjPtr->bbox.rby = max(rby, ObjPtr->obbox.rby+(width>>1));
270 }
271 
UpdPolyBBox(ObjPtr,NumPts,V)272 void UpdPolyBBox(ObjPtr, NumPts, V)
273    struct ObjRec *ObjPtr;
274    int NumPts;
275    IntPoint *V;
276 {
277    register int i;
278    int ltx, lty, rbx, rby;
279 
280    ltx = rbx = V[0].x;
281    lty = rby = V[0].y;
282 
283    for (i = 1; i < NumPts; i++) {
284       if (V[i].x < ltx) ltx = V[i].x; if (V[i].y < lty) lty = V[i].y;
285       if (V[i].x > rbx) rbx = V[i].x; if (V[i].y > rby) rby = V[i].y;
286    }
287    if (ObjPtr->ctm == NULL) {
288       ObjPtr->x = ltx;
289       ObjPtr->y = lty;
290       ObjPtr->obbox.ltx = ltx;
291       ObjPtr->obbox.lty = lty;
292       ObjPtr->obbox.rbx = rbx;
293       ObjPtr->obbox.rby = rby;
294    } else {
295       IntPoint abs_obj_obbox_vs[5];
296 
297       ObjPtr->orig_obbox.ltx = ltx;
298       ObjPtr->orig_obbox.lty = lty;
299       ObjPtr->orig_obbox.rbx = rbx;
300       ObjPtr->orig_obbox.rby = rby;
301       GetTransformedOBBoxAbsVs(ObjPtr, abs_obj_obbox_vs);
302       ObjPtr->obbox.ltx = min(min(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
303             min(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
304       ObjPtr->obbox.rbx = max(max(abs_obj_obbox_vs[0].x,abs_obj_obbox_vs[1].x),
305             max(abs_obj_obbox_vs[2].x,abs_obj_obbox_vs[3].x));
306       ObjPtr->obbox.lty = min(min(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
307             min(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
308       ObjPtr->obbox.rby = max(max(abs_obj_obbox_vs[0].y,abs_obj_obbox_vs[1].y),
309             max(abs_obj_obbox_vs[2].y,abs_obj_obbox_vs[3].y));
310    }
311    AdjObjBBox(ObjPtr);
312 }
313 
UpdNonIntSplinePolyBBox(obj_ptr,num_pts,v)314 void UpdNonIntSplinePolyBBox(obj_ptr, num_pts, v)
315    struct ObjRec *obj_ptr;
316    int num_pts;
317    IntPoint *v;
318 {
319    switch (obj_ptr->type) {
320    case OBJ_POLY:
321       switch (obj_ptr->detail.p->curved) {
322       case LT_STRAIGHT:
323       case LT_SPLINE:
324       case LT_STRUCT_SPLINE:
325          UpdPolyBBox(obj_ptr, num_pts, v);
326          break;
327       case LT_INTSPLINE:
328          UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn,
329                obj_ptr->detail.p->intvlist);
330          break;
331       }
332       break;
333    case OBJ_POLYGON:
334       switch (obj_ptr->detail.g->curved) {
335       case LT_STRAIGHT:
336       case LT_SPLINE:
337       case LT_STRUCT_SPLINE:
338          UpdPolyBBox(obj_ptr, num_pts, v);
339          break;
340       case LT_INTSPLINE:
341          UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn,
342                obj_ptr->detail.g->intvlist);
343          break;
344       }
345       break;
346    }
347 }
348 
UpdPolyOrPolygonBBox(obj_ptr)349 void UpdPolyOrPolygonBBox(obj_ptr)
350    struct ObjRec *obj_ptr;
351 {
352    switch (obj_ptr->type) {
353    case OBJ_POLY:
354       switch (obj_ptr->detail.p->curved) {
355       case LT_STRAIGHT:
356       case LT_SPLINE:
357       case LT_STRUCT_SPLINE:
358          UpdPolyBBox(obj_ptr, obj_ptr->detail.p->n, obj_ptr->detail.p->vlist);
359          break;
360       case LT_INTSPLINE:
361          UpdPolyBBox(obj_ptr, obj_ptr->detail.p->intn,
362                obj_ptr->detail.p->intvlist);
363          break;
364       }
365       break;
366    case OBJ_POLYGON:
367       switch (obj_ptr->detail.g->curved) {
368       case LT_STRAIGHT:
369       case LT_SPLINE:
370       case LT_STRUCT_SPLINE:
371          UpdPolyBBox(obj_ptr, obj_ptr->detail.g->n, obj_ptr->detail.g->vlist);
372          break;
373       case LT_INTSPLINE:
374          UpdPolyBBox(obj_ptr, obj_ptr->detail.g->intn,
375                obj_ptr->detail.g->intvlist);
376          break;
377       }
378       break;
379    }
380 }
381 
382 #define CREATE_RELATIVE (FALSE)
383 #define CREATE_ABSOLUTE (TRUE)
384 
CreatePolyObj(NumPts,CreateAbsolute)385 void CreatePolyObj(NumPts, CreateAbsolute)
386    int NumPts;
387    int CreateAbsolute;
388 {
389    struct PtRec *pt_ptr=NULL, *next_pt=NULL;
390    struct PolyRec *poly_ptr=NULL;
391    struct ObjRec *obj_ptr=NULL;
392    register int i;
393    IntPoint *v=NULL;
394    int ltx, lty, rbx, rby, num_ss_pts=0;
395    char *smooth=NULL;
396    CVListElem *elem=NULL;
397    IntPointTriplet *pipt=NULL;
398 
399    poly_ptr = (struct PolyRec *)malloc(sizeof(struct PolyRec));
400    if (poly_ptr == NULL) FailAllocMessage();
401    memset(poly_ptr, 0, sizeof(struct PolyRec));
402    if (curSpline == LT_STRUCT_SPLINE) {
403       num_ss_pts = (NumPts*3)-2;
404       poly_ptr->n = num_ss_pts;
405       v = (IntPoint*)malloc((num_ss_pts+1)*sizeof(IntPoint));
406       if (v == NULL) FailAllocMessage();
407       smooth = (char*)malloc((num_ss_pts+1)*sizeof(char));
408       if (smooth == NULL) FailAllocMessage();
409       elem = ListLast(&gStructSplineList);
410       pipt = (IntPointTriplet*)(elem->obj);
411       ltx = rbx = pipt->hinge_pt.x;
412       lty = rby = pipt->hinge_pt.y;
413 
414       for (i=NumPts-1; i >= 0; i--, elem=ListPrev(&gStructSplineList, elem)) {
415          pipt = (IntPointTriplet*)(elem->obj);
416          if (i == 0) {
417             v[0].x = CreateAbsolute ? pipt->hinge_pt.x :
418                   ABS_X(pipt->hinge_pt.x);
419             v[0].y = CreateAbsolute ? pipt->hinge_pt.y :
420                   ABS_Y(pipt->hinge_pt.y);
421             if (pipt->later_valid) {
422                v[1].x = CreateAbsolute ? pipt->later_smooth_pt.x :
423                      ABS_X(pipt->later_smooth_pt.x);
424                v[1].y = CreateAbsolute ? pipt->later_smooth_pt.y :
425                      ABS_Y(pipt->later_smooth_pt.y);
426                smooth[1] = TRUE;
427             } else {
428                v[1].x = v[0].x;
429                v[1].y = v[0].y;
430                smooth[1] = FALSE;
431             }
432             smooth[0] = FALSE;
433          } else if (i == NumPts-1) {
434             v[num_ss_pts-1].x = CreateAbsolute ? pipt->hinge_pt.x :
435                   ABS_X(pipt->hinge_pt.x);
436             v[num_ss_pts-1].y = CreateAbsolute ? pipt->hinge_pt.y :
437                   ABS_Y(pipt->hinge_pt.y);
438             if (pipt->earlier_valid) {
439                v[num_ss_pts-2].x = CreateAbsolute ? pipt->earlier_smooth_pt.x :
440                      ABS_X(pipt->earlier_smooth_pt.x);
441                v[num_ss_pts-2].y = CreateAbsolute ? pipt->earlier_smooth_pt.y :
442                      ABS_Y(pipt->earlier_smooth_pt.y);
443                smooth[num_ss_pts-2] = TRUE;
444             } else {
445                v[num_ss_pts-2].x = v[num_ss_pts-1].x;
446                v[num_ss_pts-2].y = v[num_ss_pts-1].y;
447                smooth[num_ss_pts-2] = FALSE;
448             }
449             smooth[num_ss_pts-1] = FALSE;
450          } else {
451             int index=3*i;
452 
453             v[index-1].x = CreateAbsolute ? pipt->earlier_smooth_pt.x :
454                   ABS_X(pipt->earlier_smooth_pt.x);
455             v[index-1].y = CreateAbsolute ? pipt->earlier_smooth_pt.y :
456                   ABS_Y(pipt->earlier_smooth_pt.y);
457             v[index].x = CreateAbsolute ? pipt->hinge_pt.x :
458                   ABS_X(pipt->hinge_pt.x);
459             v[index].y = CreateAbsolute ? pipt->hinge_pt.y :
460                   ABS_Y(pipt->hinge_pt.y);
461             v[index+1].x = CreateAbsolute ? pipt->later_smooth_pt.x :
462                   ABS_X(pipt->later_smooth_pt.x);
463             v[index+1].y = CreateAbsolute ? pipt->later_smooth_pt.y :
464                   ABS_Y(pipt->later_smooth_pt.y);
465             smooth[index-1] = pipt->earlier_valid;
466             smooth[index] = FALSE;
467             smooth[index+1] = pipt->later_valid;
468          }
469          free(pipt);
470       }
471       for (i=0; i < num_ss_pts; i++) {
472          if (v[i].x < ltx) ltx = v[i].x;
473          if (v[i].y < lty) lty = v[i].y;
474          if (v[i].x > rbx) rbx = v[i].x;
475          if (v[i].y > rby) rby = v[i].y;
476       }
477       numPtsInPoly = 0;
478       ListUnlinkAll(&gStructSplineList);
479    } else {
480       poly_ptr->n = NumPts;
481       v = (IntPoint*)malloc((NumPts+1)*sizeof(IntPoint));
482       if (v == NULL) FailAllocMessage();
483       if (curSpline != LT_INTSPLINE) {
484          smooth = (char*)malloc((NumPts+1)*sizeof(char));
485          if (smooth == NULL) FailAllocMessage();
486       }
487       pt_ptr = lastPtPtr;
488       ltx = rbx = pt_ptr->x;
489       lty = rby = pt_ptr->y;
490 
491       for (i=NumPts-1; i >= 0; i--, lastPtPtr=next_pt) {
492          next_pt = lastPtPtr->next;
493          v[i].x = CreateAbsolute ? lastPtPtr->x : ABS_X(lastPtPtr->x);
494          v[i].y = CreateAbsolute ? lastPtPtr->y : ABS_Y(lastPtPtr->y);
495          if (curSpline != LT_INTSPLINE) {
496             if (lastPtPtr->x < ltx) ltx = lastPtPtr->x;
497             if (lastPtPtr->y < lty) lty = lastPtPtr->y;
498             if (lastPtPtr->x > rbx) rbx = lastPtPtr->x;
499             if (lastPtPtr->y > rby) rby = lastPtPtr->y;
500             if (curSpline == LT_STRAIGHT) {
501                smooth[i] = FALSE;
502             } else {
503                smooth[i] = (i != 0 && i != NumPts-1);
504             }
505          }
506          free(lastPtPtr);
507       }
508       numPtsInPoly = 0;
509       lastPtPtr = NULL;
510    }
511    poly_ptr->vlist = v;
512    poly_ptr->smooth = smooth;
513    poly_ptr->svlist = poly_ptr->asvlist = NULL;
514    poly_ptr->intvlist = NULL;
515    poly_ptr->style = lineStyle;
516    poly_ptr->width = curWidthOfLine[lineWidth];
517    poly_ptr->aw = curArrowHeadW[lineWidth];
518    poly_ptr->ah = curArrowHeadH[lineWidth];
519    UtilStrCpyN(poly_ptr->width_spec, sizeof(poly_ptr->width_spec),
520          curWidthOfLineSpec[lineWidth]);
521    UtilStrCpyN(poly_ptr->aw_spec, sizeof(poly_ptr->aw_spec),
522          curArrowHeadWSpec[lineWidth]);
523    UtilStrCpyN(poly_ptr->ah_spec, sizeof(poly_ptr->ah_spec),
524          curArrowHeadHSpec[lineWidth]);
525    poly_ptr->pen = penPat;
526    poly_ptr->curved = curSpline;
527    poly_ptr->fill = objFill;
528    poly_ptr->dash = curDash;
529    /*
530     * poly_ptr->tighter = (curSpline == LT_STRUCT_SPLINE) ?
531     *       tighterStructSplines : FALSE;
532     */
533    poly_ptr->rotated_n = 0;
534    poly_ptr->rotated_vlist = NULL;
535    poly_ptr->rotated_asn = 0;
536    poly_ptr->rotated_asvlist = NULL;
537 
538    obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
539    if (obj_ptr == NULL) FailAllocMessage();
540    memset(obj_ptr, 0, sizeof(struct ObjRec));
541    obj_ptr->detail.p = poly_ptr;
542 
543    obj_ptr->color = colorIndex;
544    if (mainDisplay != NULL) {
545       UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
546             colorMenuItems[colorIndex]);
547    }
548    obj_ptr->type = OBJ_POLY;
549    if (CreateAbsolute) {
550       obj_ptr->obbox.ltx = obj_ptr->x = ltx;
551       obj_ptr->obbox.lty = obj_ptr->y = lty;
552       obj_ptr->obbox.rbx = rbx;
553       obj_ptr->obbox.rby = rby;
554    } else {
555       obj_ptr->obbox.ltx = obj_ptr->x = ABS_X(ltx);
556       obj_ptr->obbox.lty = obj_ptr->y = ABS_Y(lty);
557       obj_ptr->obbox.rbx = ABS_X(rbx);
558       obj_ptr->obbox.rby = ABS_Y(rby);
559    }
560    obj_ptr->id = objId++;
561    obj_ptr->dirty = FALSE;
562    obj_ptr->rotation = 0;
563    obj_ptr->locked = FALSE;
564    obj_ptr->fattr = obj_ptr->lattr = NULL;
565    obj_ptr->ctm = NULL;
566    obj_ptr->invisible = FALSE;
567    obj_ptr->trans_pat = transPat;
568 
569    AdjObjSplineVs(obj_ptr);
570    if (curSpline != LT_INTSPLINE) {
571       UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
572    } else {
573       UpdPolyBBox(obj_ptr, poly_ptr->intn, poly_ptr->intvlist);
574    }
575    AdjObjBBox(obj_ptr);
576    AddObj(NULL, topObj, obj_ptr);
577 }
578 
ResetCreatePoly()579 void ResetCreatePoly()
580 {
581    numPtsInPoly = 0;
582    lastPtPtr = NULL;
583    CVListInit(&gStructSplineList);
584 }
585 
AddPtToCreatePoly(AbsX,AbsY)586 void AddPtToCreatePoly(AbsX, AbsY)
587    int AbsX, AbsY;
588 {
589    struct PtRec *pt_ptr=(struct PtRec *)malloc(sizeof(struct PtRec));
590 
591    if (pt_ptr == NULL) FailAllocMessage();
592    memset(pt_ptr, 0, sizeof(struct PtRec));
593    pt_ptr->next = lastPtPtr;
594    numPtsInPoly++;
595    lastPtPtr = pt_ptr;
596    pt_ptr->x = AbsX;
597    pt_ptr->y = AbsY;
598 }
599 
600 #ifdef HP_LINE_BUG
601 static
MyDrawLines(dpy,win,gc,sv,sn)602 void MyDrawLines(dpy, win, gc, sv, sn)
603    Display *dpy;
604    Window win;
605    GC gc;
606    XPoint *sv;
607    int sn;
608 {
609    if (sn == 2) {
610       XPoint hp_sv[3];
611 
612       hp_sv[0].x = sv[0].x; hp_sv[0].y = sv[0].y;
613       hp_sv[1].x = sv[0].x; hp_sv[1].y = sv[0].y;
614       hp_sv[2].x = sv[1].x; hp_sv[2].y = sv[1].y;
615       XDrawLines(dpy, win, gc, hp_sv, 3, CoordModeOrigin);
616    } else {
617       XDrawLines(dpy, win, gc, sv, sn, CoordModeOrigin);
618    }
619 }
620 #else /* ~HP_LINE_BUG */
621 #define MyDrawLines(dpy,win,gc,sv,sn) \
622         XDrawLines((dpy),(win),(gc),(sv),(sn),CoordModeOrigin)
623 #endif /* HP_LINE_BUG */
624 
625 static
SetXorDrawGCForPoly(color_index,line_width_index)626 void SetXorDrawGCForPoly(color_index, line_width_index)
627    int color_index, line_width_index;
628 {
629    XGCValues values;
630 
631    values.fill_style = FillSolid;
632 #ifdef NO_THIN_LINE
633    values.line_width = 1;
634 #else /* ~NO_THIN_LINE */
635    values.line_width = 0;
636 #endif /* NO_THIN_LINE */
637    if (curChoice == FREEHAND) {
638       values.foreground = colorPixels[color_index];
639       values.function = GXcopy;
640       values.line_width = curWidthOfLine[line_width_index];
641 #ifdef NO_THIN_LINE
642       if (curWidthOfLine[lineWidth] < 1) values.line_width = 1;
643 #endif /* NO_THIN_LINE */
644    } else {
645       values.foreground = xorColorPixels[color_index];
646       values.function = GXxor;
647    }
648    values.line_style = LineSolid;
649    values.join_style = JoinBevel;
650 
651    XChangeGC(mainDisplay, drawGC,
652          GCForeground | GCFunction | GCFillStyle | GCLineWidth | GCLineStyle |
653          GCJoinStyle, &values);
654 }
655 
656 #define POLY_DRAW  (FALSE)
657 #define POLY_ERASE (TRUE)
658 #define POLY_CLICK (FALSE)
659 #define POLY_DRAG  (TRUE)
660 
661 #define POLY_STARTSHOW 0
662 #define POLY_DOSHOW    1
663 #define POLY_ENDSHOW   2
664 
665 typedef struct tagPolyMeasureCursorInfo {
666    IntPoint first_pt;
667    IntPoint prev_prev_pt;
668    IntPoint prev_pt;
669 } PolyMeasureCursorInfo;
670 
671 static
DoPolyMeasureCursor(ppmci,start,num_pts,x,y,dx,dy,erase,drag)672 void DoPolyMeasureCursor(ppmci, start, num_pts, x, y, dx, dy, erase, drag)
673    PolyMeasureCursorInfo *ppmci;
674    int start, num_pts, x, y, dx, dy, erase, drag;
675 {
676    char buf[80], w_buf[80], h_buf[80], x_buf[80], y_buf[80], a_buf[80];
677    int angle2=0;
678 
679    if (erase == POLY_DRAW && drag == POLY_CLICK) {
680       if (num_pts == 1) {
681          ppmci->first_pt.x = ppmci->prev_pt.x = ppmci->prev_prev_pt.x = x;
682          ppmci->first_pt.y = ppmci->prev_pt.y = ppmci->prev_prev_pt.y = y;
683       } else {
684          ppmci->prev_prev_pt.x = ppmci->prev_pt.x;
685          ppmci->prev_prev_pt.y = ppmci->prev_pt.y;
686          ppmci->prev_pt.x = x;
687          ppmci->prev_pt.y = y;
688       }
689    }
690    if (x == ppmci->prev_pt.x && y == ppmci->prev_pt.y) {
691       strcpy(a_buf, "0");
692    } else if (num_pts == 1) {
693       PointsToArc(ppmci->prev_pt.x, ppmci->prev_pt.y, ppmci->prev_pt.x+100,
694             ppmci->prev_pt.y, x, y, ARC_CCW, FALSE, NULL, NULL, NULL, NULL,
695             NULL, &angle2);
696       if (angle2 > 180*64) angle2=(360*64)-angle2;
697       FormatAngle(angle2, a_buf);
698    } else {
699       PointsToArc(ppmci->prev_pt.x, ppmci->prev_pt.y, ppmci->prev_prev_pt.x,
700             ppmci->prev_prev_pt.y, x, y, ARC_CCW, FALSE, NULL, NULL, NULL, NULL,
701             NULL, &angle2);
702       if (angle2 > 180*64) angle2=(360*64)-angle2;
703       FormatAngle(angle2, a_buf);
704    }
705    PixelToMeasurementUnit(w_buf, dx);
706    PixelToMeasurementUnit(h_buf, dy);
707    PixelToMeasurementUnit(x_buf, x);
708    PixelToMeasurementUnit(y_buf, y);
709    if (curChoice == FREEHAND) {
710       sprintf(buf, "x=%s\ny=%s", x_buf, y_buf);
711    } else {
712       sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s\nangle=%s", w_buf, h_buf, x_buf,
713             y_buf, a_buf);
714    }
715    x = OFFSET_X(x);
716    y = OFFSET_Y(y);
717    switch (start) {
718    case POLY_STARTSHOW: StartShowMeasureCursor(x, y, buf, TRUE); break;
719    case POLY_DOSHOW: ShowMeasureCursor(x, y, buf, TRUE); break;
720    case POLY_ENDSHOW: EndShowMeasureCursor(x, y, buf, TRUE); break;
721    }
722 }
723 
FreePointsForCont(pn_ltx,pn_lty,pn_rbx,pn_rby)724 void FreePointsForCont(pn_ltx, pn_lty, pn_rbx, pn_rby)
725    int *pn_ltx, *pn_lty, *pn_rbx, *pn_rby;
726 {
727    int ltx=(*pn_ltx), lty=(*pn_lty), rbx=(*pn_rbx), rby=(*pn_rby);
728 
729    if (curSpline == LT_STRUCT_SPLINE) {
730       CVListElem *elem=NULL;
731 
732       for (elem=ListFirst(&gStructSplineList); elem != NULL;
733             elem=ListNext(&gStructSplineList, elem)) {
734          IntPointTriplet *ipt=(IntPointTriplet*)(elem->obj);
735 
736          if (ipt != NULL) {
737             if (ipt->hinge_pt.x < ltx) ltx = ipt->hinge_pt.x;
738             if (ipt->hinge_pt.y < lty) lty = ipt->hinge_pt.y;
739             if (ipt->hinge_pt.x > rbx) rbx = ipt->hinge_pt.x;
740             if (ipt->hinge_pt.y > rby) rby = ipt->hinge_pt.y;
741             if (ipt->earlier_valid) {
742                if (ipt->earlier_smooth_pt.x < ltx) {
743                   ltx = ipt->earlier_smooth_pt.x;
744                }
745                if (ipt->earlier_smooth_pt.y < lty) {
746                   lty = ipt->earlier_smooth_pt.y;
747                }
748                if (ipt->earlier_smooth_pt.x > rbx) {
749                   rbx = ipt->earlier_smooth_pt.x;
750                }
751                if (ipt->earlier_smooth_pt.y > rby) {
752                   rby = ipt->hinge_pt.y;
753                }
754             }
755             if (ipt->later_valid) {
756                if (ipt->later_smooth_pt.x < ltx) ltx = ipt->later_smooth_pt.x;
757                if (ipt->later_smooth_pt.y < lty) lty = ipt->later_smooth_pt.y;
758                if (ipt->later_smooth_pt.x > rbx) rbx = ipt->later_smooth_pt.x;
759                if (ipt->later_smooth_pt.y > rby) rby = ipt->later_smooth_pt.y;
760             }
761             free(ipt);
762          }
763       }
764       ListUnlinkAll(&gStructSplineList);
765    } else {
766       struct PtRec *pt_ptr=NULL, *next_pt=NULL;
767 
768       for (pt_ptr=lastPtPtr; pt_ptr != NULL; pt_ptr=next_pt) {
769          if (curSpline != LT_INTSPLINE) {
770             if (pt_ptr->x < ltx) ltx = pt_ptr->x;
771             if (pt_ptr->y < lty) lty = pt_ptr->y;
772             if (pt_ptr->x > rbx) rbx = pt_ptr->x;
773             if (pt_ptr->y > rby) rby = pt_ptr->y;
774          }
775          next_pt = pt_ptr->next;
776          free(pt_ptr);
777       }
778    }
779    *pn_ltx = ltx;
780    *pn_lty = lty;
781    *pn_rbx = rbx;
782    *pn_rby = rby;
783 }
784 
SetFirstPoint(grid_x,grid_y,pipt_first)785 int SetFirstPoint(grid_x, grid_y, pipt_first)
786    int grid_x, grid_y;
787    IntPointTriplet *pipt_first;
788 {
789    if (curSpline == LT_STRUCT_SPLINE) {
790       IntPointTriplet *ipt=(IntPointTriplet*)malloc(sizeof(IntPointTriplet));
791 
792       if (ipt == NULL) return FailAllocMessage();
793       memset(ipt, 0, sizeof(IntPointTriplet));
794       if (pipt_first == NULL) {
795          ipt->earlier_smooth_pt.x = ipt->hinge_pt.x = ipt->later_smooth_pt.x =
796                grid_x; /* offset */
797          ipt->earlier_smooth_pt.y = ipt->hinge_pt.y = ipt->later_smooth_pt.y =
798                grid_y; /* offset */
799          ipt->ratio = (double)1;
800       } else {
801          memcpy(ipt, pipt_first, sizeof(IntPointTriplet));
802       }
803       ListAppend(&gStructSplineList, ipt);
804    } else {
805       numPtsInPoly = 1;
806       lastPtPtr = (struct PtRec *)malloc(sizeof(struct PtRec));
807       if (lastPtPtr == NULL) return FailAllocMessage();
808       lastPtPtr->x = grid_x; /* offset */
809       lastPtPtr->y = grid_y; /* offset */
810       lastPtPtr->next = NULL;
811    }
812    return TRUE;
813 }
814 
AddPointForCont(grid_x,grid_y,pipt)815 int AddPointForCont(grid_x, grid_y, pipt)
816    int grid_x, grid_y;
817    IntPointTriplet *pipt;
818 {
819    if (curSpline == LT_STRUCT_SPLINE) {
820       IntPointTriplet *ipt=(IntPointTriplet*)malloc(sizeof(IntPointTriplet));
821 
822       if (ipt == NULL) return FailAllocMessage();
823       memcpy(ipt, pipt, sizeof(IntPointTriplet));
824       ListAppend(&gStructSplineList, ipt);
825    } else {
826       struct PtRec *pt_ptr=NULL;
827 
828       pt_ptr = (struct PtRec *)malloc(sizeof(struct PtRec));
829       if (pt_ptr == NULL) FailAllocMessage();
830       pt_ptr->next = lastPtPtr;
831       lastPtPtr = pt_ptr;
832       pt_ptr->x = grid_x;
833       pt_ptr->y = grid_y;
834    }
835    return TRUE;
836 }
837 
UpdateLastPointForCont(pipt)838 void UpdateLastPointForCont(pipt)
839    IntPointTriplet *pipt;
840 {
841    CVListElem *elem=ListLast(&gStructSplineList);
842    IntPointTriplet *ipt=(IntPointTriplet*)(elem->obj);
843 
844    memcpy(ipt, pipt, sizeof(IntPointTriplet));
845 }
846 
DrawAllStructSplinePointsForCont(num_pts)847 void DrawAllStructSplinePointsForCont(num_pts)
848    int num_pts;
849 {
850    int i=0;
851    CVListElem *elem=ListFirst(&gStructSplineList);
852    IntPointTriplet *pipt=(IntPointTriplet*)(elem->obj);
853 
854    for (i=0; i < num_pts-1; i++) {
855       CVListElem *next_elem=ListNext(&gStructSplineList, elem);
856       IntPointTriplet *pipt_next=(IntPointTriplet*)(next_elem->obj);
857       int tmp_n=0;
858       IntPoint tmp_vs[4];
859 
860       tmp_vs[0].x = ABS_X(pipt->hinge_pt.x);
861       tmp_vs[0].y = ABS_Y(pipt->hinge_pt.y);
862       if (pipt->later_valid) {
863          if (pipt_next->earlier_valid) {
864             tmp_n = 4;
865             tmp_vs[1].x = ABS_X(pipt->later_smooth_pt.x);
866             tmp_vs[1].y = ABS_Y(pipt->later_smooth_pt.y);
867             tmp_vs[2].x = ABS_X(pipt_next->earlier_smooth_pt.x);
868             tmp_vs[2].y = ABS_Y(pipt_next->earlier_smooth_pt.y);
869          } else {
870             tmp_n = 3;
871             tmp_vs[1].x = ABS_X(pipt->later_smooth_pt.x);
872             tmp_vs[1].y = ABS_Y(pipt->later_smooth_pt.y);
873          }
874       } else {
875          if (pipt_next->earlier_valid) {
876             tmp_n = 3;
877             tmp_vs[1].x = ABS_X(pipt_next->earlier_smooth_pt.x);
878             tmp_vs[1].y = ABS_Y(pipt_next->earlier_smooth_pt.y);
879          } else {
880             tmp_n = 2;
881             XDrawLine(mainDisplay, drawWindow, drawGC, pipt->hinge_pt.x,
882                   pipt->hinge_pt.y, pipt_next->hinge_pt.x,
883                   pipt_next->hinge_pt.y);
884          }
885       }
886       tmp_vs[tmp_n-1].x = ABS_X(pipt_next->hinge_pt.x);
887       tmp_vs[tmp_n-1].y = ABS_Y(pipt_next->hinge_pt.y);
888 
889       if (tmp_n > 2) {
890          int sn=0;
891          XPoint *sv=MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
892                drawOrigY, tmp_n, tmp_vs);
893 
894          XDrawLines(mainDisplay, drawWindow, drawGC, sv, sn, CoordModeOrigin);
895          free(sv);
896       }
897    }
898 }
899 
UpdatePrevToLastPointForCont(pipt_prev)900 void UpdatePrevToLastPointForCont(pipt_prev)
901    IntPointTriplet *pipt_prev;
902 {
903    CVListElem *elem=ListLast(&gStructSplineList);
904    IntPointTriplet *pipt=(IntPointTriplet*)(elem->obj);
905 
906    elem = ListPrev(&gStructSplineList, elem);
907    pipt = (IntPointTriplet*)(elem->obj);
908    memcpy(pipt_prev, pipt, sizeof(IntPointTriplet));
909 }
910 
911 static
ContinueForStructSplinePolyControlPoints(OrigX,OrigY,LastX,LastY,psv,psn,pipt_prev,pipt,pn_abort)912 void ContinueForStructSplinePolyControlPoints(OrigX, OrigY, LastX, LastY, psv,
913       psn, pipt_prev, pipt, pn_abort)
914    int OrigX, OrigY, LastX, LastY, *psn, *pn_abort;
915    XPoint **psv;
916    IntPointTriplet *pipt_prev, *pipt;
917 {
918    int i=0, done=FALSE, grid_x=0, grid_y=0, end_x=0, end_y=0, n=2;
919    int sn=(*psn), orig_sn=(*psn), num_pts=1, first_time=TRUE;
920    IntPoint v[4];
921    XPoint *sv=NULL, *orig_sv=(*psv), dash_vs[2];
922    PolyMeasureCursorInfo pmci;
923    XGCValues values;
924 
925    *pn_abort = FALSE;
926 
927    if (orig_sv != NULL) {
928       sv = (XPoint*)malloc(orig_sn*sizeof(XPoint));
929       if (sv == NULL) FailAllocMessage();
930       memset(sv, 0, orig_sn*sizeof(XPoint));
931       for (i=0; i < orig_sn; i++) {
932          sv[i].x = orig_sv[i].x;
933          sv[i].y = orig_sv[i].y;
934       }
935       sn = orig_sn;
936    }
937    memset(pipt, 0, sizeof(IntPointTriplet));
938    pipt->earlier_valid = pipt->later_valid = FALSE;
939    pipt->hinge_pt.x = pipt->earlier_smooth_pt.x = pipt->later_smooth_pt.x =
940          LastX;
941    pipt->hinge_pt.y = pipt->earlier_smooth_pt.y = pipt->later_smooth_pt.y =
942          LastY;
943    pipt->ratio = (double)1;
944 
945    XSetDashes(mainDisplay, revDefaultGC, 0, dashList[8], dashListLength[8]);
946 
947    grid_x = end_x = dash_vs[0].x = dash_vs[1].x = LastX;
948    grid_y = end_y = dash_vs[0].y = dash_vs[1].y = LastY;
949    v[0].x = ABS_X(OrigX);
950    v[0].y = ABS_Y(OrigY);
951    v[1].x = ABS_X(LastX);
952    v[1].y = ABS_Y(LastY);
953    n = 2;
954    MARKHR(drawWindow, revDefaultGC, LastX, LastY);
955 
956    /* the previous curve has already been drawn */
957    /* draw the measure cursor */
958    DoPolyMeasureCursor(&pmci, POLY_DOSHOW, num_pts, ABS_X(grid_x),
959          ABS_Y(grid_y), 0, 0, POLY_ERASE, POLY_DRAG);
960    while (!done) {
961       XEvent input, ev;
962 
963       XNextEvent(mainDisplay, &input);
964 
965       if (input.type == Expose || input.type == VisibilityNotify) {
966          ExposeEventHandler(&input, TRUE);
967          SetXorDrawGCForPoly(colorIndex, lineWidth);
968       } else if (input.type == MotionNotify) {
969          end_x = input.xmotion.x;
970          end_y = input.xmotion.y;
971 
972          /* erase */
973          if (first_time || grid_x != LastX || grid_y != LastY) {
974             if (sv != NULL) {
975                MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
976             } else {
977                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, grid_x,
978                      grid_y);
979             }
980             first_time = FALSE;
981          } else {
982             if (orig_sv != NULL) {
983                MyDrawLines(mainDisplay, drawWindow, drawGC, orig_sv, orig_sn);
984             } else {
985                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, LastX,
986                      LastY);
987             }
988          }
989          DoPolyMeasureCursor(&pmci, POLY_DOSHOW, num_pts, ABS_X(grid_x),
990                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
991                ABS_SIZE(abs(grid_y-LastY)), POLY_ERASE, POLY_DRAG);
992          MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
993          MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
994          values.line_style = LineOnOffDash;
995          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
996          MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
997          values.line_style = LineSolid;
998          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
999 
1000          /* draw */
1001          GridXY(end_x, end_y, &grid_x, &grid_y);
1002          MarkRulers(grid_x, grid_y);
1003          if (grid_x != LastX || grid_y != LastY) {
1004             if (sv != NULL) {
1005                free(sv);
1006                sv = NULL;
1007             }
1008             if (pipt_prev->later_valid) {
1009                v[1].x = ABS_X(pipt_prev->later_smooth_pt.x);
1010                v[1].y = ABS_Y(pipt_prev->later_smooth_pt.y);
1011                n = 4;
1012             } else {
1013                n = 3;
1014             }
1015             v[n-2].x = ABS_X((LastX<<1)-grid_x);
1016             v[n-2].y = ABS_Y((LastY<<1)-grid_y);
1017             v[n-1].x = ABS_X(LastX);
1018             v[n-1].y = ABS_Y(LastY);
1019             sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX, drawOrigY,
1020                   n, v);
1021             MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1022          } else {
1023             if (orig_sv != NULL) {
1024                MyDrawLines(mainDisplay, drawWindow, drawGC, orig_sv, orig_sn);
1025             } else {
1026                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, LastX,
1027                      LastY);
1028             }
1029          }
1030          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1031 
1032          dash_vs[0].x = grid_x;
1033          dash_vs[0].y = grid_y;
1034          dash_vs[1].x = (LastX<<1)-grid_x;
1035          dash_vs[1].y = (LastY<<1)-grid_y;
1036          pipt->later_smooth_pt.x = dash_vs[0].x;
1037          pipt->later_smooth_pt.y = dash_vs[0].y;
1038          pipt->earlier_smooth_pt.x = dash_vs[1].x;
1039          pipt->earlier_smooth_pt.y = dash_vs[1].y;
1040          if (grid_x == LastX && grid_y == LastY) {
1041             pipt->earlier_valid = pipt->later_valid = FALSE;
1042          } else {
1043             pipt->earlier_valid = pipt->later_valid = TRUE;
1044          }
1045          MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
1046          MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
1047          values.line_style = LineOnOffDash;
1048          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1049          MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
1050          values.line_style = LineSolid;
1051          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1052          DoPolyMeasureCursor(&pmci, POLY_DOSHOW, num_pts, ABS_X(grid_x),
1053                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
1054                ABS_SIZE(abs(grid_y-LastY)), POLY_DRAW, POLY_DRAG);
1055       } else if (input.type == KeyPress) {
1056          if (KeyPressEventIsEscape(&input.xkey)) {
1057             /* erase */
1058             DoPolyMeasureCursor(&pmci, POLY_ENDSHOW, num_pts, ABS_X(grid_x),
1059                   ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
1060                   ABS_SIZE(abs(grid_y-LastY)), POLY_ERASE, POLY_DRAG);
1061             MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
1062             MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
1063             values.line_style = LineOnOffDash;
1064             XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1065             MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
1066             values.line_style = LineSolid;
1067             XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1068             Msg("");
1069             *pn_abort = TRUE;
1070             done = TRUE;
1071          }
1072       } else if (input.type == ButtonRelease) {
1073          /* erase */
1074          DoPolyMeasureCursor(&pmci, POLY_ENDSHOW, num_pts, ABS_X(grid_x),
1075                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-LastX)),
1076                ABS_SIZE(abs(grid_y-LastY)), POLY_ERASE, POLY_DRAG);
1077          MARKHO(drawWindow, revDefaultGC, dash_vs[0].x, dash_vs[0].y);
1078          MARKHO(drawWindow, revDefaultGC, dash_vs[1].x, dash_vs[1].y);
1079          values.line_style = LineOnOffDash;
1080          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1081          MyDashedLine(drawWindow, revDefaultGC, dash_vs, 2);
1082          values.line_style = LineSolid;
1083          XChangeGC(mainDisplay, revDefaultGC, GCLineStyle, &values);
1084 
1085          GridXY(input.xbutton.x, input.xbutton.y, &grid_x, &grid_y);
1086          pipt->later_smooth_pt.x = grid_x;
1087          pipt->later_smooth_pt.y = grid_y;
1088          pipt->earlier_smooth_pt.x = (LastX<<1)-grid_x;
1089          pipt->earlier_smooth_pt.y = (LastY<<1)-grid_y;
1090          if (grid_x == LastX && grid_y == LastY) {
1091             pipt->earlier_valid = pipt->later_valid = FALSE;
1092          } else {
1093             pipt->earlier_valid = pipt->later_valid = TRUE;
1094          }
1095          done = TRUE;
1096       }
1097    }
1098    MARKHR(drawWindow, revDefaultGC, LastX, LastY);
1099 
1100    *psv = sv;
1101    *psn = sn;
1102 
1103    if (orig_sv != NULL) free(orig_sv);
1104 }
1105 
1106 static
ContinuePoly(OrigX,OrigY)1107 void ContinuePoly(OrigX, OrigY)
1108    int OrigX, OrigY;
1109    /* OrigX and OrigY are screen coordinates (scaled and translated). */
1110    /* OrigX and OrigY are also on grid. */
1111 {
1112    int i;
1113    XGCValues values;
1114    XEvent input, ev;
1115    XButtonEvent *button_ev;
1116    int abort=FALSE;
1117    int end_x, end_y, grid_x, grid_y, done=FALSE, num_pts=1;
1118    int last_x=OrigX, last_y=OrigY, n=2, sn=0, max_n=40, intn=0;
1119    int ltx=OrigX, lty=OrigY, rbx=OrigX, rby=OrigY;
1120    int one_line_status=FALSE, freehand_n=0, nothing_is_drawn=FALSE;
1121    char status_buf[MAX_STATUS_BTNS+1][MAXSTRING+1];
1122    IntPointTriplet ipt_prev, ipt, first_ipt;
1123    XPoint *sv=NULL, *freehand_vs=NULL;
1124    IntPoint *v=NULL, *cntrlv=NULL;
1125    PolyMeasureCursorInfo pmci;
1126 
1127    memset(&ipt, 0, sizeof(IntPointTriplet));
1128    memset(&ipt_prev, 0, sizeof(IntPointTriplet));
1129    memset(&first_ipt, 0, sizeof(IntPointTriplet));
1130    memset(&pmci, 0, sizeof(PolyMeasureCursorInfo));
1131    SetXorDrawGCForPoly(colorIndex, lineWidth);
1132 
1133    grid_x = end_x = OrigX;
1134    grid_y = end_y = OrigY;
1135    if (curChoice == FREEHAND) {
1136       freehand_vs = (XPoint*)malloc((max_n+1)*sizeof(XPoint));
1137       if (freehand_vs == NULL) FailAllocMessage();
1138       freehand_vs[0].x = freehand_vs[1].x = OrigX;
1139       freehand_vs[0].y = freehand_vs[1].y = OrigY;
1140       freehand_n = 1;
1141    } else if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1142       v = (IntPoint*)malloc((max_n+1)*sizeof(IntPoint));
1143       if (v == NULL) FailAllocMessage();
1144       v[0].x = v[1].x = v[2].x = ABS_X(OrigX);
1145       v[0].y = v[1].y = v[2].y = ABS_Y(OrigY);
1146       switch (curSpline) {
1147       case LT_SPLINE:
1148          sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX, drawOrigY, n,
1149                v);
1150          break;
1151       case LT_INTSPLINE:
1152          sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
1153                drawOrigX, drawOrigY, n, v);
1154          for (i=0; i < sn; i++) {
1155             if (sv[i].x < ltx) ltx = sv[i].x;
1156             if (sv[i].y < lty) lty = sv[i].y;
1157             if (sv[i].x > rbx) rbx = sv[i].x;
1158             if (sv[i].y > rby) rby = sv[i].y;
1159          }
1160          break;
1161       }
1162    } else if (curSpline == LT_STRUCT_SPLINE) {
1163       ipt_prev.earlier_valid = ipt_prev.later_valid = FALSE;
1164       ipt_prev.earlier_smooth_pt.x = ipt_prev.hinge_pt.x =
1165             ipt_prev.later_smooth_pt.x = OrigX;
1166       ipt_prev.earlier_smooth_pt.y = ipt_prev.hinge_pt.y =
1167             ipt_prev.later_smooth_pt.y = OrigY;
1168       memcpy(&first_ipt, &ipt_prev, sizeof(IntPointTriplet));
1169       v = (IntPoint*)malloc((max_n+1)*sizeof(IntPoint));
1170       if (v == NULL) FailAllocMessage();
1171       v[0].x = v[1].x = v[2].x = v[3].x = ABS_X(OrigX);
1172       v[0].y = v[1].y = v[2].y = v[3].y = ABS_Y(OrigY);
1173       sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX, drawOrigY, n+1,
1174             v);
1175    }
1176    SaveStatusStrings();
1177    if (curChoice == FREEHAND) {
1178       DoPolyMeasureCursor(&pmci, POLY_STARTSHOW, num_pts, ABS_X(grid_x),
1179             ABS_Y(grid_y), 0, 0, POLY_DRAW, POLY_CLICK);
1180       if (!debugNoPointerGrab) {
1181          XGrabPointer(mainDisplay, drawWindow, FALSE,
1182                PointerMotionMask | ButtonReleaseMask,
1183                GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1184       }
1185       SetFirstPoint(OrigX, OrigY, NULL);
1186    } else {
1187       if (curSpline == LT_STRUCT_SPLINE) {
1188          SetMouseStatus(TgLoadCachedString(CSTID_ADD_A_STRUCT_VERTEX),
1189                TgLoadCachedString(CSTID_ADD_LAST_VERTEX),
1190                TgLoadCachedString(CSTID_ADD_LAST_VERTEX));
1191       } else {
1192          SetMouseStatus(TgLoadCachedString(CSTID_ADD_A_VERTEX),
1193                TgLoadCachedString(CSTID_ADD_LAST_VERTEX),
1194                TgLoadCachedString(CSTID_ADD_LAST_VERTEX));
1195       }
1196       DoPolyMeasureCursor(&pmci, POLY_STARTSHOW, num_pts, ABS_X(grid_x),
1197             ABS_Y(grid_y), 0, 0, POLY_DRAW, POLY_CLICK);
1198       if (!debugNoPointerGrab) {
1199          XGrabPointer(mainDisplay, drawWindow, FALSE,
1200                PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1201                GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1202       }
1203       if (curSpline == LT_STRUCT_SPLINE) {
1204          DoPolyMeasureCursor(&pmci, POLY_DOSHOW, num_pts, ABS_X(grid_x),
1205                ABS_Y(grid_y), 0, 0, POLY_ERASE, POLY_DRAG);
1206          ContinueForStructSplinePolyControlPoints(OrigX, OrigY,
1207                grid_x, grid_y, &sv, &sn, &ipt_prev, &ipt, &abort);
1208          memcpy(&first_ipt, &ipt, sizeof(IntPointTriplet));
1209          memcpy(&ipt_prev, &ipt, sizeof(IntPointTriplet));
1210          if (first_ipt.later_valid) {
1211             grid_x = OFFSET_X(first_ipt.later_smooth_pt.x);
1212             grid_y = OFFSET_Y(first_ipt.later_smooth_pt.y);
1213          }
1214          SetFirstPoint(OrigX, OrigY, &first_ipt);
1215          DoPolyMeasureCursor(&pmci, POLY_STARTSHOW, num_pts, ABS_X(grid_x),
1216                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1217                ABS_SIZE(abs(grid_y-OrigY)), POLY_DRAW, POLY_CLICK);
1218       } else {
1219          SetFirstPoint(OrigX, OrigY, NULL);
1220       }
1221    }
1222    if (gstWiringInfo.num_ports_to_connect > 0 || drawPolyToConnectPins > 0) {
1223       *gstWiringInfo.last_port_name = '\0';
1224       drawPolyHighlightedNode = NULL;
1225       SaveStatusStringsIntoBuf(status_buf, &one_line_status);
1226       values.line_width = 3;
1227       XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
1228    }
1229    while (!done) {
1230       XNextEvent(mainDisplay, &input);
1231 
1232       if (input.type == Expose || input.type == VisibilityNotify) {
1233          ExposeEventHandler(&input, TRUE);
1234          SetXorDrawGCForPoly(colorIndex, lineWidth);
1235       } else if ((input.type==MotionNotify && input.xany.window==drawWindow) ||
1236             input.type == KeyPress || input.type == KeyRelease) {
1237          if (input.type == KeyPress) {
1238             if (KeyPressEventIsEscape(&input.xkey)) {
1239                /* erase */
1240                DoPolyMeasureCursor(&pmci, POLY_ENDSHOW, num_pts, ABS_X(grid_x),
1241                      ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1242                      ABS_SIZE(abs(grid_y-OrigY)), POLY_ERASE, POLY_CLICK);
1243                Msg("");
1244                abort = TRUE;
1245                done = TRUE;
1246             }
1247          }
1248          if (done) {
1249             break;
1250          }
1251          /* erase */
1252          if (curChoice == FREEHAND) {
1253             if (freehand_n > 1) {
1254                MyDrawLines(mainDisplay, drawWindow, drawGC,
1255                      freehand_vs, freehand_n);
1256             }
1257          } else {
1258             if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1259                MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1260             } else if (curSpline == LT_STRUCT_SPLINE) {
1261                if (nothing_is_drawn) {
1262                   /* then there is nothing to erase */
1263                   nothing_is_drawn = FALSE;
1264                } else {
1265                   if (sv == NULL) {
1266                      XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1267                            grid_x, grid_y);
1268                   } else {
1269                      MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1270                   }
1271                }
1272             } else {
1273                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, grid_x,
1274                      grid_y);
1275             }
1276          }
1277          DoPolyMeasureCursor(&pmci, POLY_DOSHOW, num_pts, ABS_X(grid_x),
1278                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1279                ABS_SIZE(abs(grid_y-OrigY)), POLY_ERASE, POLY_DRAG);
1280 
1281          if (input.type == KeyPress || input.type == KeyRelease) {
1282             end_x = grid_x;
1283             end_y = grid_y;
1284          } else {
1285             end_x = input.xmotion.x;
1286             end_y = input.xmotion.y;
1287          }
1288          if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
1289             if (input.type == KeyRelease) {
1290                end_x = input.xkey.x;
1291                end_y = input.xkey.y;
1292             } else {
1293                DiagGridXY(OrigX, OrigY, &end_x, &end_y);
1294             }
1295          }
1296          /* draw */
1297          if (curChoice == FREEHAND) {
1298             grid_x = end_x;
1299             grid_y = end_y;
1300             MarkRulers(grid_x, grid_y);
1301             if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1302                if (sv != NULL) {
1303                   free(sv);
1304                   sv = NULL;
1305                }
1306                v[n-1].x = v[n].x = ABS_X(grid_x);
1307                v[n-1].y = v[n].y = ABS_Y(grid_y);
1308                switch (curSpline) {
1309                case LT_SPLINE:
1310                   sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1311                         drawOrigY, n, v);
1312                   break;
1313                case LT_INTSPLINE:
1314                   if (cntrlv != NULL) free(cntrlv);
1315                   sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
1316                         drawOrigX, drawOrigY, n, v);
1317                   for (i=0; i < sn; i++) {
1318                      if (sv[i].x < ltx) ltx = sv[i].x;
1319                      if (sv[i].y < lty) lty = sv[i].y;
1320                      if (sv[i].x > rbx) rbx = sv[i].x;
1321                      if (sv[i].y > rby) rby = sv[i].y;
1322                   }
1323                   break;
1324                }
1325                MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1326             } else {
1327                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY, grid_x,
1328                      grid_y);
1329                if (sv != NULL) {
1330                   free(sv);
1331                   sv = NULL;
1332                }
1333             }
1334             while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1335 
1336             if (grid_x != last_x || grid_y != last_y) {
1337                num_pts++;
1338                AddPointForCont(grid_x, grid_y, &ipt);
1339                last_x = grid_x;
1340                last_y = grid_y;
1341                if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1342                   if (n >= max_n-2) {
1343                      max_n += 40;
1344                      v = (IntPoint*)realloc(v, sizeof(IntPoint)*max_n+1);
1345                      if (v == NULL) FailAllocMessage();
1346                   }
1347                   MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1348                   if (sv != NULL) {
1349                      free(sv);
1350                      sv = NULL;
1351                   }
1352                   v[n].x = v[n+1].x = ABS_X(grid_x);
1353                   v[n].y = v[n+1].y = ABS_Y(grid_y);
1354                   n++;
1355                   switch (curSpline) {
1356                   case LT_SPLINE:
1357                      sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1358                            drawOrigY, n, v);
1359                      break;
1360                   case LT_INTSPLINE:
1361                      if (cntrlv != NULL) free(cntrlv);
1362                      sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
1363                            drawOrigX, drawOrigY, n, v);
1364                      for (i=0; i < sn; i++) {
1365                         if (sv[i].x < ltx) ltx = sv[i].x;
1366                         if (sv[i].y < lty) lty = sv[i].y;
1367                         if (sv[i].x > rbx) rbx = sv[i].x;
1368                         if (sv[i].y > rby) rby = sv[i].y;
1369                      }
1370                      break;
1371                   }
1372                   MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1373                } else {
1374                   if (freehand_n >= max_n-2) {
1375                      max_n += 40;
1376                      freehand_vs = (XPoint*)realloc(freehand_vs,
1377                            sizeof(XPoint)*max_n+1);
1378                      if (freehand_vs == NULL) FailAllocMessage();
1379                   }
1380                   freehand_vs[freehand_n].x = grid_x;
1381                   freehand_vs[freehand_n].y = grid_y;
1382                   freehand_n++;
1383                }
1384             }
1385             OrigX = grid_x; OrigY = grid_y;
1386          } else {
1387             if (gstWiringInfo.num_ports_to_connect > 0) {
1388                int need_to_highlight=FALSE, something_changed=FALSE;
1389                struct ObjRec *owner_obj=NULL, *obj_ptr, *obj_under_cursor=NULL;
1390                char port_name[MAXSTRING];
1391 
1392                obj_ptr = FindAnObj(end_x, end_y, &owner_obj, &obj_under_cursor,
1393                      port_name);
1394                if (drawPolyHighlightedNode != NULL) {
1395                   if (obj_under_cursor != drawPolyHighlightedNode) {
1396                      /* un-highlight */
1397                      SelBox(drawWindow, revGrayGC,
1398                            OFFSET_X(drawPolyHighlightedNode->bbox.ltx)-2,
1399                            OFFSET_Y(drawPolyHighlightedNode->bbox.lty)-2,
1400                            OFFSET_X(drawPolyHighlightedNode->bbox.rbx)+2,
1401                            OFFSET_Y(drawPolyHighlightedNode->bbox.rby)+2);
1402                      if (obj_under_cursor != NULL &&
1403                            ObjIsAPort(obj_under_cursor)) {
1404                         drawPolyHighlightedNode = obj_under_cursor;
1405                         SetWiringNodeInfo(obj_under_cursor, owner_obj,
1406                               port_name, FALSE);
1407                      } else {
1408                         drawPolyHighlightedNode = NULL;
1409                         SetWiringNodeInfo(NULL, NULL, NULL, FALSE);
1410                      }
1411                      if (drawPolyHighlightedNode != NULL) {
1412                         need_to_highlight = TRUE;
1413                      }
1414                      something_changed = TRUE;
1415                   }
1416                } else {
1417                   if (obj_under_cursor != NULL) {
1418                      if (ObjIsAPort(obj_under_cursor)) {
1419                         drawPolyHighlightedNode = obj_under_cursor;
1420                         SetWiringNodeInfo(obj_under_cursor, owner_obj,
1421                               port_name, FALSE);
1422                      } else {
1423                         drawPolyHighlightedNode = NULL;
1424                         SetWiringNodeInfo(NULL, NULL, NULL, FALSE);
1425                      }
1426                      if (drawPolyHighlightedNode != NULL) {
1427                         need_to_highlight = TRUE;
1428                         something_changed = TRUE;
1429                      }
1430                   }
1431                }
1432                if (need_to_highlight) {
1433                   SelBox(drawWindow, revGrayGC,
1434                         OFFSET_X(drawPolyHighlightedNode->bbox.ltx)-2,
1435                         OFFSET_Y(drawPolyHighlightedNode->bbox.lty)-2,
1436                         OFFSET_X(drawPolyHighlightedNode->bbox.rbx)+2,
1437                         OFFSET_Y(drawPolyHighlightedNode->bbox.rby)+2);
1438                }
1439                if (something_changed) {
1440                   if (*gstWiringInfo.last_port_name != '\0') {
1441                      sprintf(gszMsgBox,
1442                            TgLoadCachedString(CSTID_END_A_WIRE_AT_NAMED_PORT),
1443                            gstWiringInfo.last_port_name);
1444                      SetStringStatus(gszMsgBox);
1445                   } else {
1446                      RestoreStatusStringsFromBuf(status_buf, one_line_status);
1447                      SetMouseStatus(TgLoadCachedString(CSTID_ADD_A_VERTEX),
1448                            TgLoadCachedString(CSTID_ADD_LAST_VERTEX),
1449                            TgLoadCachedString(CSTID_ADD_LAST_VERTEX));
1450                   }
1451                }
1452                if (drawPolyHighlightedNode != NULL) {
1453                   grid_x = OFFSET_X((drawPolyHighlightedNode->obbox.ltx +
1454                         drawPolyHighlightedNode->obbox.rbx)>>1);
1455                   grid_y = OFFSET_Y((drawPolyHighlightedNode->obbox.lty +
1456                         drawPolyHighlightedNode->obbox.rby)>>1);
1457                } else {
1458                   GridXY(end_x, end_y, &grid_x, &grid_y);
1459                }
1460 #ifdef _NOT_DEFINED
1461             /*
1462              * drawPolyToConnectPins is only set to > 0 in "pin.c"
1463              * what's in "pin.c" is not used at this time
1464              */
1465             } else if (drawPolyToConnectPins > 0) {
1466                HandlePinHighlights(end_x, end_y);
1467                if (drawPolyHighlightedNode != NULL) {
1468                   grid_x = OFFSET_X((drawPolyHighlightedNode->obbox.ltx +
1469                         drawPolyHighlightedNode->obbox.rbx)>>1);
1470                   grid_y = OFFSET_Y((drawPolyHighlightedNode->obbox.lty +
1471                         drawPolyHighlightedNode->obbox.rby)>>1);
1472                } else {
1473                   GridXY(end_x, end_y, &grid_x, &grid_y);
1474                }
1475 #endif /* _NOT_DEFINED */
1476             } else {
1477                GridXY(end_x, end_y, &grid_x, &grid_y);
1478             }
1479             MarkRulers(grid_x, grid_y);
1480             if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1481                if (sv != NULL) {
1482                   free(sv);
1483                   sv = NULL;
1484                }
1485                v[n-1].x = v[n].x = ABS_X(grid_x);
1486                v[n-1].y = v[n].y = ABS_Y(grid_y);
1487                switch (curSpline) {
1488                case LT_SPLINE:
1489                   sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1490                         drawOrigY, n, v);
1491                   break;
1492                case LT_INTSPLINE:
1493                   free(cntrlv);
1494                   sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
1495                         drawOrigX, drawOrigY, n, v);
1496                   for (i=0; i < sn; i++) {
1497                      if (sv[i].x < ltx) ltx = sv[i].x;
1498                      if (sv[i].y < lty) lty = sv[i].y;
1499                      if (sv[i].x > rbx) rbx = sv[i].x;
1500                      if (sv[i].y > rby) rby = sv[i].y;
1501                   }
1502                   break;
1503                }
1504                MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1505             } else if (curSpline == LT_STRUCT_SPLINE) {
1506                if (sv != NULL) {
1507                   free(sv);
1508                   sv = NULL;
1509                }
1510                if (ipt_prev.later_valid) {
1511                   v[0].x = ABS_X(OrigX);
1512                   v[0].y = ABS_Y(OrigY);
1513                   v[1].x = ABS_X(ipt_prev.later_smooth_pt.x);
1514                   v[1].y = ABS_Y(ipt_prev.later_smooth_pt.y);
1515                   v[2].x = v[3].x = ABS_X(grid_x);
1516                   v[2].y = v[3].y = ABS_Y(grid_y);
1517                   n = 3;
1518                   sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1519                         drawOrigY, n, v);
1520                   MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1521                } else {
1522                   XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1523                         grid_x, grid_y);
1524                   if (sv != NULL) {
1525                      free(sv);
1526                      sv = NULL;
1527                   }
1528                }
1529             } else {
1530                XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1531                      grid_x, grid_y);
1532             }
1533          }
1534          DoPolyMeasureCursor(&pmci, POLY_DOSHOW, num_pts, ABS_X(grid_x),
1535                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1536                ABS_SIZE(abs(grid_y-OrigY)), POLY_DRAW, POLY_DRAG);
1537          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1538       } else if (input.type == ButtonPress && curChoice != FREEHAND) {
1539          /* erase */
1540          DoPolyMeasureCursor(&pmci, POLY_ENDSHOW, num_pts, ABS_X(grid_x),
1541                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1542                ABS_SIZE(abs(grid_y-OrigY)), POLY_ERASE, POLY_DRAG);
1543 
1544          button_ev = &(input.xbutton);
1545 
1546          end_x = button_ev->x;
1547          end_y = button_ev->y;
1548          if (shiftForDiagMouseMove && DiagEventCheck(&input)) {
1549             DiagGridXY(OrigX, OrigY, &end_x, &end_y);
1550          }
1551          if (drawPolyHighlightedNode != NULL) {
1552             grid_x = OFFSET_X((drawPolyHighlightedNode->obbox.ltx +
1553                   drawPolyHighlightedNode->obbox.rbx)>>1);
1554             grid_y = OFFSET_Y((drawPolyHighlightedNode->obbox.lty +
1555                   drawPolyHighlightedNode->obbox.rby)>>1);
1556          } else {
1557             GridXY(end_x, end_y, &grid_x, &grid_y);
1558          }
1559          if (grid_x == last_x && grid_y == last_y) {
1560             if (curSpline == LT_STRUCT_SPLINE) {
1561                if (num_pts == 1) {
1562                   abort = TRUE;
1563                } else {
1564                   /* need to overwrite the previous point */
1565 
1566                   /* erase */
1567                   if (sv != NULL) {
1568                      MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1569                      free(sv);
1570                      sv = NULL;
1571                   } else {
1572                      XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1573                            grid_x, grid_y);
1574                   }
1575                   if (ipt_prev.later_valid) {
1576                      /* erase whole curve */
1577                      DrawAllStructSplinePointsForCont(num_pts);
1578                      ipt_prev.earlier_valid = ipt_prev.later_valid = FALSE;
1579                      ipt_prev.earlier_smooth_pt.x = ipt_prev.later_smooth_pt.x =
1580                            ipt_prev.hinge_pt.x;
1581                      ipt_prev.earlier_smooth_pt.y = ipt_prev.later_smooth_pt.y =
1582                            ipt_prev.hinge_pt.y;
1583                      UpdateLastPointForCont(&ipt_prev);
1584                      /* draw whole curve */
1585                      DrawAllStructSplinePointsForCont(num_pts);
1586                   }
1587                   UpdatePrevToLastPointForCont(&ipt_prev);
1588                   ipt.earlier_valid = ipt.later_valid = FALSE;
1589                   ipt.earlier_smooth_pt.x = ipt.later_smooth_pt.x =
1590                         ipt.hinge_pt.x = grid_x;
1591                   ipt.earlier_smooth_pt.y = ipt.later_smooth_pt.y =
1592                         ipt.hinge_pt.y = grid_y;
1593                   OrigX = ipt_prev.hinge_pt.x;
1594                   OrigY = ipt_prev.hinge_pt.y;
1595                   if (ipt_prev.later_valid) {
1596                      v[0].x = ABS_X(OrigX);
1597                      v[0].y = ABS_Y(OrigY);
1598                      v[1].x = ABS_X(ipt_prev.later_smooth_pt.x);
1599                      v[1].y = ABS_Y(ipt_prev.later_smooth_pt.y);
1600                      v[2].x = v[3].x = ABS_X(grid_x);
1601                      v[2].y = v[3].y = ABS_Y(grid_y);
1602                      n = 3;
1603                      sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1604                            drawOrigY, n, v);
1605                   }
1606                }
1607             }
1608          } else {
1609             num_pts++;
1610             AddPointForCont(grid_x, grid_y, &ipt);
1611             last_x = grid_x;
1612             last_y = grid_y;
1613             if (curSpline != LT_STRAIGHT && curSpline != LT_STRUCT_SPLINE) {
1614                if (n >= max_n-2) {
1615                   max_n += 40;
1616                   v = (IntPoint*)realloc(v, sizeof(IntPoint)*max_n+1);
1617                   if (v == NULL) FailAllocMessage();
1618                }
1619                /* erase */
1620                MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1621                if (sv != NULL) {
1622                   free(sv);
1623                   sv = NULL;
1624                }
1625                v[n].x = v[n+1].x = ABS_X(grid_x);
1626                v[n].y = v[n+1].y = ABS_Y(grid_y);
1627                n++;
1628                switch (curSpline) {
1629                case LT_SPLINE:
1630                   sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1631                         drawOrigY, n, v);
1632                   break;
1633                case LT_INTSPLINE:
1634                   if (cntrlv != NULL) free(cntrlv);
1635                   sv = MakeIntSplinePolyVertex(&sn, &intn, &cntrlv,
1636                         drawOrigX, drawOrigY, n, v);
1637                   for (i=0; i < sn; i++) {
1638                      if (sv[i].x < ltx) ltx = sv[i].x;
1639                      if (sv[i].y < lty) lty = sv[i].y;
1640                      if (sv[i].x > rbx) rbx = sv[i].x;
1641                      if (sv[i].y > rby) rby = sv[i].y;
1642                   }
1643                   break;
1644                }
1645                /* draw */
1646                MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1647             } else if (curSpline == LT_STRUCT_SPLINE) {
1648                /* erase */
1649                if (sv != NULL) {
1650                   MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1651                   free(sv);
1652                   sv = NULL;
1653                } else {
1654                   XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1655                         grid_x, grid_y);
1656                }
1657                /* draw */
1658                if (ipt_prev.later_valid) {
1659                   v[0].x = ABS_X(OrigX);
1660                   v[0].y = ABS_Y(OrigY);
1661                   v[1].x = ABS_X(ipt_prev.later_smooth_pt.x);
1662                   v[1].y = ABS_Y(ipt_prev.later_smooth_pt.y);
1663                   v[2].x = v[3].x = ABS_X(grid_x);
1664                   v[2].y = v[3].y = ABS_Y(grid_y);
1665                   n = 3;
1666                   sv = MakeSplinePolyVertex(0, curSpline, &sn, drawOrigX,
1667                         drawOrigY, n, v);
1668                   MyDrawLines(mainDisplay, drawWindow, drawGC, sv, sn);
1669                } else {
1670                   XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1671                         grid_x, grid_y);
1672                   if (sv != NULL) {
1673                      free(sv);
1674                      sv = NULL;
1675                   }
1676                }
1677             }
1678          }
1679 
1680          switch (button_ev->button) {
1681          case Button1:
1682             if ((drawPolyToConnectPins > 0 &&
1683                   drawPolyHighlightedNode != NULL) ||
1684                   (gstWiringInfo.num_ports_to_connect > 0 &&
1685                   drawPolyHighlightedNode != NULL)) {
1686                gpEndPin = drawPolyHighlightedNode;
1687                done = TRUE;
1688             } else {
1689                if (curSpline == LT_STRUCT_SPLINE) {
1690                   ContinueForStructSplinePolyControlPoints(OrigX, OrigY, grid_x,
1691                         grid_y, &sv, &sn, &ipt_prev, &ipt, &abort);
1692                   UpdateLastPointForCont(&ipt);
1693                   /* at this point, the curve has been drawn */
1694                   if (sv != NULL) {
1695                      free(sv);
1696                      sv = NULL;
1697                   }
1698                   nothing_is_drawn = TRUE;
1699                   if (!abort) {
1700                      CVListElem *elem=ListLast(&gStructSplineList);
1701 
1702                      if (elem != NULL) {
1703                         IntPointTriplet *pipt=(IntPointTriplet*)(elem->obj);
1704 
1705                         memcpy(pipt, &ipt, sizeof(IntPointTriplet));
1706                      }
1707                      memcpy(&ipt_prev, &ipt, sizeof(IntPointTriplet));
1708                      OrigX = ipt.hinge_pt.x;
1709                      OrigY = ipt.hinge_pt.y;
1710                      if (ipt.later_valid) {
1711                         grid_x = ipt.later_smooth_pt.x;
1712                         grid_y = ipt.later_smooth_pt.y;
1713                      } else {
1714                         grid_x = ipt.hinge_pt.x;
1715                         grid_y = ipt.hinge_pt.y;
1716                      }
1717                      DoPolyMeasureCursor(&pmci, POLY_STARTSHOW, num_pts,
1718                            ABS_X(grid_x), ABS_Y(grid_y),
1719                            ABS_SIZE(abs(grid_x-OrigX)),
1720                            ABS_SIZE(abs(grid_y-OrigY)), POLY_DRAW, POLY_CLICK);
1721                   }
1722                } else {
1723                   OrigX = grid_x;
1724                   OrigY = grid_y;
1725                   /* draw */
1726                   DoPolyMeasureCursor(&pmci, POLY_STARTSHOW, num_pts,
1727                         ABS_X(grid_x), ABS_Y(grid_y), 0, 0, POLY_DRAW,
1728                         POLY_CLICK);
1729                   XDrawLine(mainDisplay, drawWindow, drawGC, OrigX, OrigY,
1730                         grid_x, grid_y);
1731                }
1732             }
1733             break;
1734          case Button2:
1735          case Button3:
1736 #ifdef _NOT_DEFINED
1737             /*
1738              * drawPolyToConnectPins is only set to > 0 in "pin.c"
1739              * what's in "pin.c" is not used at this time
1740              */
1741             if (drawPolyToConnectPins > 0) {
1742                if (drawPolyHighlightedNode == NULL) {
1743                   abort = TRUE;
1744                } else {
1745                   gpEndPin = drawPolyHighlightedNode;
1746                }
1747             }
1748 #endif /* _NOT_DEFINED */
1749             if (curSpline == LT_STRUCT_SPLINE) {
1750                memset(&ipt, 0, sizeof(IntPointTriplet));
1751                ipt.earlier_valid = ipt.later_valid = FALSE;
1752                ipt.hinge_pt.x = ipt.earlier_smooth_pt.x =
1753                      ipt.later_smooth_pt.x = grid_x;
1754                ipt.hinge_pt.y = ipt.earlier_smooth_pt.y =
1755                      ipt.later_smooth_pt.y = grid_y;
1756                ipt.ratio = (double)1;
1757                ContinueForStructSplinePolyControlPoints(OrigX, OrigY, grid_x,
1758                      grid_y, &sv, &sn, &ipt_prev, &ipt, &abort);
1759                UpdateLastPointForCont(&ipt);
1760             }
1761             done = TRUE;
1762             break;
1763          }
1764       } else if (input.type == ButtonRelease && curChoice == FREEHAND) {
1765          DoPolyMeasureCursor(&pmci, POLY_ENDSHOW, num_pts, ABS_X(grid_x),
1766                ABS_Y(grid_y), ABS_SIZE(abs(grid_x-OrigX)),
1767                ABS_SIZE(abs(grid_y-OrigY)), POLY_ERASE, POLY_CLICK);
1768 
1769          button_ev = &(input.xbutton);
1770 
1771          if (grid_x != last_x || grid_y != last_y) {
1772             num_pts++;
1773             AddPointForCont(grid_x, grid_y, &ipt);
1774             last_x = grid_x;
1775             last_y = grid_y;
1776          }
1777          done = TRUE;
1778       }
1779    }
1780    if (drawPolyHighlightedNode != NULL) {
1781       if (gstWiringInfo.num_ports_to_connect > 0) {
1782          SelBox(drawWindow, revGrayGC,
1783                OFFSET_X(drawPolyHighlightedNode->bbox.ltx)-2,
1784                OFFSET_Y(drawPolyHighlightedNode->bbox.lty)-2,
1785                OFFSET_X(drawPolyHighlightedNode->bbox.rbx)+2,
1786                OFFSET_Y(drawPolyHighlightedNode->bbox.rby)+2);
1787 #ifdef _NOT_DEFINED
1788       /*
1789        * drawPolyToConnectPins is only set to > 0 in "pin.c"
1790        * what's in "pin.c" is not used at this time
1791        */
1792       } else if (drawPolyToConnectPins > 0) {
1793          HighLightAPin(FALSE);
1794 #endif /* _NOT_DEFINED */
1795       }
1796       drawPolyHighlightedNode = NULL;
1797    } else if (!abort && gstWiringInfo.num_ports_to_connect > 0) {
1798       XBell(mainDisplay, 0);
1799       Msg("");
1800       Msg(TgLoadString(STID_TRY_AGAIN_AND_END_IN_A_PORT));
1801       abort = TRUE;
1802    }
1803    XUngrabPointer(mainDisplay, CurrentTime);
1804    if (gstWiringInfo.num_ports_to_connect > 0 || drawPolyToConnectPins > 0) {
1805       values.line_width = 1;
1806       XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
1807       RestoreStatusStringsFromBuf(status_buf, one_line_status);
1808    }
1809    RestoreStatusStrings();
1810    SetMouseStatus(NULL, NULL, NULL);
1811    if (!abort) Msg("");
1812 
1813    values.join_style = JoinMiter;
1814    XChangeGC(mainDisplay, drawGC, GCJoinStyle, &values);
1815 
1816    if (v != NULL) free(v);
1817    if (sv != NULL) free(sv);
1818    if (cntrlv != NULL) free(cntrlv);
1819    if (curChoice == FREEHAND && freehand_vs != NULL) {
1820       free(freehand_vs);
1821    }
1822    if (!abort && num_pts > 1) {
1823       CreatePolyObj(num_pts, CREATE_RELATIVE);
1824       RecordNewObjCmd();
1825       RedrawAnArea(botObj, topObj->bbox.ltx-GRID_ABS_SIZE(1),
1826             topObj->bbox.lty-GRID_ABS_SIZE(1),
1827             topObj->bbox.rbx+GRID_ABS_SIZE(1),
1828             topObj->bbox.rby+GRID_ABS_SIZE(1));
1829       polyDrawn = TRUE;
1830       SetFileModified(TRUE);
1831    } else {
1832       if (curSpline != LT_INTSPLINE) {
1833          ltx = rbx = grid_x;
1834          lty = rby = grid_y;
1835       }
1836       FreePointsForCont(&ltx, &lty, &rbx, &rby);
1837       RedrawAnArea(botObj, ABS_X(ltx)-GRID_ABS_SIZE(1),
1838             ABS_Y(lty)-GRID_ABS_SIZE(1), ABS_X(rbx)+GRID_ABS_SIZE(1),
1839             ABS_Y(rby)+GRID_ABS_SIZE(1));
1840       numPtsInPoly = 0;
1841       lastPtPtr = NULL;
1842       polyDrawn = FALSE;
1843    }
1844    if (gstWiringInfo.num_ports_to_connect == 2 && !polyDrawn) {
1845       gstWiringInfo.num_ports_to_connect = (-1);
1846    }
1847 #ifdef _NOT_DEFINED
1848    /*
1849     * drawPolyToConnectPins is only set to > 0 in "pin.c"
1850     * what's in "pin.c" is not used at this time
1851     */
1852    if (drawPolyToConnectPins == 2 && !polyDrawn) {
1853       drawPolyToConnectPins = (-1);
1854    }
1855 #endif /* _NOT_DEFINED */
1856 }
1857 
DrawPoly(input)1858 void DrawPoly(input)
1859    XEvent *input;
1860 {
1861    int mouse_x, mouse_y, grid_x, grid_y;
1862    XButtonEvent *button_ev;
1863 
1864    if (input->type == KeyPress && curChoice == DRAWPOLY &&
1865          gstWiringInfo.num_ports_to_connect > 0) {
1866       if (KeyPressEventIsEscape(&input->xkey)) {
1867          HandlePressForPortInDrawWindow(TRUE);
1868       }
1869       return;
1870    }
1871    if (input->type != ButtonPress) return;
1872 
1873    button_ev = &(input->xbutton);
1874    if (button_ev->button == Button1) {
1875       int saved_cur_spline=curSpline;
1876 
1877       mouse_x = input->xbutton.x;
1878       mouse_y = input->xbutton.y;
1879       if (gstWiringInfo.num_ports_to_connect > 0 || drawPolyToConnectPins > 0 ||
1880             curChoice == FREEHAND) {
1881          if (drawPolyHighlightedNode != NULL) {
1882             grid_x = OFFSET_X((drawPolyHighlightedNode->obbox.ltx +
1883                   drawPolyHighlightedNode->obbox.rbx)>>1);
1884             grid_y = OFFSET_Y((drawPolyHighlightedNode->obbox.lty +
1885                   drawPolyHighlightedNode->obbox.rby)>>1);
1886             if (gstWiringInfo.num_ports_to_connect > 0 ||
1887                   curChoice == FREEHAND) {
1888                HandlePressForPortInDrawWindow(FALSE);
1889 #ifdef _NOT_DEFINED
1890             /*
1891              * drawPolyToConnectPins is only set to > 0 in "pin.c"
1892              * what's in "pin.c" is not used at this time
1893              */
1894             } else if (drawPolyToConnectPins > 0) {
1895                HighLightAPin(TRUE);
1896 #endif /* _NOT_DEFINED */
1897             }
1898             drawPolyHighlightedNode = NULL;
1899          } else if (gstWiringInfo.num_ports_to_connect > 0 ||
1900                drawPolyToConnectPins > 0) {
1901             XBell(mainDisplay, 0);
1902             SetStringStatus(TgLoadString(STID_TRY_AGAIN_AND_CLICK_IN_A_PORT));
1903             return;
1904          } else {
1905             grid_x = mouse_x;
1906             grid_y = mouse_y;
1907          }
1908       } else {
1909          GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
1910       }
1911       if (curChoice == FREEHAND) curSpline = LT_STRAIGHT;
1912 
1913       ContinuePoly(grid_x, grid_y);
1914 
1915       if (curChoice == FREEHAND) curSpline = saved_cur_spline;
1916    }
1917 }
1918 
SetWiringNodeInfo(port_obj,port_owner_obj,port_name,first)1919 void SetWiringNodeInfo(port_obj, port_owner_obj, port_name, first)
1920    struct ObjRec *port_obj, *port_owner_obj;
1921    char *port_name;
1922    int first;
1923 {
1924    if (first) {
1925       gstWiringInfo.first_port_obj = port_obj;
1926       gstWiringInfo.first_port_owner_obj = port_owner_obj;
1927       if (port_name == NULL) {
1928          *gstWiringInfo.first_port_name = '\0';
1929       } else {
1930          UtilStrCpyN(gstWiringInfo.first_port_name,
1931                sizeof(gstWiringInfo.first_port_name), port_name);
1932       }
1933    } else {
1934       gstWiringInfo.last_port_obj = port_obj;
1935       gstWiringInfo.last_port_owner_obj = port_owner_obj;
1936       if (port_name == NULL) {
1937          *gstWiringInfo.last_port_name = '\0';
1938       } else {
1939          UtilStrCpyN(gstWiringInfo.last_port_name,
1940                sizeof(gstWiringInfo.last_port_name), port_name);
1941       }
1942    }
1943 }
1944 
ResetWiringNodeInfo()1945 void ResetWiringNodeInfo()
1946 {
1947    memset(&gstWiringInfo, 0, sizeof(WiringInfo));
1948 }
1949 
InputPolyPts()1950 void InputPolyPts()
1951 {
1952    char inbuf[MAXSTRING+1];
1953    int more_poly=FALSE, num_polys=0;
1954    int started_composite=FALSE;
1955    struct ObjRec *saved_top_obj=topObj;
1956 
1957    MakeQuiescent();
1958    XSync(mainDisplay, False);
1959    do {
1960       int len, ok=TRUE, num_pts=0, eof=TRUE;
1961       struct PtRec *pt_ptr;
1962 
1963       more_poly = FALSE;
1964       numPtsInPoly = 0;
1965       lastPtPtr = NULL;
1966       printf("%s\n", TgLoadString(STID_INPUT_PAIRS_OF_POINTS_POLY));
1967       printf("> ");
1968       fflush(stdout);
1969       while (ok && fgets(inbuf, MAXSTRING, stdin) != NULL) {
1970          if (strcmp(inbuf, ";\n") == 0) {
1971             more_poly = TRUE;
1972             eof = FALSE;
1973             break;
1974          }
1975          if (strcmp(inbuf, ".\n") == 0) {
1976             eof = FALSE;
1977             break;
1978          }
1979          len = strlen(inbuf);
1980          if (len > 0) {
1981             char *c_ptr=strtok(inbuf," ,\t\n"), *c_ptr1=NULL;
1982 
1983             if (c_ptr != NULL) {
1984                c_ptr1 = strtok(NULL," ,\t\n");
1985             }
1986             if (c_ptr1 != NULL) {
1987                while (strchr(" ,\t\n", *c_ptr1)) c_ptr1++;
1988             }
1989             while (c_ptr != NULL && c_ptr1 != NULL) {
1990                num_pts++;
1991                pt_ptr = (struct PtRec *)malloc(sizeof(struct PtRec));
1992                if (pt_ptr == NULL) FailAllocMessage();
1993                pt_ptr->next = lastPtPtr;
1994                if (sscanf(c_ptr, "%d", &pt_ptr->x) != 1 ||
1995                      sscanf(c_ptr1, "%d", &pt_ptr->y) != 1) {
1996                   ok = FALSE;
1997                   MsgBox(TgLoadString(STID_READ_INT_ERROR_FOR_POLY_PTS),
1998                         TOOL_NAME, INFO_MB);
1999                   XSync(mainDisplay, False);
2000                   break;
2001                }
2002                lastPtPtr = pt_ptr;
2003                c_ptr = strtok(NULL," ,\t\n");
2004                if (c_ptr != NULL) {
2005                   c_ptr1 = strtok(NULL," ,\t\n");
2006                }
2007                if (c_ptr1 != NULL) {
2008                   while (strchr(" ,\t\n", *c_ptr1)) c_ptr1++;
2009                }
2010             }
2011             if (c_ptr != NULL) {
2012                ok = FALSE;
2013                MsgBox(TgLoadString(STID_READ_INT_ERROR_FOR_POLY_PTS), TOOL_NAME,
2014                      INFO_MB);
2015                XSync(mainDisplay, False);
2016             }
2017          }
2018          printf("> ");
2019          fflush(stdout);
2020       }
2021       printf("\n");
2022       if (eof) rewind(stdin);
2023       if (ok && num_pts > 1) {
2024          num_polys++;
2025          CreatePolyObj(num_pts, CREATE_ABSOLUTE);
2026          if (more_poly || num_polys > 1) {
2027             if (num_polys <= 1) {
2028                StartCompositeCmd();
2029                started_composite = TRUE;
2030             }
2031             RecordNewObjCmd();
2032             numRedrawBBox = 0;
2033             topObj->tmp_parent = NULL;
2034             DrawObj(drawWindow, topObj);
2035          } else {
2036             RecordNewObjCmd();
2037             RedrawAnArea(botObj, topObj->bbox.ltx-GRID_ABS_SIZE(1),
2038                   topObj->bbox.lty-GRID_ABS_SIZE(1),
2039                   topObj->bbox.rbx+GRID_ABS_SIZE(1),
2040                   topObj->bbox.rby+GRID_ABS_SIZE(1));
2041             SelectTopObj();
2042             SetFileModified(TRUE);
2043             justDupped = FALSE;
2044          }
2045       }
2046       if (ok && num_pts <= 1) {
2047          MsgBox(TgLoadString(STID_TOO_FEW_POINTERS_ENTERED), TOOL_NAME,
2048                INFO_MB);
2049          XSync(mainDisplay, False);
2050       }
2051       for ( ; lastPtPtr != NULL; lastPtPtr=pt_ptr) {
2052          pt_ptr = lastPtPtr->next;
2053          free(pt_ptr);
2054       }
2055    } while (more_poly);
2056    if (num_polys > 1 || started_composite) {
2057       SelectAndHighLightNewObjects(saved_top_obj);
2058       GroupSelObj(TRUE, TRUE, TRUE);
2059       EndCompositeCmd();
2060 
2061       SetFileModified(TRUE);
2062       justDupped = FALSE;
2063    }
2064 }
2065 
2066 /* --------------------- JoinPoly() --------------------- */
2067 
2068 static
FinishJoinPoly(obj_ptr1,obj_ptr2,poly_ptr1,vs,smooth,num_pts)2069 void FinishJoinPoly(obj_ptr1, obj_ptr2, poly_ptr1, vs, smooth, num_pts)
2070    struct ObjRec *obj_ptr1, *obj_ptr2;
2071    struct PolyRec *poly_ptr1;
2072    IntPoint *vs;
2073    char *smooth;
2074    int num_pts;
2075 {
2076    struct SelRec *sel_ptr, *top_sel=NULL, *bot_sel=NULL;
2077    int x0=0, y0=0, index0=0;
2078 
2079    if (curChoice == VERTEXMODE) {
2080       if (topVSel->obj == obj_ptr1) {
2081          index0 = topVSel->v_index[0];
2082          x0 = topVSel->x[0];
2083          y0 = topVSel->y[0];
2084       } else {
2085          index0 = botVSel->v_index[0];
2086          x0 = botVSel->x[0];
2087          y0 = botVSel->y[0];
2088       }
2089    }
2090    RemoveAllSel();
2091    if (obj_ptr2->fattr != NULL) {
2092       int count=0;
2093       struct SelRec *next_sel;
2094 
2095       PrepareToReplaceAnObj(obj_ptr2);
2096       DetachAllObjAttrs(obj_ptr2, &top_sel, &bot_sel);
2097       /* obj_ptr2 is pointed to by bot_sel now */
2098       AdjObjBBox(obj_ptr2);
2099       for (sel_ptr=top_sel; sel_ptr != NULL; sel_ptr=sel_ptr->next) count++;
2100       RecordCmd(CMD_ONE_TO_MANY, NULL, top_sel, bot_sel, count);
2101       sel_ptr = bot_sel;
2102       bot_sel = bot_sel->prev;
2103       bot_sel->next = NULL;
2104       free(sel_ptr);
2105       if (curChoice == VERTEXMODE) {
2106          for (sel_ptr=top_sel; sel_ptr != NULL; sel_ptr=next_sel) {
2107             next_sel = sel_ptr->next;
2108             free(sel_ptr);
2109          }
2110          top_sel = bot_sel = NULL;
2111       }
2112    }
2113    sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
2114    if (sel_ptr == NULL) FailAllocMessage();
2115    sel_ptr->next = sel_ptr->prev = NULL;
2116    sel_ptr->obj = obj_ptr2;
2117    PrepareToRecord(CMD_DELETE, sel_ptr, sel_ptr, 1);
2118    UnlinkObj(obj_ptr2);
2119    FreeObj(obj_ptr2);
2120    RecordCmd(CMD_DELETE, NULL, NULL, NULL, 0);
2121    free(sel_ptr);
2122 
2123    PrepareToReplaceAnObj(obj_ptr1);
2124 
2125    if (poly_ptr1->vlist != NULL) free(poly_ptr1->vlist);
2126    if (poly_ptr1->svlist != NULL) free(poly_ptr1->svlist);
2127    if (poly_ptr1->asvlist != NULL) free(poly_ptr1->asvlist);
2128    if (poly_ptr1->smooth != NULL) free(poly_ptr1->smooth);
2129    if (poly_ptr1->intvlist != NULL) free(poly_ptr1->intvlist);
2130    if (poly_ptr1->rotated_vlist != NULL) free(poly_ptr1->rotated_vlist);
2131    if (poly_ptr1->rotated_asvlist != NULL) free(poly_ptr1->rotated_asvlist);
2132    poly_ptr1->smooth = smooth;
2133    poly_ptr1->vlist = poly_ptr1->intvlist = NULL;
2134    poly_ptr1->n = poly_ptr1->intn = 0;
2135    poly_ptr1->svlist = poly_ptr1->asvlist = poly_ptr1->rotated_vlist =
2136          poly_ptr1->rotated_asvlist = NULL;
2137    poly_ptr1->sn = poly_ptr1->asn = poly_ptr1->rotated_n =
2138          poly_ptr1->rotated_asn = 0;
2139    if (obj_ptr1->ctm != NULL) free(obj_ptr1->ctm);
2140    obj_ptr1->ctm = NULL;
2141 
2142    poly_ptr1->vlist = vs;
2143    poly_ptr1->n = num_pts;
2144 
2145    AdjObjSplineVs(obj_ptr1);
2146    if (poly_ptr1->curved != LT_INTSPLINE) {
2147       UpdPolyBBox(obj_ptr1, poly_ptr1->n, poly_ptr1->vlist);
2148    } else {
2149       UpdPolyBBox(obj_ptr1, poly_ptr1->intn, poly_ptr1->intvlist);
2150    }
2151    AdjObjBBox(obj_ptr1);
2152    RecordReplaceAnObj(obj_ptr1);
2153 
2154    topSel = (struct SelRec *)malloc(sizeof(struct SelRec));
2155    if (topSel == NULL) FailAllocMessage();
2156    topSel->obj = obj_ptr1;
2157    topSel->prev = NULL;
2158    topSel->next = top_sel;
2159    if (top_sel != NULL) {
2160       top_sel->prev = topSel;
2161       botSel = bot_sel;
2162    } else {
2163       botSel = topSel;
2164    }
2165    if (curChoice == VERTEXMODE) {
2166       topVSel = botVSel = (struct VSelRec *)malloc(sizeof(struct VSelRec));
2167       if (topVSel == NULL) FailAllocMessage();
2168       memset(topVSel, 0, sizeof(struct VSelRec));
2169       topVSel->obj = obj_ptr1;
2170       topVSel->max_v = 10;
2171       topVSel->v_index = (int*)malloc(10*sizeof(int));
2172       topVSel->x = (int*)malloc(10*sizeof(int));
2173       topVSel->y = (int*)malloc(10*sizeof(int));
2174       if (topVSel->v_index==NULL || topVSel->x==NULL || topVSel->y==NULL) {
2175          FailAllocMessage();
2176       }
2177       topVSel->v_index[0] = index0;
2178       topVSel->x[0] = x0;
2179       topVSel->y[0] = y0;
2180       topVSel->n = 1;
2181       topVSel->next = topVSel->prev = NULL;
2182    }
2183 }
2184 
2185 typedef struct tagJoinStructSplineInfo {
2186    StretchStructuredSplineInfo sssi1, sssi2;
2187 } JoinStructSplineInfo;
2188 
2189 static
DoJoinPoly(obj_ptr1,obj_ptr2,poly_ptr1,poly_ptr2,min_index,coincide,pjssi)2190 void DoJoinPoly(obj_ptr1, obj_ptr2, poly_ptr1, poly_ptr2, min_index, coincide,
2191       pjssi)
2192    struct ObjRec *obj_ptr1, *obj_ptr2;
2193    struct PolyRec *poly_ptr1, *poly_ptr2;
2194    int min_index, coincide;
2195    JoinStructSplineInfo *pjssi;
2196    /*
2197     * min_index==0: join point 0   of poly_ptr1 and point 0   of poly_ptr2
2198     * min_index==1: join point 0   of poly_ptr1 and point n-1 of poly_ptr2
2199     * min_index==2: join point n-1 of poly_ptr1 and point 0   of poly_ptr2
2200     * min_index==3: join point n-1 of poly_ptr1 and point n-1 of poly_ptr2
2201     */
2202 {
2203    int i, n, n1=poly_ptr1->n, n2=poly_ptr2->n, num_pts, ltx, lty, rbx, rby;
2204    int min_val=0, max_val=0, inc=0, curved=poly_ptr1->curved;
2205    IntPoint *vlist1=poly_ptr1->vlist, *vlist2=poly_ptr2->vlist;
2206    IntPoint *new_vs=NULL, tmp_p;
2207    char *new_smooth=NULL;
2208 
2209    if (pjssi != NULL) {
2210       if (coincide) {
2211          num_pts = n1+n2-1;
2212       } else {
2213          num_pts = n1+n2+2;
2214       }
2215    } else {
2216       num_pts = n1+n2;
2217       if (coincide) {
2218          num_pts = n1+n2-1;
2219       } else {
2220          num_pts = n1+n2;
2221       }
2222    }
2223    new_vs = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
2224    if (new_vs == NULL) FailAllocMessage();
2225    if (curved == LT_STRUCT_SPLINE) {
2226       IntPoint tmp_p1, tmp_p2;
2227       int fix_v1_of_vlist2=FALSE, fix_vn2_minus_2_of_vlist2=FALSE;
2228 
2229       switch (min_index) {
2230       case 0: min_val=n1-1; max_val=0; inc=(-1); break;
2231       case 1: min_val=n1-1; max_val=0; inc=(-1); break;
2232       case 2: min_val=0; max_val=n1; inc=1; break;
2233       case 3: min_val=0; max_val=n1; inc=1; break;
2234       }
2235       n = 0;
2236       i = min_val;
2237       while (inc > 0 ? i < max_val : i >= max_val) {
2238          if (obj_ptr1->ctm == NULL) {
2239             memcpy(&new_vs[n], &vlist1[i], sizeof(IntPoint));
2240          } else {
2241             TransformObjectV(obj_ptr1, &vlist1[i], &tmp_p);
2242             memcpy(&new_vs[n], &tmp_p, sizeof(IntPoint));
2243          }
2244          n++;
2245          i += inc;
2246       }
2247       if (coincide) {
2248          int has_smooth_1=FALSE, has_smooth_2=FALSE;
2249 
2250          switch (min_index) {
2251          case 0: /* join pt 0 of poly1 and pt 0 of poly2 */
2252             has_smooth_1 = pjssi->sssi1.ipt.later_valid;
2253             has_smooth_2 = pjssi->sssi2.ipt.later_valid;
2254             break;
2255          case 1: /* join pt 0 of poly1 and pt n-1 of poly2 */
2256             has_smooth_1 = pjssi->sssi1.ipt.later_valid;
2257             has_smooth_2 = pjssi->sssi2.ipt.earlier_valid;
2258             break;
2259          case 2: /* join pt n-1 of poly1 and pt 0 of poly2 */
2260             has_smooth_1 = pjssi->sssi1.ipt.earlier_valid;
2261             has_smooth_2 = pjssi->sssi2.ipt.later_valid;
2262             break;
2263          case 3: /* join pt n-1 of poly1 and pt n-1 of poly2 */
2264             has_smooth_1 = pjssi->sssi1.ipt.earlier_valid;
2265             has_smooth_2 = pjssi->sssi2.ipt.earlier_valid;
2266             break;
2267          }
2268          if (has_smooth_1) {
2269             /* first point has a corresponding smooth point */
2270             if (has_smooth_2) {
2271                /* last point has a corresponding smooth point */
2272                switch (min_index) {
2273                case 0: /* join pt 0 of poly1 and pt 0 of poly2 */
2274                case 2: /* join pt n-1 of poly1 and pt 0 of poly2 */
2275                   if (obj_ptr2->ctm == NULL) {
2276                      new_vs[n-2].x = (vlist2[0].x<<1) - vlist2[1].x;
2277                      new_vs[n-2].y = (vlist2[0].y<<1) - vlist2[1].y;
2278                   } else {
2279                      TransformObjectV(obj_ptr2, &vlist2[0], &tmp_p1);
2280                      TransformObjectV(obj_ptr2, &vlist2[1], &tmp_p2);
2281                      new_vs[n-2].x = (tmp_p1.x<<1) - tmp_p2.x;
2282                      new_vs[n-2].y = (tmp_p1.y<<1) - tmp_p2.y;
2283                   }
2284                   break;
2285                case 1: /* join pt 0 of poly1 and pt n-1 of poly2 */
2286                case 3: /* join pt n-1 of poly1 and pt n-1 of poly2 */
2287                   if (obj_ptr2->ctm == NULL) {
2288                      new_vs[n-2].x = (vlist2[n2-1].x<<1) - vlist2[n2-2].x;
2289                      new_vs[n-2].y = (vlist2[n2-1].y<<1) - vlist2[n2-2].y;
2290                   } else {
2291                      TransformObjectV(obj_ptr2, &vlist2[n2-1], &tmp_p1);
2292                      TransformObjectV(obj_ptr2, &vlist2[n2-2], &tmp_p2);
2293                      new_vs[n-2].x = (tmp_p1.x<<1) - tmp_p2.x;
2294                      new_vs[n-2].y = (tmp_p1.y<<1) - tmp_p2.y;
2295                   }
2296                   break;
2297                }
2298             } else {
2299                /* last point does not have a corresponding smooth point */
2300                new_vs[n-2].x = new_vs[n-1].x;
2301                new_vs[n-2].y = new_vs[n-1].y;
2302             }
2303          } else {
2304             /* first point does not have a corresponding smooth point */
2305             if (has_smooth_2) {
2306                /* last point has a corresponding smooth point */
2307                switch (min_index) {
2308                case 0: /* join pt 0 of poly1 and pt 0 of poly2 */
2309                case 2: /* join pt n-1 of poly1 and pt 0 of poly2 */
2310                   /*
2311                    * Cannot really do the following here because it will
2312                    *       mess up undo.  So, delay the fixing till the end.
2313                    *
2314                    * vlist2[1].x = vlist2[0].x;
2315                    * vlist2[1].y = vlist2[0].y;
2316                    */
2317                   fix_v1_of_vlist2 = TRUE;
2318                   break;
2319                case 1: /* join pt 0 of poly1 and pt n-1 of poly2 */
2320                case 3: /* join pt n-1 of poly1 and pt n-1 of poly2 */
2321                   /*
2322                    * Cannot really do the following here because it will
2323                    *       mess up undo.  So, delay the fixing till the end.
2324                    *
2325                    * vlist2[n2-2].x = vlist2[n2-1].x;
2326                    * vlist2[n2-2].y = vlist2[n2-1].y;
2327                    */
2328                   fix_vn2_minus_2_of_vlist2 = TRUE;
2329                   break;
2330                }
2331             } else {
2332                /* last point does not have a corresponding smooth point */
2333             }
2334          }
2335       } else {
2336          switch (min_index) {
2337          case 0: /* join point 0 of poly_ptr1 and point 0 of poly_ptr2 */
2338          case 1: /* join point 0 of poly_ptr1 and point n-1 of poly_ptr2 */
2339             if (pjssi->sssi1.ipt.later_valid) {
2340                /* first point has a corresponding smooth point */
2341                new_vs[n].x = (new_vs[n-1].x<<1) - new_vs[n-2].x;
2342                new_vs[n].y = (new_vs[n-1].y<<1) - new_vs[n-2].y;
2343             } else {
2344                /* first point does not have a corresponding smooth point */
2345                new_vs[n].x = new_vs[n-1].x;
2346                new_vs[n].y = new_vs[n-1].y;
2347             }
2348             n++;
2349             break;
2350          case 2: /* join point n-1 of poly_ptr1 and point 0 of poly_ptr2 */
2351          case 3: /* join point n-1 of poly_ptr1 and point n-1 of poly_ptr2 */
2352             if (pjssi->sssi1.ipt.earlier_valid) {
2353                /* first point has a corresponding smooth point */
2354                new_vs[n].x = (new_vs[n-1].x<<1) - new_vs[n-2].x;
2355                new_vs[n].y = (new_vs[n-1].y<<1) - new_vs[n-2].y;
2356             } else {
2357                /* first point does not have a corresponding smooth point */
2358                new_vs[n].x = new_vs[n-1].x;
2359                new_vs[n].y = new_vs[n-1].y;
2360             }
2361             n++;
2362             break;
2363          }
2364          switch (min_index) {
2365          case 0: /* join point 0 of poly_ptr1 and point 0 of poly_ptr2 */
2366          case 2: /* join point n-1 of poly_ptr1 and point 0 of poly_ptr2 */
2367             if (pjssi->sssi2.ipt.later_valid) {
2368                /* last point has a corresponding smooth point */
2369                if (obj_ptr2->ctm == NULL) {
2370                   new_vs[n].x = (vlist2[0].x<<1) - vlist2[1].x;
2371                   new_vs[n].y = (vlist2[0].y<<1) - vlist2[1].y;
2372                } else {
2373                   TransformObjectV(obj_ptr2, &vlist2[0], &tmp_p1);
2374                   TransformObjectV(obj_ptr2, &vlist2[1], &tmp_p2);
2375                   new_vs[n].x = (tmp_p1.x<<1) - tmp_p2.x;
2376                   new_vs[n].y = (tmp_p1.y<<1) - tmp_p2.y;
2377                }
2378             } else {
2379                /* last point does not have a corresponding smooth point */
2380                if (obj_ptr2->ctm == NULL) {
2381                   new_vs[n].x = vlist2[0].x;
2382                   new_vs[n].y = vlist2[0].y;
2383                } else {
2384                   TransformObjectV(obj_ptr2, &vlist2[0], &tmp_p);
2385                   new_vs[n].x = tmp_p.x;
2386                   new_vs[n].y = tmp_p.y;
2387                }
2388             }
2389             n++;
2390             break;
2391          case 1: /* join point 0 of poly_ptr1 and point n-1 of poly_ptr2 */
2392          case 3: /* join point n-1 of poly_ptr1 and point n-1 of poly_ptr2 */
2393             if (pjssi->sssi2.ipt.earlier_valid) {
2394                /* last point has a corresponding smooth point */
2395                if (obj_ptr2->ctm == NULL) {
2396                   new_vs[n].x = (vlist2[n2-1].x<<1) - vlist2[n2-2].x;
2397                   new_vs[n].y = (vlist2[n2-1].y<<1) - vlist2[n2-2].y;
2398                } else {
2399                   TransformObjectV(obj_ptr2, &vlist2[n2-1], &tmp_p1);
2400                   TransformObjectV(obj_ptr2, &vlist2[n2-2], &tmp_p2);
2401                   new_vs[n].x = (tmp_p1.x<<1) - tmp_p2.x;
2402                   new_vs[n].y = (tmp_p1.y<<1) - tmp_p2.y;
2403                }
2404             } else {
2405                /* last point does not have a corresponding smooth point */
2406                if (obj_ptr2->ctm == NULL) {
2407                   new_vs[n].x = vlist2[n2-1].x;
2408                   new_vs[n].y = vlist2[n2-1].y;
2409                } else {
2410                   TransformObjectV(obj_ptr2, &vlist2[n2-1], &tmp_p);
2411                   new_vs[n].x = tmp_p.x;
2412                   new_vs[n].y = tmp_p.y;
2413                }
2414             }
2415             n++;
2416             break;
2417          }
2418       }
2419       if (coincide) {
2420          switch (min_index) {
2421          case 0: min_val=1; max_val=n2; inc=1; break;
2422          case 1: min_val=n2-2; max_val=0; inc=(-1); break;
2423          case 2: min_val=1; max_val=n2; inc=1; break;
2424          case 3: min_val=n2-2; max_val=0; inc=(-1); break;
2425          }
2426       } else {
2427          switch (min_index) {
2428          case 0: min_val=0; max_val=n2; inc=1; break;
2429          case 1: min_val=n2-1; max_val=0; inc=(-1); break;
2430          case 2: min_val=0; max_val=n2; inc=1; break;
2431          case 3: min_val=n2-1; max_val=0; inc=(-1); break;
2432          }
2433       }
2434       i = min_val;
2435       while (inc > 0 ? i < max_val : i >= max_val) {
2436          if (obj_ptr2->ctm == NULL) {
2437             memcpy(&new_vs[n], &vlist2[i], sizeof(IntPoint));
2438          } else {
2439             TransformObjectV(obj_ptr2, &vlist2[i], &tmp_p);
2440             memcpy(&new_vs[n], &tmp_p, sizeof(IntPoint));
2441          }
2442          n++;
2443          i += inc;
2444       }
2445       if (fix_v1_of_vlist2 || fix_vn2_minus_2_of_vlist2) {
2446          new_vs[n1].x = new_vs[n1-1].x;
2447          new_vs[n1].y = new_vs[n1-1].y;
2448       }
2449    } else {
2450       if (curved != LT_INTSPLINE) {
2451          new_smooth = (char*)malloc((num_pts+1)*sizeof(char));
2452          if (new_smooth == NULL) FailAllocMessage();
2453       }
2454       switch (min_index) {
2455       case 0: min_val=n1-1; max_val=0; inc=(-1); break;
2456       case 1: min_val=n1-1; max_val=0; inc=(-1); break;
2457       case 2: min_val=0; max_val=n1; inc=1; break;
2458       case 3: min_val=0; max_val=n1; inc=1; break;
2459       }
2460       n = 0;
2461       i = min_val;
2462       while (inc > 0 ? i < max_val : i >= max_val) {
2463          if (obj_ptr1->ctm == NULL) {
2464             memcpy(&new_vs[n], &vlist1[i], sizeof(IntPoint));
2465          } else {
2466             TransformObjectV(obj_ptr1, &vlist1[i], &tmp_p);
2467             memcpy(&new_vs[n], &tmp_p, sizeof(IntPoint));
2468          }
2469          if (new_smooth != NULL) {
2470             new_smooth[n] = poly_ptr1->smooth[i];
2471          }
2472          n++;
2473          i += inc;
2474       }
2475       if (coincide) {
2476          switch (min_index) {
2477          case 0: min_val=1; max_val=n2; inc=1; break;
2478          case 1: min_val=n2-2; max_val=0; inc=(-1); break;
2479          case 2: min_val=1; max_val=n2; inc=1; break;
2480          case 3: min_val=n2-2; max_val=0; inc=(-1); break;
2481          }
2482       } else {
2483          switch (min_index) {
2484          case 0: min_val=0; max_val=n2; inc=1; break;
2485          case 1: min_val=n2-1; max_val=0; inc=(-1); break;
2486          case 2: min_val=0; max_val=n2; inc=1; break;
2487          case 3: min_val=n2-1; max_val=0; inc=(-1); break;
2488          }
2489       }
2490       i = min_val;
2491       while (inc > 0 ? i < max_val : i >= max_val) {
2492          if (obj_ptr2->ctm == NULL) {
2493             memcpy(&new_vs[n], &vlist2[i], sizeof(IntPoint));
2494          } else {
2495             TransformObjectV(obj_ptr2, &vlist2[i], &tmp_p);
2496             memcpy(&new_vs[n], &tmp_p, sizeof(IntPoint));
2497          }
2498          if (new_smooth != NULL) {
2499             new_smooth[n] = poly_ptr2->smooth[i];
2500          }
2501          n++;
2502          i += inc;
2503       }
2504    }
2505    ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
2506    HighLightReverse();
2507    StartCompositeCmd();
2508    FinishJoinPoly(obj_ptr1, obj_ptr2, poly_ptr1, new_vs, new_smooth, num_pts);
2509    EndCompositeCmd();
2510    UpdSelBBox();
2511    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2512          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
2513          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2514          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2515    SetFileModified(TRUE);
2516    justDupped = FALSE;
2517    HighLightForward();
2518 }
2519 
2520 static
FinishCloseOnePoly(obj_ptr,poly_ptr,vs,smooth,num_pts)2521 void FinishCloseOnePoly(obj_ptr, poly_ptr, vs, smooth, num_pts)
2522    struct ObjRec *obj_ptr;
2523    struct PolyRec *poly_ptr;
2524    IntPoint *vs;
2525    char *smooth;
2526    int num_pts;
2527 {
2528    struct PolygonRec *polygon_ptr=(struct PolygonRec *)malloc(
2529          sizeof(struct PolygonRec));
2530 
2531    if (polygon_ptr == NULL) FailAllocMessage();
2532 
2533    memset(polygon_ptr, 0, sizeof(struct PolygonRec));
2534    polygon_ptr->n = num_pts;
2535    polygon_ptr->vlist = vs;
2536    polygon_ptr->smooth = smooth;
2537    polygon_ptr->sn = 0;
2538    polygon_ptr->svlist = NULL;
2539    polygon_ptr->intn = 0;
2540    polygon_ptr->intvlist = NULL;
2541    polygon_ptr->fill = poly_ptr->fill;
2542    polygon_ptr->width = poly_ptr->width;
2543    UtilStrCpyN(polygon_ptr->width_spec, sizeof(polygon_ptr->width_spec),
2544          poly_ptr->width_spec);
2545    polygon_ptr->pen = poly_ptr->pen;
2546    polygon_ptr->curved = poly_ptr->curved;
2547    polygon_ptr->dash = poly_ptr->dash;
2548    polygon_ptr->rotated_n = 0;
2549    polygon_ptr->rotated_vlist = NULL;
2550 
2551    PrepareToReplaceAnObj(obj_ptr);
2552 
2553    if (poly_ptr->vlist != NULL) free(poly_ptr->vlist);
2554    if (poly_ptr->svlist != NULL) free(poly_ptr->svlist);
2555    if (poly_ptr->asvlist != NULL) free(poly_ptr->asvlist);
2556    if (poly_ptr->smooth != NULL) free(poly_ptr->smooth);
2557    if (poly_ptr->intvlist != NULL) free(poly_ptr->intvlist);
2558    if (poly_ptr->rotated_vlist != NULL) free(poly_ptr->rotated_vlist);
2559    if (poly_ptr->rotated_asvlist != NULL) free(poly_ptr->rotated_asvlist);
2560    free(poly_ptr);
2561 
2562    obj_ptr->type = OBJ_POLYGON;
2563    obj_ptr->detail.g = polygon_ptr;
2564 
2565    AdjObjSplineVs(obj_ptr);
2566    if (polygon_ptr->curved != LT_INTSPLINE) {
2567       UpdPolyBBox(obj_ptr, polygon_ptr->n, polygon_ptr->vlist);
2568    } else {
2569       UpdPolyBBox(obj_ptr, polygon_ptr->intn, polygon_ptr->intvlist);
2570    }
2571    AdjObjBBox(obj_ptr);
2572    RecordReplaceAnObj(obj_ptr);
2573 }
2574 
2575 static
CloseOnePoly(obj_ptr)2576 void CloseOnePoly(obj_ptr)
2577    struct ObjRec *obj_ptr;
2578 {
2579    struct PolyRec *poly_ptr=obj_ptr->detail.p;
2580    int i, n=0, num_pts=0, ltx, lty, rbx, rby, coincide=FALSE;
2581    int curved=poly_ptr->curved;
2582    IntPoint *new_vs=NULL, *vs=NULL;
2583    char *new_smooth=NULL, *smooth=NULL;
2584    StretchStructuredSplineInfo sssi_first, sssi_last;
2585 
2586    memset(&sssi_first, 0, sizeof(StretchStructuredSplineInfo));
2587    memset(&sssi_last, 0, sizeof(StretchStructuredSplineInfo));
2588 
2589    if (curved == LT_STRUCT_SPLINE) {
2590       vs = poly_ptr->ssvlist;
2591       n = poly_ptr->ssn;
2592       smooth = poly_ptr->ssmooth;
2593       if (n < 3) {
2594          MsgBox(TgLoadString(STID_TOO_FEW_VER_TO_CLOSE_POLY), TOOL_NAME,
2595                INFO_MB);
2596          return;
2597       }
2598    } else {
2599       vs = poly_ptr->vlist;
2600       n = poly_ptr->n;
2601       smooth = poly_ptr->smooth;
2602       if (n <= 2) {
2603          MsgBox(TgLoadString(STID_TOO_FEW_VER_TO_CLOSE_POLY), TOOL_NAME,
2604                INFO_MB);
2605          return;
2606       }
2607    }
2608    if (vs[0].x == vs[n-1].x && vs[0].y == vs[n-1].y) {
2609       coincide = TRUE;
2610       if (curved == LT_STRUCT_SPLINE) {
2611          if (n <= 4) {
2612             MsgBox(TgLoadString(STID_TOO_FEW_VER_TO_CLOSE_POLY), TOOL_NAME,
2613                   INFO_MB);
2614             return;
2615          }
2616          SetIPTInfoForStretchPoly(0, poly_ptr->n, poly_ptr->vlist, &sssi_first);
2617          SetIPTInfoForStretchPoly(n-1, poly_ptr->n, poly_ptr->vlist,
2618                &sssi_last);
2619          num_pts = poly_ptr->n;
2620       } else {
2621          num_pts = n;
2622       }
2623    } else {
2624       if (curved == LT_STRUCT_SPLINE) {
2625          SetIPTInfoForStretchPoly(0, poly_ptr->n, poly_ptr->vlist, &sssi_first);
2626          SetIPTInfoForStretchPoly(n-1, poly_ptr->n, poly_ptr->vlist,
2627                &sssi_last);
2628          num_pts = poly_ptr->n+3;
2629       } else {
2630          num_pts = n+1;
2631       }
2632    }
2633    new_vs = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
2634    if (new_vs == NULL) FailAllocMessage();
2635    memset(new_vs, 0,  (num_pts+1)*sizeof(IntPoint));
2636 
2637    if (curved == LT_STRUCT_SPLINE) {
2638       for (i=0; i < poly_ptr->n; i++) {
2639          memcpy(&new_vs[i], &poly_ptr->vlist[i], sizeof(IntPoint));
2640       }
2641       if (coincide) {
2642          if (sssi_first.ipt.later_valid) {
2643             /* first point has a corresponding smooth point */
2644             if (sssi_last.ipt.earlier_valid) {
2645                /* last point has a corresponding smooth point */
2646                /*
2647                 * in this case, move the last smooth point
2648                 */
2649                new_vs[poly_ptr->n-2].x = (new_vs[0].x<<1) - new_vs[1].x;
2650                new_vs[poly_ptr->n-2].y = (new_vs[0].y<<1) - new_vs[1].y;
2651             } else {
2652                /* last point does not have a corresponding smooth point */
2653                /*
2654                 * in this case, remove the first smooth point
2655                 */
2656                new_vs[1].x = new_vs[0].x;
2657                new_vs[1].y = new_vs[0].y;
2658             }
2659          } else {
2660             /* first point does not have a corresponding smooth point */
2661             if (sssi_last.ipt.earlier_valid) {
2662                /* last point has a corresponding smooth point */
2663                /*
2664                 * in this case, remove the last smooth point
2665                 */
2666                new_vs[poly_ptr->n-2].x = new_vs[poly_ptr->n-1].x;
2667                new_vs[poly_ptr->n-2].y = new_vs[poly_ptr->n-1].y;
2668             } else {
2669                /* last point does not have a corresponding smooth point */
2670                /*
2671                 * in this case, there is nothing to do
2672                 */
2673             }
2674          }
2675       } else {
2676          new_vs[poly_ptr->n+2].x = new_vs[0].x;
2677          new_vs[poly_ptr->n+2].y = new_vs[0].y;
2678 
2679          if (sssi_first.ipt.later_valid) {
2680             /* first point has a corresponding smooth point */
2681             if (sssi_last.ipt.earlier_valid) {
2682                /* last point has a corresponding smooth point */
2683                /*
2684                 * in this case, create 2 new smooth points
2685                 */
2686                new_vs[poly_ptr->n+1].x = (new_vs[0].x<<1) - new_vs[1].x;
2687                new_vs[poly_ptr->n+1].y = (new_vs[0].y<<1) - new_vs[1].y;
2688                new_vs[poly_ptr->n].x = (new_vs[poly_ptr->n-1].x<<1) -
2689                      new_vs[poly_ptr->n-2].x;
2690                new_vs[poly_ptr->n].y = (new_vs[poly_ptr->n-1].y<<1) -
2691                      new_vs[poly_ptr->n-2].y;
2692             } else {
2693                /* last point does not have a corresponding smooth point */
2694                /*
2695                 * in this case, create one new smooth point near the 1st point
2696                 */
2697                new_vs[poly_ptr->n+1].x = (new_vs[0].x<<1) - new_vs[1].x;
2698                new_vs[poly_ptr->n+1].y = (new_vs[0].y<<1) - new_vs[1].y;
2699                new_vs[poly_ptr->n].x = new_vs[poly_ptr->n-1].x;
2700                new_vs[poly_ptr->n].y = new_vs[poly_ptr->n-1].y;
2701             }
2702          } else {
2703             /* first point does not have a corresponding smooth point */
2704             if (sssi_last.ipt.earlier_valid) {
2705                /* last point has a corresponding smooth point */
2706                /*
2707                 * in this case, create one new smooth point near the last point
2708                 */
2709                new_vs[poly_ptr->n+1].x = new_vs[0].x;
2710                new_vs[poly_ptr->n+1].y = new_vs[0].y;
2711                new_vs[poly_ptr->n].x = (new_vs[poly_ptr->n-1].x<<1) -
2712                      new_vs[poly_ptr->n-2].x;
2713                new_vs[poly_ptr->n].y = (new_vs[poly_ptr->n-1].y<<1) -
2714                      new_vs[poly_ptr->n-2].y;
2715             } else {
2716                /* last point does not have a corresponding smooth point */
2717                /*
2718                 * in this case, create 2 hinge points
2719                 */
2720                new_vs[poly_ptr->n+1].x = new_vs[0].x;
2721                new_vs[poly_ptr->n+1].y = new_vs[0].y;
2722                new_vs[poly_ptr->n].x = new_vs[poly_ptr->n-1].x;
2723                new_vs[poly_ptr->n].y = new_vs[poly_ptr->n-1].y;
2724             }
2725          }
2726       }
2727    } else {
2728       for (i=0; i < n; i++) memcpy(&new_vs[i], &vs[i], sizeof(IntPoint));
2729       memcpy(&new_vs[n], &vs[0], sizeof(IntPoint));
2730       if (poly_ptr->curved != LT_INTSPLINE) {
2731          new_smooth = (char*)malloc((num_pts+1)*sizeof(char));
2732          if (new_smooth == NULL) FailAllocMessage();
2733          for (i=0; i < n; i++) new_smooth[i] = smooth[i];
2734          new_smooth[0] = new_smooth[n] = FALSE;
2735       }
2736    }
2737    ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
2738    HighLightReverse();
2739    FinishCloseOnePoly(obj_ptr, poly_ptr, new_vs, new_smooth, num_pts);
2740    if (curChoice == VERTEXMODE) {
2741       if (topVSel == botVSel) {
2742          int x0=0, y0=0, first_index=(-1), last_index=(-1);
2743 
2744          for (i=0; i < topVSel->n; i++) {
2745             if (topVSel->v_index[i] == 0) {
2746                x0 = topVSel->x[i];
2747                y0 = topVSel->y[i];
2748                first_index = i;
2749             } else if (topVSel->v_index[i] ==
2750                   (coincide ? num_pts-1 : num_pts-2)) {
2751                if (!coincide) {
2752                   topVSel->v_index[i]++;
2753                }
2754                last_index = i;
2755             }
2756          }
2757          if (last_index != (-1) && first_index != (-1)) {
2758             topVSel->n = 2;
2759             topVSel->x[first_index] = topVSel->x[last_index] = x0;
2760             topVSel->y[first_index] = topVSel->y[last_index] = y0;
2761          } else {
2762             fprintf(stderr, "%s\n",
2763                   TgLoadString(STID_HUH_WHERE_ARE_THE_VERTICES));
2764          }
2765       } else {
2766          fprintf(stderr, "%s\n", TgLoadString(STID_HUH_TOPVSEL_NE_BOTVSEL));
2767       }
2768    }
2769    UpdSelBBox();
2770    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2771          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
2772          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2773          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2774    SetFileModified(TRUE);
2775    justDupped = FALSE;
2776    HighLightForward();
2777 }
2778 
2779 static
JoinPolyCompatCheck(poly_ptr1,poly_ptr2)2780 int JoinPolyCompatCheck(poly_ptr1, poly_ptr2)
2781    struct PolyRec *poly_ptr1, *poly_ptr2;
2782 {
2783    int rc=TRUE;
2784 
2785    switch (poly_ptr1->curved) {
2786    case LT_STRAIGHT:
2787    case LT_SPLINE:
2788       if (poly_ptr2->curved == LT_STRAIGHT ||
2789             poly_ptr2->curved == LT_SPLINE) {
2790          /* compatible */
2791       } else {
2792          rc = FALSE;
2793       }
2794       break;
2795    case LT_INTSPLINE:
2796       if (poly_ptr2->curved == LT_INTSPLINE) {
2797          /* compatible */
2798       } else {
2799          rc = FALSE;
2800       }
2801       break;
2802    case LT_STRUCT_SPLINE:
2803       if (poly_ptr2->curved == LT_STRUCT_SPLINE) {
2804          /* compatible */
2805       } else {
2806          rc = FALSE;
2807       }
2808       break;
2809    }
2810    if (!rc) {
2811       MsgBox(TgLoadString(STID_SEL_2_COMPAT_END_PTS_TO_JOIN), TOOL_NAME,
2812             INFO_MB);
2813       return FALSE;
2814    }
2815    return TRUE;
2816 }
2817 
JoinPoly()2818 void JoinPoly()
2819 {
2820    struct ObjRec *obj_ptr1=NULL, *obj_ptr2=NULL;
2821    struct PolyRec *poly_ptr1=NULL, *poly_ptr2=NULL;
2822    long dx=0L, dy=0L, min_lval=0L;
2823    int i=0, min_index=(-1);
2824 
2825    if (curChoice != VERTEXMODE && curChoice != NOTHING) {
2826       MsgBox(TgLoadString(STID_CMD_ONLY_AVAIL_IN_VERSEL_MODE), TOOL_NAME,
2827             INFO_MB);
2828       return;
2829    }
2830    if (curChoice == VERTEXMODE) {
2831       if (CountSelectedVertices() != 2) {
2832          MsgBox(TgLoadString(STID_SEL_2_ENDPOINT_VER_TO_JOIN), TOOL_NAME,
2833                INFO_MB);
2834          return;
2835       }
2836       obj_ptr1 = topVSel->obj;
2837       obj_ptr2 = botVSel->obj;
2838       if (obj_ptr1->type != OBJ_POLY || obj_ptr2->type != OBJ_POLY) {
2839          MsgBox(TgLoadString(STID_SEL_VER_FROM_POLY_OPEN_ONLY), TOOL_NAME,
2840                INFO_MB);
2841          return;
2842       }
2843       poly_ptr1 = obj_ptr1->detail.p;
2844       for (i=0; i < topVSel->n; i++) {
2845          int index=topVSel->v_index[i];
2846 
2847          if (index != 0 && index != poly_ptr1->n-1) {
2848             MsgBox(TgLoadString(STID_SEL_2_ENDPOINT_VER_TO_JOIN), TOOL_NAME,
2849                   INFO_MB);
2850             return;
2851          }
2852       }
2853       if (obj_ptr1 == obj_ptr2) {
2854          CloseOnePoly(obj_ptr1);
2855          return;
2856       }
2857       poly_ptr2 = obj_ptr2->detail.p;
2858       for (i=0; i < botVSel->n; i++) {
2859          int index=botVSel->v_index[i];
2860 
2861          if (index != 0 && index != poly_ptr2->n-1) {
2862             MsgBox(TgLoadString(STID_SEL_2_ENDPOINT_VER_TO_JOIN), TOOL_NAME,
2863                   INFO_MB);
2864             return;
2865          }
2866       }
2867       if (!JoinPolyCompatCheck(poly_ptr1, poly_ptr2)) {
2868          return;
2869       }
2870       if (topVSel->v_index[0] == 0) {
2871          if (botVSel->v_index[0] == 0) {
2872             min_index = 0;
2873          } else {
2874             min_index = 1;
2875          }
2876       } else {
2877          if (botVSel->v_index[0] == 0) {
2878             min_index = 2;
2879          } else {
2880             min_index = 3;
2881          }
2882       }
2883       dx = topVSel->x[0] - botVSel->x[0];
2884       dy = topVSel->y[0] - botVSel->y[0];
2885       min_lval = (dx*dx)+(dy*dy);
2886    } else {
2887       IntPoint p[4], tmp_p;
2888       long d[4];
2889 
2890       if (numObjSelected == 1 && topSel->obj->type == OBJ_POLY) {
2891          CloseOnePoly(topSel->obj);
2892          return;
2893       } else if (numObjSelected != 2 || topSel == NULL ||
2894             topSel->obj->type != OBJ_POLY || botSel->obj->type != OBJ_POLY) {
2895          MsgBox(TgLoadString(STID_SEL_2_POLYLINES_OPEN_SPLINES), TOOL_NAME,
2896                INFO_MB);
2897          return;
2898       }
2899       obj_ptr1 = topSel->obj;
2900       obj_ptr2 = botSel->obj;
2901       poly_ptr1 = obj_ptr1->detail.p;
2902       poly_ptr2 = obj_ptr2->detail.p;
2903 
2904       if (!JoinPolyCompatCheck(poly_ptr1, poly_ptr2)) {
2905          return;
2906       }
2907       memcpy(&p[0], &poly_ptr1->vlist[0], sizeof(IntPoint));
2908       memcpy(&p[1], &poly_ptr1->vlist[poly_ptr1->n-1], sizeof(IntPoint));
2909       memcpy(&p[2], &poly_ptr2->vlist[0], sizeof(IntPoint));
2910       memcpy(&p[3], &poly_ptr2->vlist[poly_ptr2->n-1], sizeof(IntPoint));
2911       if (obj_ptr1->ctm != NULL) {
2912          TransformObjectV(obj_ptr1, &p[0], &tmp_p);
2913          memcpy(&p[0], &tmp_p, sizeof(IntPoint));
2914          TransformObjectV(obj_ptr1, &p[1], &tmp_p);
2915          memcpy(&p[1], &tmp_p, sizeof(IntPoint));
2916       }
2917       if (obj_ptr2->ctm != NULL) {
2918          TransformObjectV(obj_ptr2, &p[2], &tmp_p);
2919          memcpy(&p[2], &tmp_p, sizeof(IntPoint));
2920          TransformObjectV(obj_ptr2, &p[3], &tmp_p);
2921          memcpy(&p[3], &tmp_p, sizeof(IntPoint));
2922       }
2923       dx=(long)(p[0].x-p[2].x); dy=(long)(p[0].y-p[2].y); d[0]=dx*dx+dy*dy;
2924       dx=(long)(p[0].x-p[3].x); dy=(long)(p[0].y-p[3].y); d[1]=dx*dx+dy*dy;
2925       dx=(long)(p[1].x-p[2].x); dy=(long)(p[1].y-p[2].y); d[2]=dx*dx+dy*dy;
2926       dx=(long)(p[1].x-p[3].x); dy=(long)(p[1].y-p[3].y); d[3]=dx*dx+dy*dy;
2927       min_index = 0;
2928       min_lval = d[0];
2929       for (i=1; i < 4; i++) {
2930          if (d[i] < min_lval) {
2931             min_index = i;
2932             min_lval = d[i];
2933          }
2934       }
2935    }
2936    if (poly_ptr1->curved == LT_STRUCT_SPLINE &&
2937          poly_ptr2->curved == LT_STRUCT_SPLINE) {
2938       JoinStructSplineInfo jssi;
2939 
2940       memset(&jssi, 0, sizeof(JoinStructSplineInfo));
2941       switch (min_index) {
2942       case 0:
2943          SetIPTInfoForStretchPoly(0, poly_ptr1->n, poly_ptr1->vlist,
2944                &jssi.sssi1);
2945          SetIPTInfoForStretchPoly(0, poly_ptr2->n, poly_ptr2->vlist,
2946                &jssi.sssi2);
2947          break;
2948       case 1:
2949          SetIPTInfoForStretchPoly(0, poly_ptr1->n, poly_ptr1->vlist,
2950                &jssi.sssi1);
2951          SetIPTInfoForStretchPoly(poly_ptr2->ssn-1, poly_ptr2->n,
2952                poly_ptr2->vlist, &jssi.sssi2);
2953          break;
2954       case 2:
2955          SetIPTInfoForStretchPoly(poly_ptr1->ssn-1, poly_ptr1->n,
2956                poly_ptr1->vlist, &jssi.sssi1);
2957          SetIPTInfoForStretchPoly(0, poly_ptr2->n, poly_ptr2->vlist,
2958                &jssi.sssi2);
2959          break;
2960       case 3:
2961          SetIPTInfoForStretchPoly(poly_ptr1->ssn-1, poly_ptr1->n,
2962                poly_ptr1->vlist, &jssi.sssi1);
2963          SetIPTInfoForStretchPoly(poly_ptr2->ssn-1, poly_ptr2->n,
2964                poly_ptr2->vlist, &jssi.sssi2);
2965          break;
2966       }
2967       DoJoinPoly(obj_ptr1, obj_ptr2, poly_ptr1, poly_ptr2, min_index,
2968             (min_lval==0L), &jssi);
2969    } else {
2970       DoJoinPoly(obj_ptr1, obj_ptr2, poly_ptr1, poly_ptr2, min_index,
2971             (min_lval==0L), NULL);
2972    }
2973 }
2974 
2975 /* --------------------- CutPoly() --------------------- */
2976 
2977 static
FinishCutPoly(obj_ptr1,poly_ptr1,vs1,smooth1,vs2,smooth2,num_pts1,num_pts2)2978 void FinishCutPoly(obj_ptr1, poly_ptr1, vs1, smooth1, vs2, smooth2,
2979       num_pts1, num_pts2)
2980    struct ObjRec *obj_ptr1;
2981    struct PolyRec *poly_ptr1;
2982    IntPoint *vs1, *vs2;
2983    char *smooth1, *smooth2;
2984    int num_pts1, num_pts2;
2985 {
2986    struct ObjRec *obj_ptr2;
2987    struct PolyRec *poly_ptr2;
2988    int x0, y0;
2989 
2990    x0 = topVSel->x[0];
2991    y0 = topVSel->y[0];
2992 
2993    RemoveAllSel();
2994    PrepareToReplaceAnObj(obj_ptr1);
2995 
2996    obj_ptr2 = DupObj(obj_ptr1);
2997    poly_ptr2 = obj_ptr2->detail.p;
2998    DelAllAttrs(obj_ptr2->fattr);
2999    obj_ptr2->fattr = obj_ptr2->lattr = NULL;
3000 
3001    if (poly_ptr1->vlist != NULL) free(poly_ptr1->vlist);
3002    if (poly_ptr1->svlist != NULL) free(poly_ptr1->svlist);
3003    if (poly_ptr1->asvlist != NULL) free(poly_ptr1->asvlist);
3004    if (poly_ptr1->smooth != NULL) free(poly_ptr1->smooth);
3005    if (poly_ptr1->intvlist != NULL) free(poly_ptr1->intvlist);
3006    if (poly_ptr1->rotated_vlist != NULL) free(poly_ptr1->rotated_vlist);
3007    if (poly_ptr1->rotated_asvlist != NULL) free(poly_ptr1->rotated_asvlist);
3008    poly_ptr1->smooth = smooth1;
3009    poly_ptr1->vlist = poly_ptr1->intvlist = NULL;
3010    poly_ptr1->n = poly_ptr1->intn = 0;
3011    poly_ptr1->svlist = poly_ptr1->asvlist = poly_ptr1->rotated_vlist =
3012          poly_ptr1->rotated_asvlist = NULL;
3013    poly_ptr1->sn = poly_ptr1->asn = poly_ptr1->rotated_n =
3014          poly_ptr1->rotated_asn = 0;
3015    if (obj_ptr1->ctm != NULL) free(obj_ptr1->ctm);
3016    obj_ptr1->ctm = NULL;
3017 
3018    poly_ptr1->vlist = vs1;
3019    poly_ptr1->n = num_pts1;
3020 
3021    if (poly_ptr2->vlist != NULL) free(poly_ptr2->vlist);
3022    if (poly_ptr2->svlist != NULL) free(poly_ptr2->svlist);
3023    if (poly_ptr2->asvlist != NULL) free(poly_ptr2->asvlist);
3024    if (poly_ptr2->smooth != NULL) free(poly_ptr2->smooth);
3025    if (poly_ptr2->intvlist != NULL) free(poly_ptr2->intvlist);
3026    if (poly_ptr2->rotated_vlist != NULL) free(poly_ptr2->rotated_vlist);
3027    if (poly_ptr2->rotated_asvlist != NULL) free(poly_ptr2->rotated_asvlist);
3028    poly_ptr2->smooth = smooth2;
3029    poly_ptr2->vlist = poly_ptr2->intvlist = NULL;
3030    poly_ptr2->n = poly_ptr2->intn = 0;
3031    poly_ptr2->svlist = poly_ptr2->asvlist = poly_ptr2->rotated_vlist =
3032          poly_ptr2->rotated_asvlist = NULL;
3033    poly_ptr2->sn = poly_ptr2->asn = poly_ptr2->rotated_n =
3034          poly_ptr2->rotated_asn = 0;
3035    if (obj_ptr2->ctm != NULL) free(obj_ptr2->ctm);
3036    obj_ptr2->ctm = NULL;
3037 
3038    poly_ptr2->vlist = vs2;
3039    poly_ptr2->n = num_pts2;
3040 
3041    AdjObjSplineVs(obj_ptr1);
3042    if (poly_ptr1->curved != LT_INTSPLINE) {
3043       UpdPolyBBox(obj_ptr1, poly_ptr1->n, poly_ptr1->vlist);
3044    } else {
3045       UpdPolyBBox(obj_ptr1, poly_ptr1->intn, poly_ptr1->intvlist);
3046    }
3047    AdjObjBBox(obj_ptr1);
3048 
3049    AdjObjSplineVs(obj_ptr2);
3050    if (poly_ptr2->curved != LT_INTSPLINE) {
3051       UpdPolyBBox(obj_ptr2, poly_ptr2->n, poly_ptr2->vlist);
3052    } else {
3053       UpdPolyBBox(obj_ptr2, poly_ptr2->intn, poly_ptr2->intvlist);
3054    }
3055    AdjObjBBox(obj_ptr2);
3056    AddObj(obj_ptr1->prev, obj_ptr1, obj_ptr2);
3057 
3058    topSel = (struct SelRec *)malloc(sizeof(struct SelRec));
3059    botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
3060    if (topSel==NULL || botSel==NULL) FailAllocMessage();
3061    topSel->obj = obj_ptr2;
3062    botSel->obj = obj_ptr1;
3063    topSel->prev = botSel->next = NULL;
3064    topSel->next = botSel;
3065    botSel->prev = topSel;
3066 
3067    RecordCmd(CMD_ONE_TO_MANY, NULL, topSel, botSel, 2);
3068 
3069    topVSel = botVSel = (struct VSelRec *)malloc(sizeof(struct VSelRec));
3070    if (topVSel==NULL) FailAllocMessage();
3071    memset(topVSel, 0, sizeof(struct VSelRec));
3072    topVSel->obj = obj_ptr2;
3073    topVSel->max_v = 10;
3074    topVSel->v_index = (int*)malloc(10*sizeof(int));
3075    topVSel->x = (int*)malloc(10*sizeof(int));
3076    topVSel->y = (int*)malloc(10*sizeof(int));
3077    if (topVSel->v_index==NULL || topVSel->x==NULL || topVSel->y==NULL) {
3078       FailAllocMessage();
3079    }
3080    topVSel->v_index[0] = 0;
3081    topVSel->x[0] = x0;
3082    topVSel->y[0] = y0;
3083    topVSel->n = 1;
3084    topVSel->next = topVSel->prev = NULL;
3085 }
3086 
3087 static
DoCutPoly(obj_ptr,index,poly_ptr)3088 void DoCutPoly(obj_ptr, index, poly_ptr)
3089    struct ObjRec *obj_ptr;
3090    int index;
3091    struct PolyRec *poly_ptr;
3092 {
3093    int i=0, n=poly_ptr->n, n1=0, n2=0, ltx, lty, rbx, rby;
3094    int curved=poly_ptr->curved;
3095    IntPoint *vs1=NULL, *vs2=NULL;
3096    char *smooth1=NULL, *smooth2=NULL;
3097 
3098    if (curved == LT_STRUCT_SPLINE) {
3099       StretchStructuredSplineInfo sssi;
3100 
3101       memset(&sssi, 0, sizeof(StretchStructuredSplineInfo));
3102       if (index == poly_ptr->ssn-1) {
3103          return;
3104       }
3105       SetIPTInfoForStretchPoly(index, poly_ptr->n, poly_ptr->vlist, &sssi);
3106       if (!sssi.hinge) {
3107          MsgBox(TgLoadString(STID_CANNOT_CUT_AT_SMOOTH_PT), TOOL_NAME, INFO_MB);
3108          return;
3109       }
3110       n1 = sssi.orig_hinge_index + 1;
3111       n2 = n - sssi.orig_hinge_index;
3112       vs1 = (IntPoint*)malloc((n1+1)*sizeof(IntPoint));
3113       vs2 = (IntPoint*)malloc((n2+1)*sizeof(IntPoint));
3114       if (vs1==NULL || vs2==NULL) FailAllocMessage();
3115 
3116       for (i=0; i <= sssi.orig_hinge_index; i++) {
3117          if (obj_ptr->ctm == NULL) {
3118             memcpy(&vs1[i], &poly_ptr->vlist[i], sizeof(IntPoint));
3119          } else {
3120             IntPoint tmp_p;
3121 
3122             TransformObjectV(obj_ptr, &poly_ptr->vlist[i], &tmp_p);
3123             memcpy(&vs1[i], &tmp_p, sizeof(IntPoint));
3124          }
3125       }
3126       for (i=sssi.orig_hinge_index; i < n; i++) {
3127          if (obj_ptr->ctm == NULL) {
3128             memcpy(&vs2[i-sssi.orig_hinge_index], &poly_ptr->vlist[i],
3129                   sizeof(IntPoint));
3130          } else {
3131             IntPoint tmp_p;
3132 
3133             TransformObjectV(obj_ptr, &poly_ptr->vlist[i], &tmp_p);
3134             memcpy(&vs2[i-sssi.orig_hinge_index], &tmp_p, sizeof(IntPoint));
3135          }
3136       }
3137    } else {
3138       n1 = index+1;
3139       n2 = n-index;
3140       vs1 = (IntPoint*)malloc((n1+1)*sizeof(IntPoint));
3141       vs2 = (IntPoint*)malloc((n2+1)*sizeof(IntPoint));
3142       if (vs1==NULL || vs2==NULL) FailAllocMessage();
3143       if (poly_ptr->curved != LT_INTSPLINE) {
3144          smooth1 = (char*)malloc((n1+1)*sizeof(char));
3145          smooth2 = (char*)malloc((n2+1)*sizeof(char));
3146          if (smooth1==NULL || smooth2==NULL) FailAllocMessage();
3147       }
3148       for (i=0; i <= index; i++) {
3149          if (obj_ptr->ctm == NULL) {
3150             memcpy(&vs1[i], &poly_ptr->vlist[i], sizeof(IntPoint));
3151          } else {
3152             IntPoint tmp_p;
3153 
3154             TransformObjectV(obj_ptr, &poly_ptr->vlist[i], &tmp_p);
3155             memcpy(&vs1[i], &tmp_p, sizeof(IntPoint));
3156          }
3157          if (smooth1 != NULL) {
3158             smooth1[i] = poly_ptr->smooth[i];
3159          }
3160       }
3161       if (smooth1 != NULL) smooth1[0] = smooth1[index] = FALSE;
3162 
3163       for (i=index; i < n; i++) {
3164          if (obj_ptr->ctm == NULL) {
3165             memcpy(&vs2[i-index], &poly_ptr->vlist[i], sizeof(IntPoint));
3166          } else {
3167             IntPoint tmp_p;
3168 
3169             TransformObjectV(obj_ptr, &poly_ptr->vlist[i], &tmp_p);
3170             memcpy(&vs2[i-index], &tmp_p, sizeof(IntPoint));
3171          }
3172          if (smooth2 != NULL) {
3173             smooth2[i-index] = poly_ptr->smooth[i];
3174          }
3175       }
3176       if (smooth2 != NULL) smooth2[0] = smooth2[n-1-index] = FALSE;
3177    }
3178    ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
3179    HighLightReverse();
3180    FinishCutPoly(obj_ptr, poly_ptr, vs1, smooth1, vs2, smooth2, n1, n2);
3181    UpdSelBBox();
3182    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
3183          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
3184          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3185          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3186    SetFileModified(TRUE);
3187    justDupped = FALSE;
3188    HighLightForward();
3189 }
3190 
3191 static
FinishCutPolygon(obj_ptr1,polygon_ptr1,vs,smooth,num_pts)3192 void FinishCutPolygon(obj_ptr1, polygon_ptr1, vs, smooth, num_pts)
3193    struct ObjRec *obj_ptr1;
3194    struct PolygonRec *polygon_ptr1;
3195    IntPoint *vs;
3196    char *smooth;
3197    int num_pts;
3198 {
3199    struct ObjRec *obj_ptr2;
3200    struct PolyRec *poly_ptr;
3201    struct PolygonRec *polygon_ptr2;
3202    int x0, y0;
3203 
3204    x0 = topVSel->x[0];
3205    y0 = topVSel->y[0];
3206 
3207    poly_ptr = (struct PolyRec *)malloc(sizeof(struct PolyRec));
3208    if (poly_ptr == NULL) FailAllocMessage();
3209 
3210    memset(poly_ptr, 0, sizeof(struct PolyRec));
3211    poly_ptr->n = num_pts;
3212    poly_ptr->vlist = vs;
3213    poly_ptr->smooth = smooth;
3214    poly_ptr->asn = 0;
3215    poly_ptr->asvlist = NULL;
3216    poly_ptr->sn = 0;
3217    poly_ptr->svlist = NULL;
3218    poly_ptr->intn = 0;
3219    poly_ptr->intvlist = NULL;
3220    poly_ptr->style = LS_PLAIN;
3221    poly_ptr->width = polygon_ptr1->width;
3222    UtilStrCpyN(poly_ptr->width_spec, sizeof(poly_ptr->width_spec),
3223          polygon_ptr1->width_spec);
3224    poly_ptr->pen = polygon_ptr1->pen;
3225    poly_ptr->curved = polygon_ptr1->curved;
3226    poly_ptr->fill = polygon_ptr1->fill;
3227    poly_ptr->dash = polygon_ptr1->dash;
3228    if (poly_ptr->width == curWidthOfLine[lineWidth]) {
3229       poly_ptr->aw = curArrowHeadW[lineWidth];
3230       poly_ptr->ah = curArrowHeadH[lineWidth];
3231       UtilStrCpyN(poly_ptr->aw_spec, sizeof(poly_ptr->aw_spec),
3232             curArrowHeadWSpec[lineWidth]);
3233       UtilStrCpyN(poly_ptr->ah_spec, sizeof(poly_ptr->ah_spec),
3234             curArrowHeadHSpec[lineWidth]);
3235    } else if (maxLineWidths > 0) {
3236       int i, width=poly_ptr->width;
3237       int min_diff=abs(curWidthOfLine[0]-width), min_index=0;
3238 
3239       for (i=1; min_diff > 0 && i < maxLineWidths; i++) {
3240          int diff=abs(curWidthOfLine[i]-width);
3241 
3242          if (diff < min_diff) {
3243             min_diff = diff;
3244             min_index = i;
3245          }
3246       }
3247       poly_ptr->aw = curArrowHeadW[min_index];
3248       poly_ptr->ah = curArrowHeadH[min_index];
3249       UtilStrCpyN(poly_ptr->aw_spec, sizeof(poly_ptr->aw_spec),
3250             curArrowHeadWSpec[min_index]);
3251       UtilStrCpyN(poly_ptr->ah_spec, sizeof(poly_ptr->ah_spec),
3252             curArrowHeadHSpec[min_index]);
3253    }
3254    poly_ptr->rotated_n = poly_ptr->rotated_asn = 0;
3255    poly_ptr->rotated_vlist = poly_ptr->rotated_asvlist = NULL;
3256 
3257    JustRemoveAllVSel();
3258    PrepareToReplaceAnObj(obj_ptr1);
3259 
3260    obj_ptr2 = DupObj(obj_ptr1);
3261    obj_ptr2->fattr = obj_ptr1->fattr;
3262    obj_ptr2->lattr = obj_ptr1->lattr;
3263    obj_ptr1->fattr = obj_ptr1->lattr = NULL;
3264    polygon_ptr2 = obj_ptr2->detail.g;
3265 
3266    if (polygon_ptr2->vlist != NULL) free(polygon_ptr2->vlist);
3267    if (polygon_ptr2->svlist != NULL) free(polygon_ptr2->svlist);
3268    if (polygon_ptr2->smooth != NULL) free(polygon_ptr2->smooth);
3269    if (polygon_ptr2->intvlist != NULL) free(polygon_ptr2->intvlist);
3270    if (polygon_ptr2->rotated_vlist != NULL) free(polygon_ptr2->rotated_vlist);
3271    free(polygon_ptr2);
3272    if (obj_ptr2->ctm != NULL) free(obj_ptr2->ctm);
3273    obj_ptr2->ctm = NULL;
3274 
3275    obj_ptr2->type = OBJ_POLY;
3276    obj_ptr2->detail.p = poly_ptr;
3277 
3278    AdjObjSplineVs(obj_ptr2);
3279    if (poly_ptr->curved != LT_INTSPLINE) {
3280       UpdPolyBBox(obj_ptr2, poly_ptr->n, poly_ptr->vlist);
3281    } else {
3282       UpdPolyBBox(obj_ptr2, poly_ptr->intn, poly_ptr->intvlist);
3283    }
3284    AdjObjBBox(obj_ptr2);
3285 
3286    AddObj(obj_ptr1->prev, obj_ptr1, obj_ptr2);
3287    UnlinkObj(obj_ptr1);
3288    FreeObj(obj_ptr1);
3289 
3290    topSel->obj = obj_ptr2;
3291    topSel->prev = topSel->next = NULL;
3292    botSel = topSel;
3293 
3294    RecordReplaceAnObj(obj_ptr2);
3295 
3296    topVSel = botVSel = (struct VSelRec *)malloc(sizeof(struct VSelRec));
3297    if (topVSel == NULL) FailAllocMessage();
3298    memset(topVSel, 0, sizeof(struct VSelRec));
3299    topVSel->obj = obj_ptr2;
3300    topVSel->max_v = 10;
3301    topVSel->v_index = (int*)malloc(10*sizeof(int));
3302    topVSel->x = (int*)malloc(10*sizeof(int));
3303    topVSel->y = (int*)malloc(10*sizeof(int));
3304    if (topVSel->v_index==NULL || topVSel->x==NULL || topVSel->y==NULL) {
3305       FailAllocMessage();
3306    }
3307    topVSel->v_index[0] = 0;
3308    topVSel->x[0] = x0;
3309    topVSel->y[0] = y0;
3310    topVSel->n = 1;
3311    topVSel->next = topVSel->prev = NULL;
3312 }
3313 
3314 static
DoCutPolygon(obj_ptr,index,polygon_ptr)3315 void DoCutPolygon(obj_ptr, index, polygon_ptr)
3316    struct ObjRec *obj_ptr;
3317    int index;
3318    struct PolygonRec *polygon_ptr;
3319 {
3320    int i, n=polygon_ptr->n, num_pts, ltx, lty, rbx, rby;
3321    int curved=polygon_ptr->curved;
3322    IntPoint *vs=NULL;
3323    char *smooth=NULL;
3324 
3325    if (curved == LT_STRUCT_SPLINE) {
3326       StretchStructuredSplineInfo sssi;
3327 
3328       memset(&sssi, 0, sizeof(StretchStructuredSplineInfo));
3329       SetIPTInfoForStretchPolygon(index, polygon_ptr->n, polygon_ptr->vlist,
3330             &sssi);
3331       if (!sssi.hinge) {
3332          MsgBox(TgLoadString(STID_CANNOT_CUT_AT_SMOOTH_PT), TOOL_NAME, INFO_MB);
3333          return;
3334       }
3335       num_pts = n;
3336       vs = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
3337       if (vs == NULL) FailAllocMessage();
3338       for (i=sssi.orig_hinge_index; i < num_pts; i++) {
3339          if (obj_ptr->ctm == NULL) {
3340             memcpy(&vs[i-sssi.orig_hinge_index], &polygon_ptr->vlist[i],
3341                   sizeof(IntPoint));
3342          } else {
3343             IntPoint tmp_p;
3344 
3345             TransformObjectV(obj_ptr, &polygon_ptr->vlist[i], &tmp_p);
3346             memcpy(&vs[i-sssi.orig_hinge_index], &tmp_p, sizeof(IntPoint));
3347          }
3348       }
3349       for (i=1; i <= sssi.orig_hinge_index; i++) {
3350          if (obj_ptr->ctm == NULL) {
3351             memcpy(&vs[i+num_pts-sssi.orig_hinge_index-1],
3352                   &polygon_ptr->vlist[i], sizeof(IntPoint));
3353          } else {
3354             IntPoint tmp_p;
3355 
3356             TransformObjectV(obj_ptr, &polygon_ptr->vlist[i], &tmp_p);
3357             memcpy(&vs[i+num_pts-sssi.orig_hinge_index-1], &tmp_p,
3358                   sizeof(IntPoint));
3359          }
3360       }
3361    } else {
3362       num_pts = n;
3363       vs = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
3364       if (vs == NULL) FailAllocMessage();
3365       if (polygon_ptr->curved != LT_INTSPLINE) {
3366          smooth = (char*)malloc((num_pts+1)*sizeof(char));
3367          if (smooth == NULL) FailAllocMessage();
3368       }
3369       for (i=index; i < num_pts; i++) {
3370          if (obj_ptr->ctm == NULL) {
3371             memcpy(&vs[i-index], &polygon_ptr->vlist[i], sizeof(IntPoint));
3372          } else {
3373             IntPoint tmp_p;
3374 
3375             TransformObjectV(obj_ptr, &polygon_ptr->vlist[i], &tmp_p);
3376             memcpy(&vs[i-index], &tmp_p, sizeof(IntPoint));
3377          }
3378          if (smooth != NULL) {
3379             smooth[i-index] = polygon_ptr->smooth[i];
3380          }
3381       }
3382       for (i=1; i <= index; i++) {
3383          if (obj_ptr->ctm == NULL) {
3384             memcpy(&vs[i+num_pts-index-1], &polygon_ptr->vlist[i],
3385                   sizeof(IntPoint));
3386          } else {
3387             IntPoint tmp_p;
3388 
3389             TransformObjectV(obj_ptr, &polygon_ptr->vlist[i], &tmp_p);
3390             memcpy(&vs[i+num_pts-index-1], &tmp_p, sizeof(IntPoint));
3391          }
3392          if (smooth != NULL) {
3393             smooth[i+num_pts-index-1] = polygon_ptr->smooth[i];
3394          }
3395       }
3396       if (smooth != NULL) smooth[0] = smooth[num_pts-1] = FALSE;
3397    }
3398    ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
3399    HighLightReverse();
3400    FinishCutPolygon(obj_ptr, polygon_ptr, vs, smooth, num_pts);
3401    UpdSelBBox();
3402    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
3403          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
3404          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3405          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3406    SetFileModified(TRUE);
3407    justDupped = FALSE;
3408    HighLightForward();
3409 }
3410 
3411 static
CopyPolySegmentProperties(obj_ptr,poly_ptr,curved)3412 void CopyPolySegmentProperties(obj_ptr, poly_ptr, curved)
3413    struct ObjRec *obj_ptr;
3414    struct PolyRec *poly_ptr;
3415    int curved;
3416 {
3417    struct PolyRec *new_poly_ptr=topObj->detail.p;
3418 
3419    new_poly_ptr->style = LS_PLAIN;
3420    new_poly_ptr->width = poly_ptr->width;
3421    new_poly_ptr->aw = poly_ptr->aw;
3422    new_poly_ptr->ah = poly_ptr->ah;
3423    strcpy(new_poly_ptr->width_spec, poly_ptr->width_spec);
3424    strcpy(new_poly_ptr->aw_spec, poly_ptr->aw_spec);
3425    strcpy(new_poly_ptr->ah_spec, poly_ptr->ah_spec);
3426    new_poly_ptr->pen = poly_ptr->pen;
3427    new_poly_ptr->fill = poly_ptr->fill;
3428    new_poly_ptr->curved = curved;
3429    new_poly_ptr->dash = poly_ptr->dash;
3430 
3431    topObj->color = obj_ptr->color;
3432    topObj->bg_color = obj_ptr->bg_color;
3433    memcpy(topObj->color_str, obj_ptr->color_str, sizeof(obj_ptr->color_str));
3434    memcpy(topObj->bg_color_str, obj_ptr->bg_color_str,
3435          sizeof(obj_ptr->bg_color_str));
3436    topObj->trans_pat = obj_ptr->trans_pat;
3437 
3438    AdjObjSplineVs(topObj);
3439    AdjObjBBox(topObj);
3440 }
3441 
3442 static
CopyPolygonSegmentProperties(obj_ptr,polygon_ptr,curved)3443 void CopyPolygonSegmentProperties(obj_ptr, polygon_ptr, curved)
3444    struct ObjRec *obj_ptr;
3445    struct PolygonRec *polygon_ptr;
3446    int curved;
3447 {
3448    struct PolyRec *new_poly_ptr=topObj->detail.p;
3449    int index=0;
3450 
3451    new_poly_ptr->style = LS_PLAIN;
3452    new_poly_ptr->width = polygon_ptr->width;
3453    strcpy(new_poly_ptr->width_spec, polygon_ptr->width_spec);
3454    index = GetBestLineWidthIndex(new_poly_ptr->width, INVALID, INVALID);
3455    new_poly_ptr->aw = curArrowHeadW[index];
3456    new_poly_ptr->ah = curArrowHeadH[index];
3457    strcpy(new_poly_ptr->aw_spec, curArrowHeadWSpec[index]);
3458    strcpy(new_poly_ptr->ah_spec, curArrowHeadHSpec[index]);
3459    new_poly_ptr->pen = polygon_ptr->pen;
3460    new_poly_ptr->fill = polygon_ptr->fill;
3461    new_poly_ptr->curved = curved;
3462    new_poly_ptr->dash = polygon_ptr->dash;
3463 
3464    topObj->color = obj_ptr->color;
3465    topObj->bg_color = obj_ptr->bg_color;
3466    memcpy(topObj->color_str, obj_ptr->color_str, sizeof(obj_ptr->color_str));
3467    memcpy(topObj->bg_color_str, obj_ptr->bg_color_str,
3468          sizeof(obj_ptr->bg_color_str));
3469    topObj->trans_pat = obj_ptr->trans_pat;
3470 
3471    AdjObjSplineVs(topObj);
3472    AdjObjBBox(topObj);
3473 }
3474 
3475 static
CreateSegmentsFromObject(obj_ptr,pp_top_obj,pp_bot_obj)3476 int CreateSegmentsFromObject(obj_ptr, pp_top_obj, pp_bot_obj)
3477    struct ObjRec *obj_ptr, **pp_top_obj, **pp_bot_obj;
3478 {
3479    int i=0, n=0, ssn=0, saved_line_style=0, saved_spline=0, curved=(-1);
3480    IntPoint *vlist=NULL, *ssvlist=NULL, tmp_p;
3481    struct PolyRec *poly_ptr=NULL;
3482    struct PolygonRec *polygon_ptr=NULL;
3483    struct ObjRec *saved_top_obj=topObj, *saved_bot_obj=botObj;
3484    char *ssmooth=NULL;
3485 
3486    switch (obj_ptr->type) {
3487    case OBJ_POLY:
3488       poly_ptr = obj_ptr->detail.p;
3489       curved = poly_ptr->curved;
3490       n = poly_ptr->n;
3491       if (n <= 2) return FALSE;
3492       vlist = poly_ptr->vlist;
3493       if (curved == LT_STRUCT_SPLINE) {
3494          ssn = poly_ptr->ssn;
3495          if (ssn <= 2) return FALSE;
3496          ssvlist = poly_ptr->ssvlist;
3497          ssmooth = poly_ptr->ssmooth;
3498       }
3499       break;
3500    case OBJ_POLYGON:
3501       polygon_ptr = obj_ptr->detail.g;
3502       curved = polygon_ptr->curved;
3503       n = polygon_ptr->n;
3504       if (n <= 2) return FALSE;
3505       vlist = polygon_ptr->vlist;
3506       if (curved == LT_STRUCT_SPLINE) {
3507          ssn = polygon_ptr->ssn;
3508          if (ssn <= 2) return FALSE;
3509          ssvlist = polygon_ptr->ssvlist;
3510          ssmooth = polygon_ptr->ssmooth;
3511       }
3512       break;
3513    }
3514    curPage->top = topObj = (*pp_top_obj);
3515    curPage->bot = botObj = (*pp_bot_obj);
3516    saved_line_style = lineStyle;
3517    saved_spline = curSpline;
3518    lineStyle = LS_PLAIN;
3519    if (curved == LT_STRUCT_SPLINE) {
3520       IntPoint tmp_vs[4];
3521       int num_vs=0;
3522 
3523       curSpline = LT_STRUCT_SPLINE;
3524       ResetCreatePoly();
3525       if (obj_ptr->ctm == NULL) {
3526          memcpy(&tmp_vs[0], &ssvlist[0], sizeof(IntPoint));
3527       } else {
3528          TransformObjectV(obj_ptr, &ssvlist[0], &tmp_p);
3529          memcpy(&tmp_vs[0], &tmp_p, sizeof(IntPoint));
3530       }
3531       num_vs = 1;
3532       for (i=1; i < ssn; i++) {
3533          if (obj_ptr->ctm == NULL) {
3534             memcpy(&tmp_vs[num_vs], &ssvlist[i], sizeof(IntPoint));
3535          } else {
3536             TransformObjectV(obj_ptr, &ssvlist[i], &tmp_p);
3537             memcpy(&tmp_vs[num_vs], &tmp_p, sizeof(IntPoint));
3538          }
3539          num_vs++;
3540          if (!ssmooth[i]) {
3541             IntPointTriplet ipt_first, ipt_last;
3542 
3543             memset(&ipt_first, 0, sizeof(IntPointTriplet));
3544             memset(&ipt_last, 0, sizeof(IntPointTriplet));
3545 
3546             memcpy(&ipt_first.hinge_pt, &tmp_vs[0], sizeof(IntPoint));
3547             ipt_first.earlier_valid = ipt_first.later_valid = FALSE;
3548             ipt_first.ratio = (double)1;
3549 
3550             memcpy(&ipt_last.hinge_pt, &tmp_vs[num_vs-1], sizeof(IntPoint));
3551             ipt_last.earlier_valid = ipt_last.later_valid = FALSE;
3552             ipt_last.ratio = (double)1;
3553 
3554             switch (num_vs) {
3555             case 2: break;
3556             case 3:
3557                memcpy(&ipt_first.later_smooth_pt, &tmp_vs[1], sizeof(IntPoint));
3558                ipt_first.later_valid = TRUE;
3559                break;
3560             case 4:
3561                memcpy(&ipt_first.later_smooth_pt, &tmp_vs[1], sizeof(IntPoint));
3562                ipt_first.later_valid = TRUE;
3563                memcpy(&ipt_last.earlier_smooth_pt, &tmp_vs[2],
3564                      sizeof(IntPoint));
3565                ipt_last.earlier_valid = TRUE;
3566                break;
3567             }
3568             AddPointForCont(0, 0, &ipt_first);
3569             AddPointForCont(0, 0, &ipt_last);
3570             CreatePolyObj(2, TRUE);
3571             switch (obj_ptr->type) {
3572             case OBJ_POLY:
3573                CopyPolySegmentProperties(obj_ptr, poly_ptr, LT_STRUCT_SPLINE);
3574                break;
3575             case OBJ_POLYGON:
3576                CopyPolygonSegmentProperties(obj_ptr, polygon_ptr,
3577                      LT_STRUCT_SPLINE);
3578                break;
3579             }
3580             ResetCreatePoly();
3581             memcpy(&tmp_vs[0], &tmp_vs[num_vs-1], sizeof(IntPoint));
3582             num_vs = 1;
3583          }
3584       }
3585    } else {
3586       IntPoint *tmp_vs=NULL;
3587 
3588       tmp_vs = (IntPoint*)malloc(n*sizeof(IntPoint));
3589       if (tmp_vs == NULL) FailAllocMessage();
3590       memset(tmp_vs, 0, n*sizeof(IntPoint));
3591       for (i=0; i < n; i++) {
3592          if (obj_ptr->ctm == NULL) {
3593             memcpy(&tmp_vs[i], &vlist[i], sizeof(IntPoint));
3594          } else {
3595             TransformObjectV(obj_ptr, &vlist[i], &tmp_p);
3596             memcpy(&tmp_vs[i], &tmp_p, sizeof(IntPoint));
3597          }
3598       }
3599       curSpline = LT_STRAIGHT;
3600       for (i=0; i < n-1; i++) {
3601          ResetCreatePoly();
3602          AddPtToCreatePoly(tmp_vs[i].x, tmp_vs[i].y);
3603          AddPtToCreatePoly(tmp_vs[i+1].x, tmp_vs[i+1].y);
3604          CreatePolyObj(2, TRUE);
3605          switch (obj_ptr->type) {
3606          case OBJ_POLY:
3607             CopyPolySegmentProperties(obj_ptr, poly_ptr, LT_STRAIGHT);
3608             break;
3609          case OBJ_POLYGON:
3610             CopyPolygonSegmentProperties(obj_ptr, polygon_ptr, LT_STRAIGHT);
3611             break;
3612          }
3613       }
3614       free(tmp_vs);
3615    }
3616    lineStyle = saved_line_style;
3617    curSpline = saved_spline;
3618    (*pp_top_obj) = topObj;
3619    (*pp_bot_obj) = botObj;
3620    curPage->top = topObj = saved_top_obj;
3621    curPage->bot = botObj = saved_bot_obj;
3622 
3623    return TRUE;
3624 }
3625 
3626 static
CutPolyIntoSegments()3627 void CutPolyIntoSegments()
3628 {
3629    struct SelRec *sel_ptr=NULL, *new_top_sel=NULL, *new_bot_sel=NULL;
3630    int something_changed=FALSE;
3631 
3632    UnSelNonVertexObjs(TRUE, FALSE); /* with highlight */
3633    UpdSelBBox();
3634    if (topSel == NULL) {
3635       MsgBox(TgLoadString(STID_NO_POLY_OBJ_SELECTED), TOOL_NAME, INFO_MB);
3636       return;
3637    }
3638    HighLightReverse();
3639    StartCompositeCmd();
3640 
3641    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
3642       struct ObjRec *new_top_obj=NULL, *new_bot_obj=NULL;
3643 
3644       PrepareToReplaceAnObj(sel_ptr->obj);
3645       if (CreateSegmentsFromObject(sel_ptr->obj, &new_top_obj, &new_bot_obj)) {
3646          struct ObjRec *obj_ptr=NULL;
3647          struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
3648          int count=0;
3649 
3650          something_changed = TRUE;
3651          UnlinkObj(sel_ptr->obj);
3652          FreeObj(sel_ptr->obj);
3653 
3654          /* add newly created line segments to the top of the object chain */
3655          new_bot_obj->next = topObj;
3656          if (topObj == NULL) {
3657             curPage->bot = botObj = new_bot_obj;
3658          } else {
3659             topObj->prev = new_bot_obj;
3660          }
3661          curPage->top = topObj = new_top_obj;
3662 
3663          topSel = botSel = NULL;
3664          for (obj_ptr=new_bot_obj; obj_ptr != NULL; obj_ptr=obj_ptr->prev,
3665                count++) {
3666             AddSel(NULL, topSel, SelectThisObject(obj_ptr));
3667          }
3668          UpdSelBBox();
3669          RecordCmd(CMD_ONE_TO_MANY, NULL, topSel, botSel, numObjSelected);
3670 
3671          botSel->next = new_top_sel;
3672          if (new_top_sel == NULL) {
3673             new_bot_sel = botSel;
3674          } else {
3675             new_top_sel->prev = botSel;
3676          }
3677          new_top_sel = topSel;
3678 
3679          topSel = saved_top_sel;
3680          botSel = saved_bot_sel;
3681       } else {
3682          AbortPrepareCmd(CMD_REPLACE);
3683       }
3684    }
3685    EndCompositeCmd();
3686 
3687    if (something_changed) {
3688       RemoveAllSel();
3689       topSel = new_top_sel;
3690       botSel = new_bot_sel;
3691       UpdSelBBox();
3692 
3693       RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
3694             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
3695       SetFileModified(TRUE);
3696       justDupped = FALSE;
3697    }
3698    HighLightForward();
3699 }
3700 
CutPoly()3701 void CutPoly()
3702 {
3703    struct ObjRec *obj_ptr;
3704    struct PolyRec *poly_ptr=NULL;
3705    struct PolygonRec *polygon_ptr=NULL;
3706    int index;
3707 
3708    if (curChoice == NOTHING) {
3709       if (topSel == NULL) {
3710          MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
3711          return;
3712       }
3713       if (MsgBox(TgLoadString(STID_Q_OK_TO_CUT_INTO_SEGMENTS), TOOL_NAME,
3714             YNC_MB) != MB_ID_YES) {
3715          return;
3716       }
3717       CutPolyIntoSegments();
3718       return;
3719    } else if (curChoice != VERTEXMODE) {
3720       MsgBox(TgLoadString(STID_CMD_ONLY_AVAIL_IN_VERTEX_MODE), TOOL_NAME,
3721             INFO_MB);
3722       return;
3723    } else if (CountSelectedVertices() != 1) {
3724       MsgBox(TgLoadString(STID_SEL_1_VERTEX_TO_CUT), TOOL_NAME, INFO_MB);
3725       return;
3726    }
3727    obj_ptr = topVSel->obj;
3728    index = topVSel->v_index[0];
3729    switch (obj_ptr->type) {
3730    case OBJ_POLY:
3731       poly_ptr = obj_ptr->detail.p;
3732       if (index==0 || index==poly_ptr->n-1) return;
3733       DoCutPoly(obj_ptr, index, poly_ptr);
3734       break;
3735    case OBJ_POLYGON:
3736       polygon_ptr = obj_ptr->detail.g;
3737       DoCutPolygon(obj_ptr, index, polygon_ptr);
3738       break;
3739    default:
3740       MsgBox(TgLoadString(STID_SEL_A_VERTEX_FROM_POLY_OR_GON), TOOL_NAME,
3741             INFO_MB);
3742       return;
3743    }
3744 }
3745 
3746 /* --------------------- GetWidthInDouble() --------------------- */
3747 
GetWidthInDouble(nVal,pszSpec,pnIsInt)3748 double GetWidthInDouble(nVal, pszSpec, pnIsInt)
3749    int nVal, *pnIsInt;
3750    char *pszSpec;
3751 {
3752    float fval;
3753 
3754    if (pnIsInt != NULL) *pnIsInt = TRUE;
3755    if (pszSpec == NULL || *pszSpec == '\0') return (double)nVal;
3756    if (sscanf(pszSpec, "%f", &fval) != 1) return (double)nVal;
3757    if (pnIsInt != NULL) {
3758       if (fabs(((float)nVal)-fval) > INT_TOL) {
3759          *pnIsInt = FALSE;
3760       }
3761    }
3762    return ((double)fval);
3763 }
3764 
3765 /* --------------------- SetWidthAndSpec() --------------------- */
3766 
SetWidthAndSpec(dWidth,pnWidth,pszWidthSpec)3767 void SetWidthAndSpec(dWidth, pnWidth, pszWidthSpec)
3768    double dWidth;
3769    int *pnWidth;
3770    char *pszWidthSpec;
3771 {
3772    float fval=(float)dWidth;
3773 
3774    FormatFloat(&fval, pszWidthSpec);
3775    *pnWidth = round(dWidth);
3776 }
3777 
3778 /* --------------------- ScaleWidthAndSpec() --------------------- */
3779 
ScaleWidthAndSpec(dScale,pnWidth,pszWidthSpec)3780 void ScaleWidthAndSpec(dScale, pnWidth, pszWidthSpec)
3781    double dScale;
3782    int *pnWidth;
3783    char *pszWidthSpec; /* char[40] */
3784 {
3785    double dw=GetWidthInDouble(*pnWidth, pszWidthSpec, NULL);
3786 
3787    dw = dw*dScale;
3788    SetWidthAndSpec(dw, pnWidth, pszWidthSpec);
3789 }
3790 
3791 /* --------------------- DumpArrow() --------------------- */
3792 
DumpArrow(FP,TailV,HeadV,ArrowW,ArrowH,aw_spec,ah_spec,Pen,TransPat,ColorIndex)3793 void DumpArrow(FP, TailV, HeadV, ArrowW, ArrowH, aw_spec, ah_spec, Pen,
3794       TransPat, ColorIndex)
3795    FILE *FP;
3796    IntPoint *TailV, *HeadV;
3797    int ArrowW, ArrowH, Pen, TransPat, ColorIndex;
3798    char *aw_spec, *ah_spec;
3799    /* HeadV is where the arrow tip is */
3800    /* Make sure this function is not called with (Pen==BACKPAT && TransPat) */
3801 {
3802    int i, dx, dy;
3803    struct BBRec bbox;
3804    IntPoint v[2];
3805    double len, sin, cos, daw, dah;
3806 
3807    memset(&bbox, 0, sizeof(struct BBRec));
3808    dx = HeadV->x - TailV->x;
3809    dy = HeadV->y - TailV->y;
3810 
3811    if (dx == 0 && dy == 0) return;
3812 
3813    fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
3814    fprintf(FP, "   %s\n", &(gPsCmd[PS_TGIFSETMATRIX])[1]);
3815 
3816    daw = GetWidthInDouble(ArrowW, aw_spec, NULL);
3817    dah = GetWidthInDouble(ArrowH, ah_spec, NULL);
3818    if (colorDump || !useGray) {
3819       len = (double)sqrt((double)(((double)dx)*((double)dx) +
3820             ((double)dy)*((double)dy)));
3821       sin = ((double)dy) / len;
3822       cos = ((double)dx) / len;
3823 
3824       v[0].x = round(HeadV->x - daw*cos + dah*sin);
3825       v[0].y = round(HeadV->y - daw*sin - dah*cos);
3826       v[1].x = round(HeadV->x - daw*cos - dah*sin);
3827       v[1].y = round(HeadV->y - daw*sin + dah*cos);
3828 
3829       bbox.ltx = bbox.rbx = HeadV->x;
3830       bbox.lty = bbox.rby = HeadV->y;
3831 
3832       for (i = 0; i < 2; i++) {
3833          if (v[i].x < bbox.ltx) bbox.ltx = v[i].x;
3834          if (v[i].y < bbox.lty) bbox.lty = v[i].y;
3835          if (v[i].x > bbox.rbx) bbox.rbx = v[i].x;
3836          if (v[i].y > bbox.rby) bbox.rby = v[i].y;
3837       }
3838       if (preDumpSetup) PSUseArrow();
3839       if (!TransPat) {
3840          fprintf(FP, "   %s\n", gPsCmd[PS_NEWPATH]);
3841          fprintf(FP, "      %1d %1d %.3f %.3f %1d %1d TGAT\n",
3842                HeadV->x, HeadV->y, daw, dah, dx, dy);
3843          fprintf(FP, "   1 %s %s %s\n", gPsCmd[PS_SETGRAY],
3844                gPsCmd[PS_CLOSEPATH], gPsCmd[PS_FILL]);
3845          DumpRGBColorLine(FP, ColorIndex, 3, TRUE);
3846       }
3847    } else {
3848       switch (Pen) {
3849       case SOLIDPAT: break;
3850       case BACKPAT: break;
3851       default:
3852          GrayCheck(Pen);
3853          fprintf(FP, "   %s %s\n", GrayStr(Pen), gPsCmd[PS_SETGRAY]);
3854          break;
3855       }
3856    }
3857    if (!((colorDump || !useGray) && Pen==BACKPAT)) {
3858       if (preDumpSetup) PSUseArrow();
3859       fprintf(FP, "   %s\n", gPsCmd[PS_NEWPATH]);
3860       fprintf(FP, "      %1d %1d %.3f %.3f %1d %1d TGAT\n",
3861             HeadV->x, HeadV->y, daw, dah, dx, dy);
3862    }
3863    if (colorDump || !useGray) {
3864       switch (Pen) {
3865       case SOLIDPAT:
3866          fprintf(FP, "   %s %s\n", gPsCmd[PS_CLOSEPATH], gPsCmd[PS_FILL]);
3867          break;
3868       case BACKPAT: break;
3869       default:
3870          if (preDumpSetup) PSUseColorPattern();
3871          fprintf(FP, "   %s %s %s\n", gPsCmd[PS_CLOSEPATH],
3872                gPsCmd[PS_EOCLIP], gPsCmd[PS_NEWPATH]);
3873          DumpPatFill(FP, Pen, bbox, 3, TRUE);
3874          break;
3875       }
3876    } else {
3877       switch (Pen) {
3878       case SOLIDPAT:
3879          fprintf(FP, "   %s %s\n", gPsCmd[PS_CLOSEPATH], gPsCmd[PS_FILL]);
3880          break;
3881       case BACKPAT:
3882          if (!TransPat) {
3883             fprintf(FP, "   %s 1 %s %s\n", gPsCmd[PS_CLOSEPATH],
3884                   gPsCmd[PS_SETGRAY], gPsCmd[PS_FILL]);
3885          }
3886          break;
3887       default:
3888          fprintf(FP, "   %s %s\n", gPsCmd[PS_CLOSEPATH], gPsCmd[PS_FILL]);
3889          break;
3890       }
3891    }
3892    fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
3893 }
3894 
3895 /* --------------------- DumpPolyObj() --------------------- */
3896 
3897 static
CalcArrowRetreatPoint(TailV,HeadV,ArrowW,aw_spec,ReturnV)3898 int CalcArrowRetreatPoint(TailV, HeadV, ArrowW, aw_spec, ReturnV)
3899    IntPoint *TailV, *HeadV, *ReturnV;
3900    int ArrowW;
3901    char *aw_spec;
3902    /* HeadV is where the arrow tip is */
3903 {
3904    int dx, dy;
3905    double len, sin, cos, daw;
3906 
3907    dx = HeadV->x - TailV->x;
3908    dy = HeadV->y - TailV->y;
3909 
3910    if (dx == 0 && dy == 0) return FALSE;
3911 
3912    len = (double)sqrt((double)(((double)dx)*((double)dx) +
3913          ((double)dy)*((double)dy)));
3914    sin = ((double)dy) / len;
3915    cos = ((double)dx) / len;
3916 
3917    daw = GetWidthInDouble(ArrowW, aw_spec, NULL);
3918    ReturnV->x = round(HeadV->x-RETREAT*daw*cos);
3919    ReturnV->y = round(HeadV->y-RETREAT*daw*sin);
3920    return TRUE;
3921 }
3922 
3923 static
DumpPolyPath(FP,ObjPtr,Vs,NumPts,Smooth,Style,Width,ArrowW,ArrowH,width_spec,aw_spec,ah_spec,Pen,Fill,Curved,Dash,Indent,TransPat)3924 void DumpPolyPath(FP, ObjPtr, Vs, NumPts, Smooth, Style, Width, ArrowW, ArrowH,
3925       width_spec, aw_spec, ah_spec, Pen, Fill, Curved, Dash, Indent, TransPat)
3926    FILE *FP;
3927    register struct ObjRec *ObjPtr;
3928    IntPoint *Vs;
3929    int NumPts, Style, Width, ArrowW, ArrowH;
3930    char *width_spec, *aw_spec, *ah_spec;
3931    int Pen, Fill, Curved, Dash, Indent, TransPat;
3932    char *Smooth;
3933 {
3934    register int i, dx, dy;
3935    int retracted_arrow, color_index=ObjPtr->color, w_is_int=TRUE;
3936    double daw, dw;
3937 
3938    retracted_arrow = (RetractedArrowAttr(ObjPtr) ||
3939          AutoRetractedArrowAttr(ObjPtr, TRUE));
3940 
3941    daw = GetWidthInDouble(ArrowW, aw_spec, NULL);
3942    dw = GetWidthInDouble(Width, width_spec, &w_is_int);
3943    if (Fill == (-1) && Pen != (-1)) {
3944       /* dumping the pen */
3945       if (Dash != 0) {
3946          for (i=0; i < Indent+3; i++) fprintf(FP, " ");
3947          fprintf(FP, "[");
3948          for (i = 0; i < dashListLength[Dash]-1; i++) {
3949             fprintf(FP, "%1d ", (int)(dashList[Dash][i]));
3950          }
3951          fprintf(FP, "%1d] 0 %s\n",
3952                (int)(dashList[Dash][dashListLength[Dash]-1]),
3953                gPsCmd[PS_SETDASH]);
3954       }
3955    } else if (Fill != (-1) && Pen == (-1)) {
3956       /* dumping the fill */
3957       if (Fill > BACKPAT) {
3958          if (colorDump || !useGray) {
3959             for (i=0; i < Indent; i++) fprintf(FP, " ");
3960             fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
3961             if (preDumpSetup) PSUseColorPattern();
3962             if (!TransPat) {
3963                DumpPolyPath(FP, ObjPtr, Vs, NumPts, Smooth, LS_PLAIN, Width,
3964                      ArrowW, ArrowH, width_spec, aw_spec, ah_spec,
3965                      (-1), BACKPAT, Curved, Dash, Indent, TransPat);
3966             }
3967          } else {
3968             for (i=0; i < Indent; i++) fprintf(FP, " ");
3969             fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
3970             GrayCheck(Fill);
3971             for (i=0; i < Indent+3; i++) fprintf(FP, " ");
3972             fprintf(FP, "%s %s\n", GrayStr(Fill), gPsCmd[PS_SETGRAY]);
3973          }
3974       }
3975    }
3976 #ifndef DONT_DRAW_ZERO_LENGTH_POLY_AS_DOT
3977    if (NumPts == 2 && Vs[0].x == Vs[1].x && Vs[0].y == Vs[1].y) {
3978       for (i=0; i < Indent+3; i++) fprintf(FP, " ");
3979       fprintf(FP, "1 %s\n", gPsCmd[PS_SETLINECAP]);
3980    }
3981 #endif /* ~DONT_DRAW_ZERO_LENGTH_POLY_AS_DOT */
3982    for (i=0; i < Indent+3; i++) fprintf(FP, " ");
3983    fprintf(FP, "%s\n", gPsCmd[PS_NEWPATH]);
3984    for (i=0; i < Indent+3; i++) fprintf(FP, " ");
3985    fprintf(FP, "   %1d %1d %s\n", Vs[0].x, Vs[0].y, gPsCmd[PS_MOVETO]);
3986    if (Style & LS_LEFT) {
3987       dx = Vs[1].x - Vs[0].x;
3988       dy = Vs[1].y - Vs[0].y;
3989       if (dx != 0 || dy != 0) {
3990          if (!retracted_arrow) {
3991             if (ObjPtr->ctm == NULL) {
3992                for (i=0; i < Indent+6; i++) fprintf(FP, " ");
3993                fprintf(FP, "%1d %1d atan %s cos %.3f %s exch sin %.3f %s %s\n",
3994                      dy, dx, gPsCmd[PS_DUP], daw, gPsCmd[PS_MUL], daw,
3995                      gPsCmd[PS_MUL], gPsCmd[PS_RMOVETO]);
3996             } else {
3997                IntPoint ip0, ip1, ip2, ip3;
3998 
3999                TransformObjectV(ObjPtr, &Vs[1], &ip0);
4000                TransformObjectV(ObjPtr, &Vs[0], &ip1);
4001                if (CalcArrowRetreatPoint(&ip0, &ip1, ArrowW, aw_spec, &ip2)) {
4002                   ReversedTransformObjectV(ObjPtr, &ip2, &ip3);
4003                   for (i=0; i < Indent+6; i++) fprintf(FP, " ");
4004                   fprintf(FP, "%1d %1d %s\n", ip3.x, ip3.y, gPsCmd[PS_MOVETO]);
4005                }
4006             }
4007          }
4008       }
4009    }
4010    if (Style & LS_RIGHT) {
4011       if (Curved == LT_INTSPLINE) {
4012          DumpCurvedPolyPoints(FP, Curved, NumPts, Vs, Indent+6);
4013       } else {
4014          DumpMultiCurvedPolyPoints(FP, Smooth, Style, Curved, NumPts, Vs,
4015                Indent+6);
4016       }
4017       dx = Vs[NumPts-1].x - Vs[NumPts-2].x;
4018       dy = Vs[NumPts-1].y - Vs[NumPts-2].y;
4019       if (dx != 0 || dy != 0) {
4020          if (retracted_arrow) {
4021             for (i=0; i < Indent+6; i++) fprintf(FP, " ");
4022             fprintf(FP, "%1d %1d", Vs[NumPts-1].x, Vs[NumPts-1].y);
4023          } else {
4024             if (ObjPtr->ctm == NULL) {
4025                for (i=0; i < Indent+6; i++) fprintf(FP, " ");
4026                fprintf(FP, "%1d %1d atan %s cos %.3f %s %1d exch %s\n",
4027                      dy, dx, gPsCmd[PS_DUP], daw, gPsCmd[PS_MUL],
4028                      Vs[NumPts-1].x, gPsCmd[PS_SUB]);
4029                for (i=0; i < Indent+6; i++) fprintf(FP, " ");
4030                fprintf(FP, "exch sin %.3f %s %1d exch %s",
4031                      daw, gPsCmd[PS_MUL], Vs[NumPts-1].y, gPsCmd[PS_SUB]);
4032             } else {
4033                IntPoint ip0, ip1, ip2, ip3;
4034 
4035                TransformObjectV(ObjPtr, &Vs[NumPts-2], &ip0);
4036                TransformObjectV(ObjPtr, &Vs[NumPts-1], &ip1);
4037                if (CalcArrowRetreatPoint(&ip0, &ip1, ArrowW, aw_spec, &ip2)) {
4038                   ReversedTransformObjectV(ObjPtr, &ip2, &ip3);
4039                   for (i=0; i < Indent+6; i++) fprintf(FP, " ");
4040                   fprintf(FP, "%1d %1d", ip3.x, ip3.y);
4041                }
4042             }
4043          }
4044          switch (Curved) {
4045          case LT_STRAIGHT:
4046          case LT_SPLINE:
4047          case LT_STRUCT_SPLINE:
4048             if (NumPts <= 2 || (Smooth != NULL && !Smooth[NumPts-2])) {
4049                fprintf(FP, " %s", gPsCmd[PS_LINETO]);
4050             } else {
4051                fprintf(FP, " %s", gPsCmd[PS_CURVETO]);
4052             }
4053             break;
4054          case LT_INTSPLINE:
4055             if (NumPts <= 2) {
4056                fprintf(FP, " %s", gPsCmd[PS_LINETO]);
4057             } else {
4058                fprintf(FP, " %s", gPsCmd[PS_CURVETO]);
4059             }
4060             break;
4061          }
4062       }
4063       fprintf(FP, "\n");
4064    } else if (Curved == LT_INTSPLINE) {
4065       DumpCurvedPolyPoints(FP, Curved, NumPts, Vs, Indent+6);
4066       if (NumPts <= 2) {
4067          for (i=0; i < Indent+6; i++) fprintf(FP, " ");
4068          fprintf(FP, "%1d %1d %s\n",Vs[NumPts-1].x,Vs[NumPts-1].y,
4069                gPsCmd[PS_LINETO]);
4070       } else {
4071          for (i=0; i < Indent+6; i++) fprintf(FP, " ");
4072          fprintf(FP, "%1d %1d %s\n",Vs[NumPts-1].x,Vs[NumPts-1].y,
4073                gPsCmd[PS_CURVETO]);
4074       }
4075    } else {
4076       DumpMultiCurvedPolyPoints(FP, Smooth, Style, Curved, NumPts, Vs,
4077             Indent+6);
4078    }
4079    if (Fill == (-1) && Pen != (-1)) {
4080       /* dumping the pen */
4081       for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4082       fprintf(FP, "%s\n", &(gPsCmd[PS_TGIFSETMATRIX])[1]);
4083       for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4084       if (w_is_int) {
4085          fprintf(FP, "%1d %s\n", Width, gPsCmd[PS_SETLINEWIDTH]);
4086       } else {
4087          fprintf(FP, "%.3f %s\n", dw, gPsCmd[PS_SETLINEWIDTH]);
4088       }
4089       for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4090       switch (Pen) {
4091       case SOLIDPAT: fprintf(FP, "%s\n", gPsCmd[PS_STROKE]); break;
4092       case BACKPAT:
4093          if (!TransPat) {
4094             fprintf(FP, "1 %s %s\n", gPsCmd[PS_SETGRAY], gPsCmd[PS_STROKE]);
4095          }
4096          break;
4097       default:
4098          if (colorDump || !useGray) {
4099             if (preDumpSetup) PSUseColorPattern();
4100             fprintf(FP, "%s\n", gPsCmd[PS_FLATTENPATH]);
4101             for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4102             DumpPatFill(FP, Pen, ObjPtr->bbox, 0, TRUE);
4103          } else {
4104             GrayCheck(Pen);
4105             fprintf(FP, "%s %s\n", GrayStr(Pen), gPsCmd[PS_SETGRAY]);
4106             for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4107             fprintf(FP, "%s\n", gPsCmd[PS_STROKE]);
4108          }
4109          break;
4110       }
4111       if (Dash != 0) {
4112          for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4113          fprintf(FP, "[] 0 %s\n", gPsCmd[PS_SETDASH]);
4114       }
4115       if (Width != 1) {
4116          for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4117          fprintf(FP, "1 %s\n", gPsCmd[PS_SETLINEWIDTH]);
4118       }
4119    } else if (Fill != (-1) && Pen == (-1)) {
4120       /* dumping the fill */
4121       for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4122       switch (Fill) {
4123       case SOLIDPAT:
4124          fprintf(FP, "%s %s\n", gPsCmd[PS_CLOSEPATH], gPsCmd[PS_EOFILL]);
4125          break;
4126       case BACKPAT:
4127          if (!TransPat) {
4128             fprintf(FP, "%s 1 %s %s\n", gPsCmd[PS_CLOSEPATH],
4129                   gPsCmd[PS_SETGRAY], gPsCmd[PS_EOFILL]);
4130             for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4131             DumpRGBColorLine(FP, color_index, 0, TRUE);
4132          }
4133          break;
4134       default:
4135          if (colorDump || !useGray) {
4136             if (preDumpSetup) PSUseColorPattern();
4137             fprintf(FP, "%s %s %s\n", gPsCmd[PS_CLOSEPATH],
4138                   gPsCmd[PS_EOCLIP], gPsCmd[PS_NEWPATH]);
4139             for (i=0; i < Indent+3; i++) fprintf(FP, " ");
4140             DumpPatFill(FP, Fill, ObjPtr->bbox, 0, TRUE);
4141          } else {
4142             fprintf(FP, "%s %s\n", gPsCmd[PS_CLOSEPATH], gPsCmd[PS_EOFILL]);
4143          }
4144          for (i=0; i < Indent; i++) fprintf(FP, " ");
4145          fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
4146          break;
4147       }
4148    }
4149 }
4150 
DumpPolyObj(FP,ObjPtr)4151 void DumpPolyObj(FP, ObjPtr)
4152    FILE *FP;
4153    register struct ObjRec *ObjPtr;
4154 {
4155    IntPoint *intv=NULL, *v=NULL;
4156    int num_pts, trans_pat, fill, pen, width, curved, dash, color_index;
4157    int style, aw, ah, rotation, intn, retracted_arrow;
4158    char *smooth=NULL, *width_spec=NULL, *aw_spec=NULL, *ah_spec=NULL;
4159 
4160    trans_pat = ObjPtr->trans_pat;
4161    fill = ObjPtr->detail.p->fill;
4162    width = ObjPtr->detail.p->width;
4163    aw = ObjPtr->detail.p->aw;
4164    ah = ObjPtr->detail.p->ah;
4165    width_spec = ObjPtr->detail.p->width_spec;
4166    aw_spec = ObjPtr->detail.p->aw_spec;
4167    ah_spec = ObjPtr->detail.p->ah_spec;
4168    pen = ObjPtr->detail.p->pen;
4169    style = ObjPtr->detail.p->style;
4170    curved = ObjPtr->detail.p->curved;
4171    dash = ObjPtr->detail.p->dash;
4172    rotation = ObjPtr->rotation;
4173    if (curved == LT_STRUCT_SPLINE) {
4174       v = ObjPtr->detail.p->ssvlist;
4175       num_pts = ObjPtr->detail.p->ssn;
4176       smooth = ObjPtr->detail.p->ssmooth;
4177    } else {
4178       v = ObjPtr->detail.p->vlist;
4179       num_pts = ObjPtr->detail.p->n;
4180       smooth = ObjPtr->detail.p->smooth;
4181    }
4182    intv = ObjPtr->detail.p->intvlist;
4183    intn = ObjPtr->detail.p->intn;
4184 
4185    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
4186          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
4187       return;
4188    }
4189    fprintf(FP, "%% POLY/OPEN-SPLINE\n");
4190    color_index = ObjPtr->color;
4191    DumpRGBColorLine(FP, color_index, 0, TRUE);
4192 
4193    if (ObjPtr->ctm != NULL) {
4194       float m[6];
4195 
4196       fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
4197       m[CTM_SX] = ((float)ObjPtr->ctm->m[CTM_SX])/((float)1000.0);
4198       m[CTM_SY] = ((float)ObjPtr->ctm->m[CTM_SY])/((float)1000.0);
4199       m[CTM_SIN] = ((float)ObjPtr->ctm->m[CTM_SIN])/((float)1000.0);
4200       m[CTM_MSIN] = ((float)ObjPtr->ctm->m[CTM_MSIN])/((float)1000.0);
4201       fprintf(FP, "   %1d %1d %s\n", ObjPtr->x, ObjPtr->y,
4202             gPsCmd[PS_TRANSLATE]);
4203       fprintf(FP, "   [%.3f %.3f %.3f %.3f %1d %1d] %s\n",
4204             m[CTM_SX], m[CTM_SIN], m[CTM_MSIN], m[CTM_SY],
4205             ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY], gPsCmd[PS_CONCAT]);
4206       fprintf(FP, "   %1d %s %1d %s %s\n",
4207             ObjPtr->x, gPsCmd[PS_NEG], ObjPtr->y, gPsCmd[PS_NEG],
4208             gPsCmd[PS_TRANSLATE]);
4209    }
4210    if (fill != NONEPAT && num_pts > 2 && !(fill == BACKPAT && trans_pat)) {
4211       if (curved != LT_INTSPLINE) {
4212          DumpPolyPath(FP, ObjPtr, v, num_pts, smooth, LS_PLAIN, width, aw, ah,
4213                width_spec, aw_spec, ah_spec, (-1), fill, curved, dash,
4214                (fill > BACKPAT ? 0 : (-3)), trans_pat);
4215       } else {
4216          DumpPolyPath(FP, ObjPtr, intv, intn, smooth, LS_PLAIN, width, aw, ah,
4217                width_spec, aw_spec, ah_spec, (-1), fill, curved, dash,
4218                (fill > BACKPAT ? 0 : (-3)), trans_pat);
4219       }
4220    }
4221    if (pen == NONEPAT || (pen == BACKPAT && trans_pat)) {
4222       if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
4223       fprintf(FP, "\n");
4224       return;
4225    }
4226 
4227    fprintf(FP, "%s\n", gPsCmd[PS_GSAVE]);
4228 
4229    if ((colorDump || !useGray) && pen > BACKPAT && !trans_pat) {
4230       fprintf(FP, "   %s\n", gPsCmd[PS_GSAVE]);
4231       if (curved != LT_INTSPLINE) {
4232          DumpPolyPath(FP, ObjPtr, v, num_pts, smooth, style, width, aw, ah,
4233                width_spec, aw_spec, ah_spec, BACKPAT, (-1), curved, 0, 3,
4234                trans_pat);
4235       } else {
4236          DumpPolyPath(FP, ObjPtr, intv, intn, smooth, style, width, aw, ah,
4237                width_spec, aw_spec, ah_spec, BACKPAT, (-1), curved, 0, 3,
4238                trans_pat);
4239       }
4240       fprintf(FP, "   %s\n", gPsCmd[PS_GRESTORE]);
4241    }
4242    if (curved != LT_INTSPLINE) {
4243       DumpPolyPath(FP, ObjPtr, v, num_pts, smooth, style, width, aw, ah,
4244             width_spec, aw_spec, ah_spec, pen, (-1), curved, dash, 0,
4245             trans_pat);
4246    } else {
4247       DumpPolyPath(FP, ObjPtr, intv, intn, smooth, style, width, aw, ah,
4248             width_spec, aw_spec, ah_spec, pen, (-1), curved, dash, 0,
4249             trans_pat);
4250    }
4251    fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
4252 
4253    retracted_arrow = (RetractedArrowAttr(ObjPtr) ||
4254          AutoRetractedArrowAttr(ObjPtr, TRUE));
4255 
4256    if (ObjPtr->ctm == NULL) {
4257       if (curved != LT_INTSPLINE) {
4258          switch (style) {
4259          case LS_PLAIN: break;
4260          case LS_LEFT:
4261             if (retracted_arrow) {
4262                DumpArrow(FP, &v[2], &v[1], aw, ah, aw_spec, ah_spec,
4263                      pen, trans_pat, color_index);
4264             } else {
4265                DumpArrow(FP, &v[1], &v[0], aw, ah, aw_spec, ah_spec,
4266                      pen, trans_pat, color_index);
4267             }
4268             break;
4269          case LS_RIGHT:
4270             if (retracted_arrow) {
4271                DumpArrow(FP, &v[num_pts-3], &v[num_pts-2], aw, ah,
4272                      aw_spec, ah_spec, pen, trans_pat, color_index);
4273             } else {
4274                DumpArrow(FP, &v[num_pts-2], &v[num_pts-1], aw, ah,
4275                      aw_spec, ah_spec, pen, trans_pat, color_index);
4276             }
4277             break;
4278          case LS_DOUBLE:
4279             if (retracted_arrow) {
4280                DumpArrow(FP, &v[2], &v[1], aw, ah, aw_spec, ah_spec,
4281                      pen, trans_pat, color_index);
4282                DumpArrow(FP, &v[num_pts-3], &v[num_pts-2], aw, ah,
4283                      aw_spec, ah_spec, pen, trans_pat, color_index);
4284             } else {
4285                DumpArrow(FP, &v[1], &v[0], aw, ah, aw_spec, ah_spec,
4286                      pen, trans_pat, color_index);
4287                DumpArrow(FP, &v[num_pts-2], &v[num_pts-1], aw, ah,
4288                      aw_spec, ah_spec, pen, trans_pat, color_index);
4289             }
4290             break;
4291          }
4292       } else {
4293          switch (style) {
4294          case LS_PLAIN: break;
4295          case LS_LEFT:
4296             if (retracted_arrow) {
4297                DumpArrow(FP, &intv[2], &v[1], aw, ah, aw_spec, ah_spec,
4298                      pen, trans_pat, color_index);
4299             } else {
4300                DumpArrow(FP, &intv[1], &intv[0], aw, ah, aw_spec, ah_spec,
4301                      pen, trans_pat, color_index);
4302             }
4303             break;
4304          case LS_RIGHT:
4305             if (retracted_arrow) {
4306                DumpArrow(FP, &intv[intn-3], &v[num_pts-2], aw, ah,
4307                      aw_spec, ah_spec, pen, trans_pat, color_index);
4308             } else {
4309                DumpArrow(FP, &intv[intn-2], &intv[intn-1], aw, ah,
4310                      aw_spec, ah_spec, pen, trans_pat, color_index);
4311             }
4312             break;
4313          case LS_DOUBLE:
4314             if (retracted_arrow) {
4315                DumpArrow(FP, &intv[2], &v[1], aw, ah, aw_spec, ah_spec,
4316                      pen, trans_pat, color_index);
4317                DumpArrow(FP, &intv[intn-3], &v[num_pts-2], aw, ah,
4318                      aw_spec, ah_spec, pen, trans_pat, color_index);
4319             } else {
4320                DumpArrow(FP, &intv[1], &intv[0], aw, ah, aw_spec, ah_spec,
4321                      pen, trans_pat, color_index);
4322                DumpArrow(FP, &intv[intn-2], &intv[intn-1], aw, ah,
4323                      aw_spec, ah_spec, pen, trans_pat, color_index);
4324             }
4325             break;
4326          }
4327       }
4328    } else {
4329       IntPoint ip0, ip1;
4330 
4331       if (curved != LT_INTSPLINE) {
4332          switch (style) {
4333          case LS_PLAIN: break;
4334          case LS_LEFT:
4335             if (retracted_arrow) {
4336                TransformObjectV(ObjPtr, &v[2], &ip0);
4337                TransformObjectV(ObjPtr, &v[1], &ip1);
4338                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4339                      pen, trans_pat, color_index);
4340             } else {
4341                TransformObjectV(ObjPtr, &v[1], &ip0);
4342                TransformObjectV(ObjPtr, &v[0], &ip1);
4343                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4344                      pen, trans_pat, color_index);
4345             }
4346             break;
4347          case LS_RIGHT:
4348             if (retracted_arrow) {
4349                TransformObjectV(ObjPtr, &v[num_pts-3], &ip0);
4350                TransformObjectV(ObjPtr, &v[num_pts-2], &ip1);
4351                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4352                      pen, trans_pat, color_index);
4353             } else {
4354                TransformObjectV(ObjPtr, &v[num_pts-2], &ip0);
4355                TransformObjectV(ObjPtr, &v[num_pts-1], &ip1);
4356                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4357                      pen, trans_pat, color_index);
4358             }
4359             break;
4360          case LS_DOUBLE:
4361             if (retracted_arrow) {
4362                TransformObjectV(ObjPtr, &v[2], &ip0);
4363                TransformObjectV(ObjPtr, &v[1], &ip1);
4364                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4365                      pen, trans_pat, color_index);
4366                TransformObjectV(ObjPtr, &v[num_pts-3], &ip0);
4367                TransformObjectV(ObjPtr, &v[num_pts-2], &ip1);
4368                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4369                      pen, trans_pat, color_index);
4370             } else {
4371                TransformObjectV(ObjPtr, &v[1], &ip0);
4372                TransformObjectV(ObjPtr, &v[0], &ip1);
4373                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4374                      pen, trans_pat, color_index);
4375                TransformObjectV(ObjPtr, &v[num_pts-2], &ip0);
4376                TransformObjectV(ObjPtr, &v[num_pts-1], &ip1);
4377                DumpArrow(FP, &ip0, &ip1,aw, ah, aw_spec, ah_spec,
4378                      pen, trans_pat, color_index);
4379             }
4380             break;
4381          }
4382       } else {
4383          switch (style) {
4384          case LS_PLAIN: break;
4385          case LS_LEFT:
4386             if (retracted_arrow) {
4387                TransformObjectV(ObjPtr, &intv[2], &ip0);
4388                TransformObjectV(ObjPtr, &v[1], &ip1);
4389                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4390                      pen, trans_pat, color_index);
4391             } else {
4392                TransformObjectV(ObjPtr, &intv[1], &ip0);
4393                TransformObjectV(ObjPtr, &intv[0], &ip1);
4394                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4395                      pen, trans_pat, color_index);
4396             }
4397             break;
4398          case LS_RIGHT:
4399             if (retracted_arrow) {
4400                TransformObjectV(ObjPtr, &intv[intn-3], &ip0);
4401                TransformObjectV(ObjPtr, &v[num_pts-2], &ip1);
4402                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4403                      pen, trans_pat, color_index);
4404             } else {
4405                TransformObjectV(ObjPtr, &intv[intn-2], &ip0);
4406                TransformObjectV(ObjPtr, &intv[intn-1], &ip1);
4407                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4408                      pen, trans_pat, color_index);
4409             }
4410             break;
4411          case LS_DOUBLE:
4412             if (retracted_arrow) {
4413                TransformObjectV(ObjPtr, &intv[2], &ip0);
4414                TransformObjectV(ObjPtr, &v[1], &ip1);
4415                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4416                      pen, trans_pat, color_index);
4417                TransformObjectV(ObjPtr, &intv[intn-3], &ip0);
4418                TransformObjectV(ObjPtr, &v[num_pts-2], &ip1);
4419                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4420                      pen, trans_pat, color_index);
4421             } else {
4422                TransformObjectV(ObjPtr, &intv[1], &ip0);
4423                TransformObjectV(ObjPtr, &intv[0], &ip1);
4424                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4425                      pen, trans_pat, color_index);
4426                TransformObjectV(ObjPtr, &intv[intn-2], &ip0);
4427                TransformObjectV(ObjPtr, &intv[intn-1], &ip1);
4428                DumpArrow(FP, &ip0, &ip1, aw, ah, aw_spec, ah_spec,
4429                      pen, trans_pat, color_index);
4430             }
4431             break;
4432          }
4433       }
4434    }
4435    if (ObjPtr->ctm != NULL) fprintf(FP, "%s\n", gPsCmd[PS_GRESTORE]);
4436    fprintf(FP, "\n");
4437 }
4438 
4439 /* --------------------- NeedsToCachePolyObj() --------------------- */
4440 
NeedsToCachePolyObj(ObjPtr)4441 int NeedsToCachePolyObj(ObjPtr)
4442    struct ObjRec *ObjPtr;
4443 {
4444    return (ObjPtr->ctm != NULL);
4445 }
4446 
4447 /* --------------------- DrawPolyObj() --------------------- */
4448 
4449 static
MakeCachedPoly(ObjPtr)4450 void MakeCachedPoly(ObjPtr)
4451    struct ObjRec *ObjPtr;
4452 {
4453    int i;
4454    struct PolyRec *poly_ptr=ObjPtr->detail.p;
4455    IntPoint *pv=poly_ptr->vlist, *intvs=NULL, *vs=NULL;
4456    int n=poly_ptr->n, intn=0;
4457 
4458    if (ObjPtr->ctm == NULL) return;
4459    if (poly_ptr->rotated_vlist != NULL) free(poly_ptr->rotated_vlist);
4460    if (poly_ptr->rotated_asvlist != NULL) free(poly_ptr->rotated_asvlist);
4461    poly_ptr->rotated_n = poly_ptr->rotated_asn = 0;
4462    poly_ptr->rotated_vlist = poly_ptr->rotated_asvlist = NULL;
4463 
4464    if (poly_ptr->curved == LT_STRUCT_SPLINE) {
4465       pv = poly_ptr->ssvlist;
4466       n = poly_ptr->ssn;
4467    }
4468    vs = (IntPoint*)malloc((n+1)*sizeof(IntPoint));
4469    if (vs == NULL) FailAllocMessage();
4470    for (i=0; i < n; i++) {
4471       int x, y;
4472 
4473       TransformPointThroughCTM(pv[i].x-ObjPtr->x, pv[i].y-ObjPtr->y,
4474             ObjPtr->ctm, &x, &y);
4475       vs[i].x = x+ObjPtr->x;
4476       vs[i].y = y+ObjPtr->y;
4477    }
4478    vs[n].x = vs[0].x;
4479    vs[n].y = vs[0].y;
4480 
4481    switch (poly_ptr->curved) {
4482    case LT_STRAIGHT:
4483    case LT_SPLINE:
4484       poly_ptr->rotated_vlist = MakeMultiSplinePolyVertex(
4485             poly_ptr->curved, &(poly_ptr->rotated_n), poly_ptr->smooth,
4486             drawOrigX, drawOrigY, n, vs);
4487       break;
4488    case LT_STRUCT_SPLINE:
4489       poly_ptr->rotated_vlist = MakeMultiSplinePolyVertex(
4490             poly_ptr->curved, &(poly_ptr->rotated_n), poly_ptr->ssmooth,
4491             drawOrigX, drawOrigY, n, vs);
4492       break;
4493    case LT_INTSPLINE:
4494       poly_ptr->rotated_vlist = MakeIntSplinePolyVertex(
4495             &(poly_ptr->rotated_n), &(intn), &(intvs),
4496             drawOrigX, drawOrigY, n, vs);
4497       break;
4498    }
4499    poly_ptr->rotated_vlist[poly_ptr->rotated_n].x =
4500          poly_ptr->rotated_vlist[0].x;
4501    poly_ptr->rotated_vlist[poly_ptr->rotated_n].y =
4502          poly_ptr->rotated_vlist[0].y;
4503 
4504    if (poly_ptr->style != LS_PLAIN && !RetractedArrowAttr(ObjPtr) &&
4505          !AutoRetractedArrowAttr(ObjPtr,TRUE)) {
4506       int aw=poly_ptr->aw, dx, dy;
4507       double len, sin, cos;
4508 
4509       if (aw == 0) aw = 1;
4510 
4511       switch (poly_ptr->curved) {
4512       case LT_STRAIGHT:
4513       case LT_SPLINE:
4514       case LT_STRUCT_SPLINE:
4515          dx = vs[1].x - vs[0].x;
4516          dy = vs[1].y - vs[0].y;
4517          if ((poly_ptr->style & LS_LEFT) && (dx != 0 || dy != 0)) {
4518             len = (double)sqrt((double)(((double)dx)*((double)dx) +
4519                   ((double)dy)*((double)dy)));
4520             sin = ((double)dy)/len;
4521             cos = ((double)dx)/len;
4522             vs[0].x = round(vs[0].x+RETREAT*aw*cos);
4523             vs[0].y = round(vs[0].y+RETREAT*aw*sin);
4524          }
4525          dx = vs[n-1].x - vs[n-2].x;
4526          dy = vs[n-1].y - vs[n-2].y;
4527          if ((poly_ptr->style & LS_RIGHT) && (dx != 0 || dy != 0)) {
4528             len = (double)sqrt((double)(((double)dx)*((double)dx) +
4529                   ((double)dy)*((double)dy)));
4530             sin = ((double)dy)/len;
4531             cos = ((double)dx)/len;
4532             vs[n-1].x = round(vs[n-1].x-(RETREAT*aw*cos));
4533             vs[n-1].y = round(vs[n-1].y-(RETREAT*aw*sin));
4534          }
4535          break;
4536       case LT_INTSPLINE:
4537          dx = intvs[1].x - intvs[0].x;
4538          dy = intvs[1].y - intvs[0].y;
4539          if ((poly_ptr->style & LS_LEFT) && (dx != 0 || dy != 0)) {
4540             len = (double)sqrt((double)(((double)dx)*((double)dx) +
4541                   ((double)dy)*((double)dy)));
4542             sin = ((double)dy)/len;
4543             cos = ((double)dx)/len;
4544             intvs[0].x = round(intvs[0].x+RETREAT*aw*cos);
4545             intvs[0].y = round(intvs[0].y+RETREAT*aw*sin);
4546          }
4547          dx = intvs[intn-1].x - intvs[intn-2].x;
4548          dy = intvs[intn-1].y - intvs[intn-2].y;
4549          if ((poly_ptr->style & LS_RIGHT) && (dx != 0 || dy != 0)) {
4550             len = (double)sqrt((double)(((double)dx)*((double)dx) +
4551                   ((double)dy)*((double)dy)));
4552             sin = ((double)dy)/len;
4553             cos = ((double)dx)/len;
4554             intvs[intn-1].x = round(intvs[intn-1].x-(RETREAT*aw*cos));
4555             intvs[intn-1].y = round(intvs[intn-1].y-(RETREAT*aw*sin));
4556          }
4557          break;
4558       }
4559    }
4560    if (poly_ptr->style != LS_PLAIN) {
4561       switch (poly_ptr->curved) {
4562       case LT_STRAIGHT:
4563       case LT_SPLINE:
4564          poly_ptr->rotated_asvlist = MakeMultiSplinePolyVertex(
4565                poly_ptr->curved, &(poly_ptr->rotated_asn), poly_ptr->smooth,
4566                drawOrigX, drawOrigY, n, vs);
4567          break;
4568       case LT_STRUCT_SPLINE:
4569          poly_ptr->rotated_asvlist = MakeMultiSplinePolyVertex(
4570                poly_ptr->curved, &(poly_ptr->rotated_asn), poly_ptr->ssmooth,
4571                drawOrigX, drawOrigY, n, vs);
4572          break;
4573       case LT_INTSPLINE:
4574          poly_ptr->rotated_asvlist = MakeSplinePolyVertex(
4575                0, poly_ptr->curved, &(poly_ptr->rotated_asn),
4576                drawOrigX, drawOrigY, intn, intvs);
4577          break;
4578       }
4579    }
4580    free(vs);
4581    if (intvs != NULL) free(intvs);
4582 }
4583 
4584 static
SetArrowVsForDraw(obj_ptr,retracted_arrow,real_x_off,real_y_off,v0,v1,vnminus2,vnminus1)4585 void SetArrowVsForDraw(obj_ptr, retracted_arrow, real_x_off, real_y_off,
4586       v0, v1, vnminus2, vnminus1)
4587    struct ObjRec *obj_ptr;
4588    int retracted_arrow, real_x_off, real_y_off;
4589    XPoint *v0, *v1, *vnminus2, *vnminus1;
4590 {
4591    struct PolyRec *poly_ptr=obj_ptr->detail.p;
4592    int n=poly_ptr->n;
4593 
4594    if (obj_ptr->ctm == NULL) {
4595       if (poly_ptr->curved != LT_INTSPLINE) {
4596          IntPoint *vs=poly_ptr->vlist;
4597 
4598          if (poly_ptr->curved == LT_STRUCT_SPLINE) {
4599             n = poly_ptr->ssn;
4600             vs = poly_ptr->ssvlist;
4601          }
4602          if (retracted_arrow) {
4603             v0->x = ZOOMED_SIZE(vs[1].x-real_x_off);
4604             v0->y = ZOOMED_SIZE(vs[1].y-real_y_off);
4605             v1->x = ZOOMED_SIZE(vs[2].x-real_x_off);
4606             v1->y = ZOOMED_SIZE(vs[2].y-real_y_off);
4607             vnminus2->x = ZOOMED_SIZE(vs[n-3].x-real_x_off);
4608             vnminus2->y = ZOOMED_SIZE(vs[n-3].y-real_y_off);
4609             vnminus1->x = ZOOMED_SIZE(vs[n-2].x-real_x_off);
4610             vnminus1->y = ZOOMED_SIZE(vs[n-2].y-real_y_off);
4611          } else {
4612             v0->x = ZOOMED_SIZE(vs[0].x-real_x_off);
4613             v0->y = ZOOMED_SIZE(vs[0].y-real_y_off);
4614             v1->x = ZOOMED_SIZE(vs[1].x-real_x_off);
4615             v1->y = ZOOMED_SIZE(vs[1].y-real_y_off);
4616             vnminus2->x = ZOOMED_SIZE(vs[n-2].x-real_x_off);
4617             vnminus2->y = ZOOMED_SIZE(vs[n-2].y-real_y_off);
4618             vnminus1->x = ZOOMED_SIZE(vs[n-1].x-real_x_off);
4619             vnminus1->y = ZOOMED_SIZE(vs[n-1].y-real_y_off);
4620          }
4621       } else {
4622          int intn=poly_ptr->intn;
4623          IntPoint *intvlist=poly_ptr->intvlist;
4624 
4625          if (retracted_arrow) {
4626             int n=poly_ptr->n;
4627             IntPoint *vs=poly_ptr->vlist;
4628 
4629             v0->x = ZOOMED_SIZE(vs[1].x-real_x_off);
4630             v0->y = ZOOMED_SIZE(vs[1].y-real_y_off);
4631             v1->x = ZOOMED_SIZE(intvlist[2].x-real_x_off);
4632             v1->y = ZOOMED_SIZE(intvlist[2].y-real_y_off);
4633             vnminus2->x = ZOOMED_SIZE(intvlist[intn-3].x-real_x_off);
4634             vnminus2->y = ZOOMED_SIZE(intvlist[intn-3].y-real_y_off);
4635             vnminus1->x = ZOOMED_SIZE(vs[n-2].x-real_x_off);
4636             vnminus1->y = ZOOMED_SIZE(vs[n-2].y-real_y_off);
4637          } else {
4638             v0->x = ZOOMED_SIZE(intvlist[0].x-real_x_off);
4639             v0->y = ZOOMED_SIZE(intvlist[0].y-real_y_off);
4640             v1->x = ZOOMED_SIZE(intvlist[1].x-real_x_off);
4641             v1->y = ZOOMED_SIZE(intvlist[1].y-real_y_off);
4642             vnminus2->x = ZOOMED_SIZE(intvlist[intn-2].x-real_x_off);
4643             vnminus2->y = ZOOMED_SIZE(intvlist[intn-2].y-real_y_off);
4644             vnminus1->x = ZOOMED_SIZE(intvlist[intn-1].x-real_x_off);
4645             vnminus1->y = ZOOMED_SIZE(intvlist[intn-1].y-real_y_off);
4646          }
4647       }
4648    } else {
4649       int x, y;
4650 
4651       if (poly_ptr->curved != LT_INTSPLINE) {
4652          IntPoint *vs=poly_ptr->vlist;
4653 
4654          if (poly_ptr->curved == LT_STRUCT_SPLINE) {
4655             n = poly_ptr->ssn;
4656             vs = poly_ptr->ssvlist;
4657          }
4658          if (retracted_arrow) {
4659             TransformPointThroughCTM(vs[1].x-obj_ptr->x, vs[1].y-obj_ptr->y,
4660                   obj_ptr->ctm, &x, &y);
4661             v0->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4662             v0->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4663             TransformPointThroughCTM(vs[2].x-obj_ptr->x, vs[2].y-obj_ptr->y,
4664                   obj_ptr->ctm, &x, &y);
4665             v1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4666             v1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4667             TransformPointThroughCTM(vs[n-3].x-obj_ptr->x, vs[n-3].y-obj_ptr->y,
4668                   obj_ptr->ctm, &x, &y);
4669             vnminus2->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4670             vnminus2->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4671             TransformPointThroughCTM(vs[n-2].x-obj_ptr->x, vs[n-2].y-obj_ptr->y,
4672                   obj_ptr->ctm, &x, &y);
4673             vnminus1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4674             vnminus1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4675          } else {
4676             TransformPointThroughCTM(vs[0].x-obj_ptr->x, vs[0].y-obj_ptr->y,
4677                   obj_ptr->ctm, &x, &y);
4678             v0->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4679             v0->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4680             TransformPointThroughCTM(vs[1].x-obj_ptr->x, vs[1].y-obj_ptr->y,
4681                   obj_ptr->ctm, &x, &y);
4682             v1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4683             v1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4684             TransformPointThroughCTM(vs[n-2].x-obj_ptr->x, vs[n-2].y-obj_ptr->y,
4685                   obj_ptr->ctm, &x, &y);
4686             vnminus2->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4687             vnminus2->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4688             TransformPointThroughCTM(vs[n-1].x-obj_ptr->x, vs[n-1].y-obj_ptr->y,
4689                   obj_ptr->ctm, &x, &y);
4690             vnminus1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4691             vnminus1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4692          }
4693       } else {
4694          int intn=poly_ptr->intn;
4695          IntPoint *intvlist=poly_ptr->intvlist;
4696 
4697          if (retracted_arrow) {
4698             int n=poly_ptr->n;
4699             IntPoint *vs=poly_ptr->vlist;
4700 
4701             TransformPointThroughCTM(vs[1].x-obj_ptr->x, vs[1].y-obj_ptr->y,
4702                   obj_ptr->ctm, &x, &y);
4703             v0->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4704             v0->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4705             TransformPointThroughCTM(intvlist[2].x-obj_ptr->x,
4706                   intvlist[2].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
4707             v1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4708             v1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4709             TransformPointThroughCTM(intvlist[intn-3].x-obj_ptr->x,
4710                   intvlist[intn-3].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
4711             vnminus2->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4712             vnminus2->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4713             TransformPointThroughCTM(vs[n-2].x-obj_ptr->x, vs[n-2].y-obj_ptr->y,
4714                   obj_ptr->ctm, &x, &y);
4715             vnminus1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4716             vnminus1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4717          } else {
4718             TransformPointThroughCTM(intvlist[0].x-obj_ptr->x,
4719                   intvlist[0].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
4720             v0->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4721             v0->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4722             TransformPointThroughCTM(intvlist[1].x-obj_ptr->x,
4723                   intvlist[1].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
4724             v1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4725             v1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4726             TransformPointThroughCTM(intvlist[intn-2].x-obj_ptr->x,
4727                   intvlist[intn-2].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
4728             vnminus2->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4729             vnminus2->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4730             TransformPointThroughCTM(intvlist[intn-1].x-obj_ptr->x,
4731                   intvlist[intn-1].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
4732             vnminus1->x = ZOOMED_SIZE(x+obj_ptr->x-real_x_off);
4733             vnminus1->y = ZOOMED_SIZE(y+obj_ptr->y-real_y_off);
4734          }
4735       }
4736    }
4737 }
4738 
DrawPolyObj(Win,XOff,YOff,ObjPtr)4739 void DrawPolyObj(Win, XOff, YOff, ObjPtr)
4740    Window Win;
4741    int XOff, YOff;
4742    struct ObjRec *ObjPtr;
4743 {
4744    struct PolyRec *poly_ptr=ObjPtr->detail.p;
4745    XPoint *v, tmp_v[4];
4746    XPoint v0, v1, vnminus2, vnminus1;
4747    int trans_pat, pen, width, pixel, fill, n, dash, real_x_off, real_y_off;
4748    int style, aw, ah, num_pts, left_dx, left_dy, right_dx, right_dy;
4749    int retracted_arrow=FALSE;
4750    short tmps;
4751    double len, sin, cos;
4752    XGCValues values;
4753 
4754    trans_pat = ObjPtr->trans_pat;
4755    n = poly_ptr->n;
4756    fill = poly_ptr->fill;
4757    width = poly_ptr->width;
4758    aw = poly_ptr->aw;
4759    ah = poly_ptr->ah;
4760    pen = poly_ptr->pen;
4761    style = poly_ptr->style;
4762    dash = poly_ptr->dash;
4763    pixel = colorPixels[ObjPtr->color];
4764 
4765    if (NeedsToCachePolyObj(ObjPtr) && poly_ptr->rotated_vlist==NULL) {
4766       MakeCachedPoly(ObjPtr);
4767    }
4768    if (userDisableRedraw) return;
4769 
4770    if ((fill == NONEPAT || (trans_pat && fill == BACKPAT)) &&
4771          (pen == NONEPAT || (trans_pat && pen == BACKPAT))) {
4772       return;
4773    }
4774    real_x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
4775    real_y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
4776 
4777    v = poly_ptr->svlist;
4778    num_pts = poly_ptr->sn;
4779 
4780    if (v != NULL) {
4781       v[num_pts].x = v[0].x;
4782       v[num_pts].y = v[0].y;
4783    }
4784    if (fill != NONEPAT) {
4785       values.foreground = GetDrawingBgPixel(fill, pixel);
4786       values.function = GXcopy;
4787       values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
4788       values.stipple = patPixmap[fill];
4789       XChangeGC(mainDisplay, drawGC,
4790             GCForeground | GCFunction | GCFillStyle | GCStipple, &values);
4791       if (ObjPtr->ctm == NULL) {
4792          XFillPolygon(mainDisplay, Win, drawGC, v, num_pts+1, Complex,
4793                CoordModeOrigin);
4794       } else {
4795          XFillPolygon(mainDisplay, Win, drawGC, poly_ptr->rotated_vlist,
4796                poly_ptr->rotated_n+1, Complex, CoordModeOrigin);
4797       }
4798    }
4799 
4800    if (pen == NONEPAT || (pen == BACKPAT && trans_pat)) return;
4801 
4802    retracted_arrow = (RetractedArrowAttr(ObjPtr) ||
4803          AutoRetractedArrowAttr(ObjPtr, TRUE));
4804 
4805    SetArrowVsForDraw(ObjPtr, retracted_arrow, real_x_off, real_y_off,
4806          &v0, &v1, &vnminus2, &vnminus1);
4807 
4808    aw = ZOOMED_SIZE(aw); if (aw == 0) aw = 1;
4809    ah = ZOOMED_SIZE(ah); if (ah == 0) ah = 1;
4810 
4811    values.foreground = GetDrawingBgPixel(pen, pixel);
4812    values.function = GXcopy;
4813    values.fill_style = (trans_pat ? FillStippled : FillOpaqueStippled);
4814    values.stipple = patPixmap[pen];
4815    values.line_width = ZOOMED_SIZE(width);
4816 #ifdef NO_THIN_LINE
4817    if (values.line_width < 1) values.line_width = 1;
4818 #endif
4819    values.join_style = JoinBevel;
4820    if (dash != 0) {
4821       XSetDashes(mainDisplay, drawGC, 0, dashList[dash],
4822             dashListLength[dash]);
4823       values.line_style = LineOnOffDash;
4824    } else {
4825       values.line_style = LineSolid;
4826    }
4827    XChangeGC(mainDisplay, drawGC,
4828          GCForeground | GCFunction | GCFillStyle | GCStipple | GCLineWidth |
4829          GCLineStyle | GCJoinStyle, &values);
4830 
4831    left_dx = v1.x - v0.x;
4832    left_dy = v1.y - v0.y;
4833 
4834    if ((style & LS_LEFT) && (left_dx != 0 || left_dy != 0)) {
4835       /* adjust the first point */
4836       len = (double)sqrt((double)(((double)left_dx)*((double)left_dx) +
4837             ((double)left_dy)*((double)left_dy)));
4838       sin = ((double)left_dy)/len;
4839       cos = ((double)left_dx)/len;
4840 
4841       tmp_v[0].x = tmp_v[3].x = v0.x;
4842       tmp_v[0].y = tmp_v[3].y = v0.y;
4843       tmps = round(v0.x + aw*cos - ah*sin); tmp_v[1].x = tmps;
4844       tmps = round(v0.y + aw*sin + ah*cos); tmp_v[1].y = tmps;
4845       tmps = round(v0.x + aw*cos + ah*sin); tmp_v[2].x = tmps;
4846       tmps = round(v0.y + aw*sin - ah*cos); tmp_v[2].y = tmps;
4847 
4848       XFillPolygon(mainDisplay, Win, drawGC, tmp_v, 4, Convex,
4849             CoordModeOrigin);
4850    }
4851    right_dx = vnminus1.x - vnminus2.x;
4852    right_dy = vnminus1.y - vnminus2.y;
4853 
4854    if ((style & LS_RIGHT) && (right_dx != 0 || right_dy != 0)) {
4855       /* adjust the last point */
4856       len = (double)sqrt((double)(((double)right_dx)*((double)right_dx) +
4857             ((double)right_dy)*((double)right_dy)));
4858       sin = ((double)right_dy)/len;
4859       cos = ((double)right_dx)/len;
4860 
4861       tmp_v[0].x = tmp_v[3].x = vnminus1.x;
4862       tmp_v[0].y = tmp_v[3].y = vnminus1.y;
4863       tmps = round(vnminus1.x - aw*cos + ah*sin); tmp_v[1].x = tmps;
4864       tmps = round(vnminus1.y - aw*sin - ah*cos); tmp_v[1].y = tmps;
4865       tmps = round(vnminus1.x - aw*cos - ah*sin); tmp_v[2].x = tmps;
4866       tmps = round(vnminus1.y - aw*sin + ah*cos); tmp_v[2].y = tmps;
4867 
4868       XFillPolygon(mainDisplay, Win, drawGC, tmp_v, 4, Convex,
4869             CoordModeOrigin);
4870    }
4871    if (style != LS_PLAIN) {
4872       if (ObjPtr->ctm == NULL) {
4873          MyDrawLines(mainDisplay, Win, drawGC, poly_ptr->asvlist,
4874                poly_ptr->asn);
4875       } else {
4876          MyDrawLines(mainDisplay, Win, drawGC, poly_ptr->rotated_asvlist,
4877                poly_ptr->rotated_asn);
4878       }
4879    } else {
4880       int draw_zero_length_poly=FALSE;
4881 
4882 #ifndef DONT_DRAW_ZERO_LENGTH_POLY_AS_DOT
4883       if (ObjPtr->ctm == NULL) {
4884          if (num_pts == 2 && v[0].x == v[1].x && v[0].y == v[1].y) {
4885             draw_zero_length_poly = TRUE;
4886          }
4887       } else {
4888          if (poly_ptr->rotated_n == 2 &&
4889                poly_ptr->rotated_vlist[0].x == poly_ptr->rotated_vlist[1].x &&
4890                poly_ptr->rotated_vlist[0].y == poly_ptr->rotated_vlist[1].y) {
4891             draw_zero_length_poly = TRUE;
4892          }
4893       }
4894 #endif /* ~DONT_DRAW_ZERO_LENGTH_POLY_AS_DOT */
4895       if (ObjPtr->ctm == NULL) {
4896          if (draw_zero_length_poly) {
4897             values.cap_style = CapRound;
4898             XChangeGC(mainDisplay, drawGC, GCCapStyle, &values);
4899          }
4900          MyDrawLines(mainDisplay, Win, drawGC, v, num_pts);
4901          if (draw_zero_length_poly) {
4902             values.cap_style = CapButt;
4903             XChangeGC(mainDisplay, drawGC, GCCapStyle, &values);
4904          }
4905       } else {
4906          if (draw_zero_length_poly) {
4907             values.cap_style = CapRound;
4908             XChangeGC(mainDisplay, drawGC, GCCapStyle, &values);
4909          }
4910          MyDrawLines(mainDisplay, Win, drawGC, poly_ptr->rotated_vlist,
4911                poly_ptr->rotated_n);
4912          if (draw_zero_length_poly) {
4913             values.cap_style = CapButt;
4914             XChangeGC(mainDisplay, drawGC, GCCapStyle, &values);
4915          }
4916       }
4917    }
4918    values.join_style = JoinMiter;
4919    XChangeGC(mainDisplay, drawGC, GCJoinStyle, &values);
4920 }
4921 
4922 /* --------------------- SaveSmoothHinge() --------------------- */
4923 
4924 static char hexValue[]="0123456789abcdef";
4925 
SaveSmoothHinge(FP,Curved,NumPts,Smooth)4926 void SaveSmoothHinge(FP, Curved, NumPts, Smooth)
4927    FILE *FP;
4928    int Curved, NumPts;
4929    char *Smooth;
4930 {
4931    register int nibble_count=0, bit_count=0, data=0, j;
4932 
4933    if (Curved == LT_INTSPLINE || Smooth == NULL) return;
4934 
4935    for (j=0; j < NumPts; j++) {
4936       data = (Smooth[j] ? (data<<1) | 1 : (data<<1));
4937 
4938       if (++bit_count == 4) {
4939          if (nibble_count++ == 64) {
4940             nibble_count = 1;
4941             if (fprintf(FP, "\n     ") == EOF) writeFileFailed = TRUE;
4942          }
4943          if (fprintf(FP, "%c", hexValue[data]) == EOF) {
4944             writeFileFailed = TRUE;
4945          }
4946          bit_count = 0;
4947          data = 0;
4948       }
4949    }
4950    if ((NumPts & 0x3) != 0) {
4951       data <<= (4 - (NumPts & 0x3));
4952       if (nibble_count++ == 64) {
4953          nibble_count = 1;
4954          if (fprintf(FP, "\n     ") == EOF) writeFileFailed = TRUE;
4955       }
4956       if (fprintf(FP, "%c", hexValue[data]) == EOF) writeFileFailed = TRUE;
4957    }
4958 }
4959 
4960 /* --------------------- SavePolyObj() --------------------- */
4961 
4962 static
SaveArrowSpec(FP,arrow_style,aw,ah,aindent,aw_spec,ah_spec,aindent_spec)4963 void SaveArrowSpec(FP, arrow_style, aw, ah, aindent, aw_spec, ah_spec,
4964       aindent_spec)
4965    FILE *FP;
4966    int arrow_style, aw, ah, aindent;
4967    char *aw_spec, *ah_spec, *aindent_spec;
4968 {
4969    if (fprintf(FP, "%1d,%1d,%1d,%1d,'%s','%s','%s'",
4970          arrow_style, aw, ah, aindent, aw_spec, ah_spec, aindent_spec) == EOF) {
4971       writeFileFailed = TRUE;
4972    }
4973 }
4974 
SavePolyObj(FP,ObjPtr)4975 void SavePolyObj(FP, ObjPtr)
4976    FILE *FP;
4977    struct ObjRec *ObjPtr;
4978 {
4979    register int i, n;
4980    int count, line_cap=LCAP_BUTT;
4981    struct PolyRec *poly_ptr=ObjPtr->detail.p;
4982 
4983    n = poly_ptr->n;
4984    if (fprintf(FP, "poly('%s','',%1d,[\n\t",
4985          colorMenuItems[ObjPtr->color], poly_ptr->n) == EOF) {
4986       writeFileFailed = TRUE;
4987    }
4988    for (i=0, count = 0; i < n-1; i++) {
4989       if (fprintf(FP, "%1d,%1d,", poly_ptr->vlist[i].x,
4990             poly_ptr->vlist[i].y) == EOF) {
4991          writeFileFailed = TRUE;
4992       }
4993       if (++count == 8) {
4994          count = 0;
4995          if (fprintf(FP, "\n\t") == EOF) writeFileFailed = TRUE;
4996       }
4997    }
4998    if (fprintf(FP, "%1d,%1d],", poly_ptr->vlist[n-1].x,
4999          poly_ptr->vlist[n-1].y) == EOF) {
5000       writeFileFailed = TRUE;
5001    }
5002    if (fprintf(FP,
5003          "%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,'%s',%1d,%1d,",
5004          poly_ptr->style, poly_ptr->width, poly_ptr->pen, ObjPtr->id,
5005          poly_ptr->curved, poly_ptr->fill, poly_ptr->dash, ObjPtr->rotation,
5006          ObjPtr->locked, ObjPtr->ctm!=NULL, ObjPtr->invisible,
5007          poly_ptr->width_spec, ObjPtr->trans_pat, line_cap) == EOF) {
5008       writeFileFailed = TRUE;
5009    }
5010    if (fprintf(FP, "\n    \"") == EOF) writeFileFailed = TRUE;
5011    SaveSmoothHinge(FP, poly_ptr->curved, poly_ptr->n, poly_ptr->smooth);
5012    if (fprintf(FP, "\",") == EOF) writeFileFailed = TRUE;
5013 
5014    /* save an empty spline tension spec */
5015    if (fprintf(FP, "\"\",") == EOF) writeFileFailed = TRUE;
5016    /* save the left arrow spec */
5017    if (fprintf(FP, "[\n    ") == EOF) writeFileFailed = TRUE;
5018    SaveArrowSpec(FP, ASTY_COMPAT, poly_ptr->aw, poly_ptr->ah, 0,
5019          poly_ptr->aw_spec, poly_ptr->ah_spec, "0");
5020    if (fprintf(FP, "],[") == EOF) writeFileFailed = TRUE;
5021    /* save the right arrow spec */
5022    SaveArrowSpec(FP, ASTY_COMPAT, poly_ptr->aw, poly_ptr->ah, 0,
5023          poly_ptr->aw_spec, poly_ptr->ah_spec, "0");
5024    if (fprintf(FP, "],") == EOF) writeFileFailed = TRUE;
5025 
5026    if (ObjPtr->ctm != NULL && fprintf(FP,
5027          "[\n\t%1d,%1d,%1d,%1d,%1d,%1d,%g,%g,%g,%g,%1d,%1d],",
5028          ObjPtr->x, ObjPtr->y,
5029          ObjPtr->orig_obbox.ltx, ObjPtr->orig_obbox.lty,
5030          ObjPtr->orig_obbox.rbx, ObjPtr->orig_obbox.rby,
5031          ObjPtr->ctm->m[CTM_SX], ObjPtr->ctm->m[CTM_SIN],
5032          ObjPtr->ctm->m[CTM_MSIN], ObjPtr->ctm->m[CTM_SY],
5033          ObjPtr->ctm->t[CTM_TX], ObjPtr->ctm->t[CTM_TY]) == EOF) {
5034       writeFileFailed = TRUE;
5035    }
5036    if (serializingFile) SaveCreatorID(FP, ObjPtr, "    ");
5037    SaveAttrs(FP, ObjPtr->lattr);
5038    if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
5039 }
5040 
5041 /* --------------------- ReadSmoothHinge() --------------------- */
5042 
ReadSmoothHinge(FP,Curved,NumPts,Smooth)5043 int ReadSmoothHinge(FP, Curved, NumPts, Smooth)
5044    FILE *FP;
5045    int Curved, NumPts;
5046    char *Smooth;
5047 {
5048    int num_nibbles=NumPts>>2, nibble_count=0, bit_count=0, j, k;
5049    char *c_ptr, inbuf[MAXSTRING+1];
5050 
5051    if ((NumPts & 0x3) != 0) num_nibbles++;
5052    (void)fgets(inbuf, MAXSTRING, FP);
5053    scanLineNum++;
5054    if (Curved == LT_INTSPLINE || Smooth == NULL) return TRUE;
5055    if ((c_ptr=strchr(inbuf, '"')) == NULL) {
5056       (void)sprintf(gszMsgBox, TgLoadString(STID_INVALID_SMOOTHHINGE_SPEC_POLY),
5057             scanFileName, scanLineNum);
5058       if (PRTGIF) {
5059          fprintf(stderr, "%s\n", gszMsgBox);
5060       } else {
5061          Msg(gszMsgBox);
5062       }
5063       return FALSE;
5064    }
5065    c_ptr++;
5066    for (j=0; *c_ptr != '"' && j < num_nibbles; j++) {
5067       int data=0;
5068 
5069       if (nibble_count++ == 64) {
5070          (void)fgets(inbuf, MAXSTRING, FP);
5071          scanLineNum++;
5072          for (c_ptr=inbuf; *c_ptr == ' '; c_ptr++) ;
5073          nibble_count = 1;
5074       }
5075       if (*c_ptr >= '0' && *c_ptr <= '9') {
5076          data = (int)(*c_ptr++) - (int)('0');
5077       } else if (*c_ptr >= 'a' && *c_ptr <= 'f') {
5078          data = (int)(*c_ptr++) - (int)('a') + 10;
5079       }
5080       for (k = 0; k < 4; k++) {
5081          if (bit_count++ == NumPts) break;
5082 
5083          Smooth[(j<<2)+k] = (data & (1<<(3-k)) ? TRUE : FALSE);
5084       }
5085    }
5086    /*
5087     * Should be reading spline tension here.  But this is not implemented, yet.
5088     */
5089    return TRUE;
5090 }
5091 
5092 /* --------------------- ReadPolyObj() --------------------- */
5093 
ReadPolyObj(FP,Inbuf,ObjPtr)5094 void ReadPolyObj(FP, Inbuf, ObjPtr)
5095    FILE *FP;
5096    char *Inbuf;
5097    struct ObjRec **ObjPtr;
5098 {
5099    register int i;
5100    struct PolyRec *poly_ptr;
5101    IntPoint *v;
5102    char color_str[40], bg_color_str[40], *s, inbuf[MAXSTRING+1];
5103    char width_spec[40], aw_spec[40], ah_spec[40];
5104    int num_pts, ltx=0, lty=0, rbx=0, rby=0, x, y, id=0;
5105    int initialized, rotation, count, new_alloc, line_cap=LCAP_BUTT;
5106    int style, width=0, pen, curved, fill, dash, locked=FALSE, trans_pat=FALSE;
5107    int aw=origArrowHeadW[6], ah=origArrowHeadH[6], arrow_style=ASTY_COMPAT;
5108    char *smooth=NULL;
5109    int real_x=0, real_y=0, transformed=FALSE, invisible=FALSE;
5110    struct XfrmMtrxRec *ctm=NULL;
5111    struct BBRec orig_obbox;
5112 
5113    *ObjPtr = NULL;
5114 
5115    s = FindChar((int)'(', Inbuf);
5116    s = ParseStr(s, (int)',', color_str, sizeof(color_str));
5117    if (fileVersion >= 37) {
5118       s = ParseStr(s, (int)',', bg_color_str, sizeof(bg_color_str));
5119    }
5120    InitScan(s, "\t\n, []");
5121 
5122    if (GETINT("poly", num_pts, "number of points") == INVALID) {
5123       return;
5124    }
5125    if (num_pts <= 0) {
5126       (void)sprintf(gszMsgBox, TgLoadString(STID_INVALID_NUM_PTS_IN_POLY),
5127             scanFileName, scanLineNum);
5128       if (PRTGIF) {
5129          fprintf(stderr, "%s\n", gszMsgBox);
5130       } else {
5131          Msg(gszMsgBox);
5132       }
5133       return;
5134    }
5135 
5136    *ObjPtr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
5137    if (*ObjPtr == NULL) FailAllocMessage();
5138    memset(*ObjPtr, 0, sizeof(struct ObjRec));
5139    poly_ptr = (struct PolyRec *)malloc(sizeof(struct PolyRec));
5140    if (poly_ptr == NULL) FailAllocMessage();
5141    memset(poly_ptr, 0, sizeof(struct PolyRec));
5142 
5143    if (num_pts == 1) {
5144       v = (IntPoint*)malloc(4*sizeof(IntPoint));
5145       if (v == NULL) FailAllocMessage();
5146       memset(v, 0, 4*sizeof(IntPoint));
5147       smooth = (char*)malloc(4*sizeof(char));
5148       if (smooth == NULL) FailAllocMessage();
5149       memset(smooth, 0, 4*sizeof(char));
5150    } else {
5151       v = (IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
5152       if (v == NULL) FailAllocMessage();
5153       memset(v, 0, (num_pts+1)*sizeof(IntPoint));
5154       smooth = (char*)malloc((num_pts+1)*sizeof(char));
5155       if (smooth == NULL) FailAllocMessage();
5156       memset(smooth, 0, (num_pts+1)*sizeof(char));
5157    }
5158 
5159    initialized = FALSE;
5160 
5161    *width_spec = *aw_spec = *ah_spec = '\0';
5162    if (fileVersion <= 13) {
5163       for (i=0; i < num_pts; i++) {
5164          if (GETINT("poly", x, "x") == INVALID ||
5165              GETINT("poly", y, "y") == INVALID) {
5166             free(*ObjPtr);
5167             free(poly_ptr);
5168             free(v);
5169             *ObjPtr = NULL;
5170             return;
5171          }
5172          v[i].x = x; v[i].y = y;
5173          if (!initialized) {
5174             initialized = TRUE;
5175             ltx = rbx = x; lty = rby = y;
5176          } else {
5177             if (x < ltx) ltx = x; if (y < lty) lty = y;
5178             if (x > rbx) rbx = x; if (y > rby) rby = y;
5179          }
5180       }
5181    } else {
5182       (void)fgets(inbuf, MAXSTRING, FP);
5183       scanLineNum++;
5184       s = inbuf;
5185       InitScan(s, "\t\n, []");
5186       for (i=0, count = 0; i < num_pts; i++) {
5187          if (GETINT("poly", x, "x") == INVALID ||
5188              GETINT("poly", y, "y") == INVALID) {
5189             free(*ObjPtr);
5190             free(poly_ptr);
5191             free(v);
5192             *ObjPtr = NULL;
5193             return;
5194          }
5195          v[i].x = x; v[i].y = y;
5196          if (!initialized) {
5197             initialized = TRUE;
5198             ltx = rbx = x; lty = rby = y;
5199          } else {
5200             if (x < ltx) ltx = x; if (y < lty) lty = y;
5201             if (x > rbx) rbx = x; if (y > rby) rby = y;
5202          }
5203          if (++count == 8 && i != num_pts-1) {
5204             count = 0;
5205             (void)fgets(inbuf, MAXSTRING, FP);
5206             scanLineNum++;
5207             s = inbuf;
5208             InitScan(s, "\t\n, []");
5209          }
5210       }
5211    }
5212 
5213    if (num_pts == 1) {
5214       sprintf(gszMsgBox, TgLoadCachedString(CSTID_SINGLE_PT_POLY_CONVERTED),
5215             v[0].x, v[0].y);
5216       if (PRTGIF) {
5217          fprintf(stderr, "%s\n", gszMsgBox);
5218       } else {
5219          Msg(gszMsgBox);
5220       }
5221       v[1].x = v[0].x;
5222       v[1].y = v[0].y;
5223       num_pts = 2;
5224    }
5225 
5226    poly_ptr->n = num_pts;
5227 
5228    dash = 0;
5229    rotation = 0;
5230    if (fileVersion == INVALID) {
5231       if (GETINT("poly", style,    "style") == INVALID ||
5232           GETINT("poly", width,    "width") == INVALID ||
5233           GETINT("poly", pen,      "pen") == INVALID) {
5234          free(*ObjPtr);
5235          free(poly_ptr);
5236          free(v);
5237          *ObjPtr = NULL;
5238          return;
5239       }
5240       id = objId++;
5241       fill = NONEPAT;
5242       if (width == LINE_CURVED) {
5243          width = 0;
5244          curved = TRUE;
5245       } else {
5246          curved = FALSE;
5247       }
5248       switch (width) {
5249       case 1: width = 3; break;
5250       case 2: width = 6; break;
5251       }
5252    } else if (fileVersion <= 3) {
5253       if (GETINT("poly", style,    "style") == INVALID ||
5254           GETINT("poly", width,    "width") == INVALID ||
5255           GETINT("poly", pen,      "pen") == INVALID ||
5256           GETINT("poly", id,       "id") == INVALID) {
5257          free(*ObjPtr);
5258          free(poly_ptr);
5259          free(v);
5260          *ObjPtr = NULL;
5261          return;
5262       }
5263       if (id >= objId) objId = id+1;
5264       fill = NONEPAT;
5265       if (width == LINE_CURVED) {
5266          width = 0;
5267          curved = TRUE;
5268       } else {
5269          curved = FALSE;
5270       }
5271       switch (width) {
5272       case 1: width = 3; break;
5273       case 2: width = 6; break;
5274       }
5275    } else if (fileVersion <= 4) {
5276       if (GETINT("poly", style,    "style") == INVALID ||
5277           GETINT("poly", width,    "width") == INVALID ||
5278           GETINT("poly", pen,      "pen") == INVALID ||
5279           GETINT("poly", id,       "id") == INVALID ||
5280           GETINT("poly", curved,   "curved") == INVALID) {
5281          free(*ObjPtr);
5282          free(poly_ptr);
5283          free(v);
5284          *ObjPtr = NULL;
5285          return;
5286       }
5287       if (id >= objId) objId = id+1;
5288       fill = NONEPAT;
5289       switch (width) {
5290       case 1: width = 3; break;
5291       case 2: width = 6; break;
5292       }
5293    } else if (fileVersion <= 5) {
5294       if (GETINT("poly", style,    "style") == INVALID ||
5295           GETINT("poly", width,    "width") == INVALID ||
5296           GETINT("poly", pen,      "pen") == INVALID ||
5297           GETINT("poly", id,       "id") == INVALID ||
5298           GETINT("poly", curved,   "curved") == INVALID ||
5299           GETINT("poly", fill,     "fill") == INVALID) {
5300          free(*ObjPtr);
5301          free(poly_ptr);
5302          free(v);
5303          *ObjPtr = NULL;
5304          return;
5305       }
5306       if (id >= objId) objId = id+1;
5307       switch (width) {
5308       case 1: width = 3; break;
5309       case 2: width = 6; break;
5310       }
5311    } else if (fileVersion <= 8) {
5312       if (GETINT("poly", style,    "style") == INVALID ||
5313           GETINT("poly", width,    "width") == INVALID ||
5314           GETINT("poly", pen,      "pen") == INVALID ||
5315           GETINT("poly", id,       "id") == INVALID ||
5316           GETINT("poly", curved,   "curved") == INVALID ||
5317           GETINT("poly", fill,     "fill") == INVALID) {
5318          free(*ObjPtr);
5319          free(poly_ptr);
5320          free(v);
5321          *ObjPtr = NULL;
5322          return;
5323       }
5324       if (id >= objId) objId = id+1;
5325    } else if (fileVersion <= 13) {
5326       if (GETINT("poly", style,    "style") == INVALID ||
5327           GETINT("poly", width,    "width") == INVALID ||
5328           GETINT("poly", pen,      "pen") == INVALID ||
5329           GETINT("poly", id,       "id") == INVALID ||
5330           GETINT("poly", curved,   "curved") == INVALID ||
5331           GETINT("poly", fill,     "fill") == INVALID ||
5332           GETINT("poly", dash,     "dash") == INVALID) {
5333          free(*ObjPtr);
5334          free(poly_ptr);
5335          free(v);
5336          *ObjPtr = NULL;
5337          return;
5338       }
5339       if (id >= objId) objId = id+1;
5340    } else if (fileVersion <= 16) {
5341       if (GETINT("poly", style,    "style") == INVALID ||
5342           GETINT("poly", width,    "width") == INVALID ||
5343           GETINT("poly", pen,      "pen") == INVALID ||
5344           GETINT("poly", id,       "id") == INVALID ||
5345           GETINT("poly", curved,   "curved") == INVALID ||
5346           GETINT("poly", fill,     "fill") == INVALID ||
5347           GETINT("poly", dash,     "dash") == INVALID ||
5348           GETINT("poly", rotation, "rotation") == INVALID) {
5349          free(*ObjPtr);
5350          free(poly_ptr);
5351          free(v);
5352          *ObjPtr = NULL;
5353          return;
5354       }
5355       if (id >= objId) objId = id+1;
5356    } else if (fileVersion <= 25) {
5357       if (GETINT("poly", style,    "style") == INVALID ||
5358           GETINT("poly", width,    "width") == INVALID ||
5359           GETINT("poly", pen,      "pen") == INVALID ||
5360           GETINT("poly", id,       "id") == INVALID ||
5361           GETINT("poly", curved,   "curved") == INVALID ||
5362           GETINT("poly", fill,     "fill") == INVALID ||
5363           GETINT("poly", dash,     "dash") == INVALID ||
5364           GETINT("poly", rotation, "rotation") == INVALID ||
5365           GETINT("poly", aw,       "arrow head width") == INVALID ||
5366           GETINT("poly", ah,       "arrow head height") == INVALID) {
5367          free(*ObjPtr);
5368          free(poly_ptr);
5369          free(v);
5370          *ObjPtr = NULL;
5371          return;
5372       }
5373       if (id >= objId) objId = id+1;
5374    } else if (fileVersion <= 32) {
5375       if (GETINT("poly", style,    "style") == INVALID ||
5376           GETINT("poly", width,    "width") == INVALID ||
5377           GETINT("poly", pen,      "pen") == INVALID ||
5378           GETINT("poly", id,       "id") == INVALID ||
5379           GETINT("poly", curved,   "curved") == INVALID ||
5380           GETINT("poly", fill,     "fill") == INVALID ||
5381           GETINT("poly", dash,     "dash") == INVALID ||
5382           GETINT("poly", rotation, "rotation") == INVALID ||
5383           GETINT("poly", aw,       "arrow head width") == INVALID ||
5384           GETINT("poly", ah,       "arrow head height") == INVALID ||
5385           GETINT("poly", locked,   "locked") == INVALID) {
5386          free(*ObjPtr);
5387          free(poly_ptr);
5388          free(v);
5389          *ObjPtr = NULL;
5390          return;
5391       }
5392       if (id >= objId) objId = id+1;
5393    } else if (fileVersion <= 34) {
5394       if (GETINT("poly", style,       "style") == INVALID ||
5395           GETINT("poly", width,       "width") == INVALID ||
5396           GETINT("poly", pen,         "pen") == INVALID ||
5397           GETINT("poly", id,          "id") == INVALID ||
5398           GETINT("poly", curved,      "curved") == INVALID ||
5399           GETINT("poly", fill,        "fill") == INVALID ||
5400           GETINT("poly", dash,        "dash") == INVALID ||
5401           GETINT("poly", rotation,    "rotation") == INVALID ||
5402           GETINT("poly", aw,          "arrow head width") == INVALID ||
5403           GETINT("poly", ah,          "arrow head height") == INVALID ||
5404           GETINT("poly", locked,      "locked") == INVALID ||
5405           GETINT("poly", transformed, "transformed") == INVALID ||
5406           GETINT("poly", invisible,   "invisible") == INVALID ||
5407           GETSTR("poly", width_spec,  "width_spec") == INVALID ||
5408           GETSTR("poly", aw_spec,     "aw_spec") == INVALID ||
5409           GETSTR("poly", ah_spec,     "ah_spec") == INVALID) {
5410          free(*ObjPtr);
5411          free(poly_ptr);
5412          free(v);
5413          *ObjPtr = NULL;
5414          return;
5415       }
5416       if (id >= objId) objId = id+1;
5417       UtilRemoveQuotes(width_spec);
5418       UtilRemoveQuotes(aw_spec);
5419       UtilRemoveQuotes(ah_spec);
5420    } else if (fileVersion <= 36) {
5421       if (GETINT("poly", style,       "style") == INVALID ||
5422           GETINT("poly", width,       "width") == INVALID ||
5423           GETINT("poly", pen,         "pen") == INVALID ||
5424           GETINT("poly", id,          "id") == INVALID ||
5425           GETINT("poly", curved,      "curved") == INVALID ||
5426           GETINT("poly", fill,        "fill") == INVALID ||
5427           GETINT("poly", dash,        "dash") == INVALID ||
5428           GETINT("poly", rotation,    "rotation") == INVALID ||
5429           GETINT("poly", aw,          "arrow head width") == INVALID ||
5430           GETINT("poly", ah,          "arrow head height") == INVALID ||
5431           GETINT("poly", locked,      "locked") == INVALID ||
5432           GETINT("poly", transformed, "transformed") == INVALID ||
5433           GETINT("poly", invisible,   "invisible") == INVALID ||
5434           GETSTR("poly", width_spec,  "width_spec") == INVALID ||
5435           GETSTR("poly", aw_spec,     "aw_spec") == INVALID ||
5436           GETSTR("poly", ah_spec,     "ah_spec") == INVALID ||
5437           GETINT("poly", trans_pat,   "trans_pat") == INVALID) {
5438          free(*ObjPtr);
5439          free(poly_ptr);
5440          free(v);
5441          *ObjPtr = NULL;
5442          return;
5443       }
5444       if (id >= objId) objId = id+1;
5445       UtilRemoveQuotes(width_spec);
5446       UtilRemoveQuotes(aw_spec);
5447       UtilRemoveQuotes(ah_spec);
5448    } else {
5449       if (GETINT("poly", style,       "style") == INVALID ||
5450           GETINT("poly", width,       "width") == INVALID ||
5451           GETINT("poly", pen,         "pen") == INVALID ||
5452           GETINT("poly", id,          "id") == INVALID ||
5453           GETINT("poly", curved,      "curved") == INVALID ||
5454           GETINT("poly", fill,        "fill") == INVALID ||
5455           GETINT("poly", dash,        "dash") == INVALID ||
5456           GETINT("poly", rotation,    "rotation") == INVALID ||
5457           GETINT("poly", locked,      "locked") == INVALID ||
5458           GETINT("poly", transformed, "transformed") == INVALID ||
5459           GETINT("poly", invisible,   "invisible") == INVALID ||
5460           GETSTR("poly", width_spec,  "width_spec") == INVALID ||
5461           GETINT("poly", trans_pat,   "trans_pat") == INVALID ||
5462           GETINT("poly", line_cap,    "line_cap") == INVALID) {
5463          free(*ObjPtr);
5464          free(poly_ptr);
5465          free(v);
5466          *ObjPtr = NULL;
5467          return;
5468       }
5469       if (id >= objId) objId = id+1;
5470       UtilRemoveQuotes(width_spec);
5471       UtilRemoveQuotes(aw_spec);
5472       UtilRemoveQuotes(ah_spec);
5473       if (line_cap != LCAP_BUTT) {
5474          /* does not support other linecaps, yet */
5475          line_cap = LCAP_BUTT;
5476       }
5477    }
5478 
5479    if (fileVersion <= 16 && width <= 6) {
5480       aw = origArrowHeadW[width];
5481       ah = origArrowHeadH[width];
5482       width = origWidthOfLine[width];
5483    }
5484    if (curved == LT_INTSPLINE && smooth != NULL) {
5485       free(smooth);
5486       smooth = NULL;
5487    }
5488    if (fileVersion <= 30) {
5489       switch (curved) {
5490       case LT_STRAIGHT:
5491          for (i=0; i < num_pts; i++) smooth[i] = FALSE;
5492          break;
5493       case LT_SPLINE:
5494          smooth[0] = smooth[num_pts-1] = FALSE;
5495          for (i=1; i < num_pts-1; i++) smooth[i] = TRUE;
5496          break;
5497       }
5498    } else if (!ReadSmoothHinge(FP, curved, num_pts, smooth)) {
5499       free(*ObjPtr);
5500       free(poly_ptr);
5501       free(v);
5502       *ObjPtr = NULL;
5503       return;
5504    }
5505    if (smooth != NULL && (smooth[0] != FALSE || smooth[num_pts-1] != FALSE)) {
5506       smooth[0] = smooth[num_pts-1] = FALSE;
5507       SetFileModified(TRUE);
5508 
5509       sprintf(gszMsgBox, TgLoadCachedString(CSTID_BAD_SMOOTHHINGE_POLY_FIXED));
5510       if (PRTGIF) {
5511          fprintf(stderr, "%s\n", gszMsgBox);
5512       } else {
5513          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
5514       }
5515    }
5516    if (fileVersion >= 37) {
5517       int aindent=0;
5518       char aindent_spec[40];
5519 
5520       (void)fgets(inbuf, MAXSTRING, FP);
5521       scanLineNum++;
5522       InitScan(inbuf, "\t\n, []");
5523 
5524       /* for now, they both spec are identical */
5525       if (GETINT("poly", arrow_style,  "arrow_style") == INVALID ||
5526           GETINT("poly", aw,           "aw") == INVALID ||
5527           GETINT("poly", ah,           "ah") == INVALID ||
5528           GETINT("poly", aindent,      "aindent") == INVALID ||
5529           GETSTR("poly", aw_spec,      "aw_spec") == INVALID ||
5530           GETSTR("poly", ah_spec,      "ah_spec") == INVALID ||
5531           GETSTR("poly", aindent_spec, "aindent_spec") == INVALID ||
5532           GETINT("poly", arrow_style,  "arrow_style") == INVALID ||
5533           GETINT("poly", aw,           "aw") == INVALID ||
5534           GETINT("poly", ah,           "ah") == INVALID ||
5535           GETINT("poly", aindent,      "aindent") == INVALID ||
5536           GETSTR("poly", aw_spec,      "aw_spec") == INVALID ||
5537           GETSTR("poly", ah_spec,      "ah_spec") == INVALID ||
5538           GETSTR("poly", aindent_spec, "aindent_spec") == INVALID) {
5539          free(*ObjPtr);
5540          free(poly_ptr);
5541          free(v);
5542          *ObjPtr = NULL;
5543          return;
5544       }
5545       UtilRemoveQuotes(aw_spec);
5546       UtilRemoveQuotes(ah_spec);
5547       UtilRemoveQuotes(aindent_spec);
5548    }
5549    if (fileVersion >= 33 && transformed) {
5550       (void)fgets(inbuf, MAXSTRING, FP);
5551       scanLineNum++;
5552       InitScan(inbuf, "\t\n, ");
5553 
5554       ctm = (struct XfrmMtrxRec *)malloc(sizeof(struct XfrmMtrxRec));
5555       if (ctm == NULL) FailAllocMessage();
5556       if (GETINT("poly", real_x,           "real_x") == INVALID ||
5557           GETINT("poly", real_y,           "real_y") == INVALID ||
5558           GETINT("poly", orig_obbox.ltx,   "orig_obbox.ltx") == INVALID ||
5559           GETINT("poly", orig_obbox.lty,   "orig_obbox.lty") == INVALID ||
5560           GETINT("poly", orig_obbox.rbx,   "orig_obbox.rbx") == INVALID ||
5561           GETINT("poly", orig_obbox.rby,   "orig_obbox.rby") == INVALID ||
5562           GETDBL("poly", ctm->m[CTM_SX],   "CTM_SX") == INVALID ||
5563           GETDBL("poly", ctm->m[CTM_SIN],  "CTM_SIN") == INVALID ||
5564           GETDBL("poly", ctm->m[CTM_MSIN], "CTM_MSIN") == INVALID ||
5565           GETDBL("poly", ctm->m[CTM_SY],   "CTM_SY") == INVALID ||
5566           GETINT("poly", ctm->t[CTM_TX],   "CTM_TX") == INVALID ||
5567           GETINT("poly", ctm->t[CTM_TY],   "CTM_TY") == INVALID) {
5568          free(*ObjPtr);
5569          free(poly_ptr);
5570          free(v);
5571          *ObjPtr = NULL;
5572          free(ctm);
5573          return;
5574       }
5575    }
5576    if (fileVersion <= 32) {
5577       sprintf(width_spec, "%1d", width);
5578       sprintf(aw_spec, "%1d", aw);
5579       sprintf(ah_spec, "%1d", ah);
5580    }
5581 
5582    fill = UpgradePenFill(fill);
5583    pen = UpgradePenFill(pen);
5584 
5585    poly_ptr->style = style;
5586    poly_ptr->width = width;
5587    poly_ptr->aw = aw;
5588    poly_ptr->ah = ah;
5589    UtilStrCpyN(poly_ptr->width_spec, sizeof(poly_ptr->width_spec), width_spec);
5590    UtilStrCpyN(poly_ptr->aw_spec, sizeof(poly_ptr->aw_spec), aw_spec);
5591    UtilStrCpyN(poly_ptr->ah_spec, sizeof(poly_ptr->ah_spec), ah_spec);
5592    poly_ptr->pen = pen;
5593    poly_ptr->curved = curved;
5594    poly_ptr->fill = fill;
5595    poly_ptr->dash = dash;
5596 
5597    poly_ptr->vlist = v;
5598    poly_ptr->smooth = smooth;
5599    poly_ptr->svlist = poly_ptr->asvlist = NULL;
5600    poly_ptr->intvlist = NULL;
5601 
5602    poly_ptr->rotated_n = poly_ptr->rotated_asn = 0;
5603    poly_ptr->rotated_vlist = poly_ptr->rotated_asvlist = NULL;
5604 
5605    (*ObjPtr)->x = ltx;
5606    (*ObjPtr)->y = lty;
5607    (*ObjPtr)->color = QuickFindColorIndex(*ObjPtr, color_str, &new_alloc, TRUE);
5608    UtilStrCpyN((*ObjPtr)->color_str, sizeof((*ObjPtr)->color_str), color_str);
5609    (*ObjPtr)->dirty = FALSE;
5610    (*ObjPtr)->id = id;
5611    (*ObjPtr)->rotation = rotation;
5612    (*ObjPtr)->locked = locked;
5613    (*ObjPtr)->type = OBJ_POLY;
5614    (*ObjPtr)->obbox.ltx = ltx;
5615    (*ObjPtr)->obbox.lty = lty;
5616    (*ObjPtr)->obbox.rbx = rbx;
5617    (*ObjPtr)->obbox.rby = rby;
5618    (*ObjPtr)->detail.p = poly_ptr;
5619    (*ObjPtr)->ctm = ctm;
5620    (*ObjPtr)->invisible = invisible;
5621    (*ObjPtr)->trans_pat = trans_pat;
5622    if (ctm != NULL) {
5623       memcpy(&(*ObjPtr)->orig_obbox, &orig_obbox, sizeof(struct BBRec));
5624       (*ObjPtr)->x = real_x;
5625       (*ObjPtr)->y = real_y;
5626       GetTransformedOBBoxOffsetVs(*ObjPtr, (*ObjPtr)->rotated_obbox);
5627    }
5628    AdjObjCache(*ObjPtr);
5629    AdjObjSplineVs(*ObjPtr);
5630    if (poly_ptr->curved != LT_INTSPLINE) {
5631       UpdPolyBBox(*ObjPtr, poly_ptr->n, poly_ptr->vlist);
5632    } else {
5633       UpdPolyBBox(*ObjPtr, poly_ptr->intn, poly_ptr->intvlist);
5634    }
5635 }
5636 
5637 /* --------------------- SetPolyPropMask() --------------------- */
5638 
SetPolyPropMask(ObjPtr,plMask,plSkip,pProp)5639 void SetPolyPropMask(ObjPtr, plMask, plSkip, pProp)
5640    struct ObjRec *ObjPtr;
5641    long *plMask, *plSkip;
5642    struct PropertiesRec *pProp;
5643 {
5644    struct PolyRec *poly_ptr=ObjPtr->detail.p;
5645 
5646    SetCTMPropertyMask(ObjPtr->ctm, plMask, plSkip, pProp);
5647 
5648    SetIntPropertyMask(PROP_MASK_COLOR, ObjPtr->color,
5649          colorMenuItems[ObjPtr->color], plMask, plSkip, pProp);
5650    SetIntPropertyMask(PROP_MASK_WIDTH, poly_ptr->width, poly_ptr->width_spec,
5651          plMask, plSkip, pProp);
5652    SetIntPropertyMask(PROP_MASK_AW, poly_ptr->aw, poly_ptr->aw_spec,
5653          plMask, plSkip, pProp);
5654    SetIntPropertyMask(PROP_MASK_AH, poly_ptr->ah, poly_ptr->ah_spec,
5655          plMask, plSkip, pProp);
5656 
5657    SetIntPropertyMask(PROP_MASK_TRANSPAT, ObjPtr->trans_pat, NULL,
5658          plMask, plSkip, pProp);
5659    SetIntPropertyMask(PROP_MASK_FILL, poly_ptr->fill, NULL,
5660          plMask, plSkip, pProp);
5661    SetIntPropertyMask(PROP_MASK_PEN, poly_ptr->pen, NULL,
5662          plMask, plSkip, pProp);
5663    SetIntPropertyMask(PROP_MASK_DASH, poly_ptr->dash, NULL,
5664          plMask, plSkip, pProp);
5665    SetIntPropertyMask(PROP_MASK_CURVED, poly_ptr->curved, NULL,
5666          plMask, plSkip, pProp);
5667    SetIntPropertyMask(PROP_MASK_ARROW_STYLE, poly_ptr->style, NULL,
5668          plMask, plSkip, pProp);
5669 }
5670 
5671 /* --------------------- FreePolyObj() --------------------- */
5672 
FreePolyObj(ObjPtr)5673 void FreePolyObj(ObjPtr)
5674    struct ObjRec *ObjPtr;
5675 {
5676    if (ObjPtr->detail.p->ssvlist != NULL) free(ObjPtr->detail.p->ssvlist);
5677    if (ObjPtr->detail.p->svlist != NULL) free(ObjPtr->detail.p->svlist);
5678    if (ObjPtr->detail.p->asvlist != NULL) free(ObjPtr->detail.p->asvlist);
5679    if (ObjPtr->detail.p->intvlist != NULL) free(ObjPtr->detail.p->intvlist);
5680    if (ObjPtr->detail.p->rotated_vlist != NULL) {
5681       free(ObjPtr->detail.p->rotated_vlist);
5682    }
5683    if (ObjPtr->detail.p->rotated_asvlist != NULL) {
5684       free(ObjPtr->detail.p->rotated_asvlist);
5685    }
5686    free(ObjPtr->detail.p->vlist);
5687    if (ObjPtr->detail.p->smooth != NULL) free(ObjPtr->detail.p->smooth);
5688    if (ObjPtr->detail.p->ssmooth != NULL) free(ObjPtr->detail.p->ssmooth);
5689    free(ObjPtr->detail.p);
5690    free(ObjPtr);
5691 }
5692 
5693 /* --------------------- InitPoly() --------------------- */
5694 
InitPoly()5695 void InitPoly()
5696 {
5697    ResetWiringNodeInfo();
5698    CVListInit(&gStructSplineList);
5699 }
5700