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/spline.c,v 1.45 2011/05/16 16:21:59 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_SPLINE_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "dialog.e"
26 #include "file.e"
27 #include "msg.e"
28 #include "poly.e"
29 #include "polygon.e"
30 #include "ps.e"
31 #include "raster.e"
32 #include "rect.e"
33 #include "setup.e"
34 #include "spline.e"
35 #include "strtbl.e"
36 
37 #define SUM_MINUS_2 (theSum-((double)2.0))
38 #define HALF ((double)0.5)
39 
40 int intSplineTension=3;
41 int splineTol=9;
42 int tighterStructSplines=TRUE;
43 
44 #define curveToFactor (((double)2.0)/((double)3.0))
45 #define compCurveToFactor (((double)1.0)/((double)3.0))
46 
47 static double theSum=(double)6.0;
48 
ReadSplineTightness(buf)49 int ReadSplineTightness(buf)
50    char *buf;
51 {
52    int tighter=TRUE;
53    char *psz=NULL;
54 
55    if (importingFile) return TRUE;
56 
57    psz = FindChar((int)'(', buf);
58    InitScan(psz, "\t\n, ");
59    if (GETINT("spline_tightness", tighter, "tighter_splines") == INVALID) {
60       return FALSE;
61    }
62    tighterStructSplines = tighter;
63 
64    return TRUE;
65 }
66 
CalcAutoRetractedArrowAttrBend(Style,X0,Y0,X2,Y2,X1,Y1)67 void CalcAutoRetractedArrowAttrBend(Style, X0, Y0, X2, Y2, X1, Y1)
68    int Style, X0, Y0, X2, Y2, *X1, *Y1;
69 {
70    double dx, dy, len, new_x, new_y;
71 
72    dx = (double)(X2 - X0);
73    dy = (double)(Y2 - Y0);
74    len = (double)(sqrt(((double)dx)*((double)dx)+((double)dy)*((double)dy)));
75    if (Style == LS_RIGHT) {
76       new_x = ((double)((X0+X2)>>1)) + dy/((double)8.0);
77       new_y = ((double)((Y0+Y2)>>1)) - dx/((double)8.0);
78    } else {
79       new_x = ((double)((X0+X2)>>1)) - dy/((double)8.0);
80       new_y = ((double)((Y0+Y2)>>1)) + dx/((double)8.0);
81    }
82    *X1 = (int)round(new_x);
83    *Y1 = (int)round(new_y);
84 }
85 
86 static
MidPoint(X1,Y1,X2,Y2,pd_mx,pd_my)87 void MidPoint(X1, Y1, X2, Y2, pd_mx, pd_my)
88    double X1, Y1, X2, Y2, *pd_mx, *pd_my;
89 {
90    *pd_mx = HALF*X1+HALF*X2;
91    *pd_my = HALF*Y1+HALF*Y2;
92 }
93 
94 static
SetAStructuredSplineTickMark(vs,num_pts,target_vs)95 void SetAStructuredSplineTickMark(vs, num_pts, target_vs)
96    IntPoint *vs, *target_vs;
97    int num_pts;
98 {
99    double x, y, x0, y0, x1, y1, x2, y2, x3, y3;
100    double mx1, my1, mx2, my2, mx3, my3, mx12, my12, mx23, my23;
101 
102    switch (num_pts) {
103    case 1:
104       target_vs[0].x = vs[0].x;
105       target_vs[0].y = vs[0].y;
106       break;
107    case 3:
108       x0 = (double)(vs[0].x); y0 = (double)(vs[0].y);
109       x1 = (double)(vs[1].x); y1 = (double)(vs[1].y);
110       x2 = (double)(vs[2].x); y2 = (double)(vs[2].y);
111       MidPoint(x0, y0, x1, y1, &mx1, &my1);
112       MidPoint(x2, y2, x1, y1, &mx2, &my2);
113       MidPoint(mx1, my1, mx2, my2, &x, &y);
114       target_vs[0].x = (int)x;
115       target_vs[0].y = (int)y;
116       break;
117    case 4:
118       x0 = (double)(vs[0].x); y0 = (double)(vs[0].y);
119       x1 = (double)(vs[1].x); y1 = (double)(vs[1].y);
120       x2 = (double)(vs[2].x); y2 = (double)(vs[2].y);
121       x3 = (double)(vs[3].x); y3 = (double)(vs[3].y);
122       MidPoint(x0, y0, x1, y1, &mx1, &my1);
123       MidPoint(x1, y1, x2, y2, &mx2, &my2);
124       MidPoint(x2, y2, x3, y3, &mx3, &my3);
125       MidPoint(mx1, my1, mx2, my2, &mx12, &my12);
126       MidPoint(mx2, my2, mx3, my3, &mx23, &my23);
127       MidPoint(mx12, my12, mx23, my23, &x, &y);
128       target_vs[0].x = (int)x;
129       target_vs[0].y = (int)y;
130       break;
131    }
132 }
133 
GetStructuredSplinePolyTickMarkVs(pn_N,obj_ptr,poly_ptr,polygon_ptr)134 IntPoint *GetStructuredSplinePolyTickMarkVs(pn_N, obj_ptr, poly_ptr,
135       polygon_ptr)
136    int *pn_N;
137    struct ObjRec *obj_ptr;
138    struct PolyRec *poly_ptr;
139    struct PolygonRec *polygon_ptr;
140 {
141    int i=0, j=0, n=0, num_hinge_vs=0, num_vs=0, index=0;
142    int last_was_smooth=FALSE;
143    IntPoint *vs=NULL, *vlist=NULL, tmp_vs[4], *xformed_vs=NULL;
144 
145    if (poly_ptr != NULL) {
146       n = poly_ptr->n;
147       vlist = poly_ptr->vlist;
148    } else if (polygon_ptr != NULL) {
149       n = polygon_ptr->n;
150       vlist = polygon_ptr->vlist;
151    }
152    if (obj_ptr->ctm != NULL) {
153       xformed_vs = (IntPoint*)malloc((n+1)*sizeof(IntPoint));
154       if (xformed_vs == NULL) FailAllocMessage();
155       memset(xformed_vs, 0, (n+1)*sizeof(IntPoint));
156       for (i=0; i < n; i++) {
157          int tmp_x=0, tmp_y=0;
158 
159          TransformPointThroughCTM(vlist[i].x-obj_ptr->x, vlist[i].y-obj_ptr->y,
160                obj_ptr->ctm, &tmp_x, &tmp_y);
161          xformed_vs[i].x = tmp_x + obj_ptr->x;
162          xformed_vs[i].y = tmp_y + obj_ptr->y;
163       }
164    }
165    num_hinge_vs = (n+2)/3;
166 #ifdef _TGIF_DBG /* debug, do not translate */
167    TgAssert((n+2)%3 == 0,
168          "invalid n in GetStructuredSplinePolyTickMarkVs()", NULL);
169 #endif /* _TGIF_DBG */
170    num_vs = num_hinge_vs;
171    for (i=0, j=0; i < num_hinge_vs; i++, j+=3) {
172       if (i == 0) {
173          if (vlist[0].x != vlist[1].x || vlist[0].y != vlist[1].y) {
174             last_was_smooth = TRUE;
175          }
176       } else if (i == num_hinge_vs-1) {
177          if (vlist[n-1].x != vlist[n-2].x || vlist[n-1].y != vlist[n-2].y) {
178             num_vs++;
179             last_was_smooth = TRUE;
180          } else if (last_was_smooth) {
181             num_vs++;
182             last_was_smooth = FALSE;
183          }
184       } else {
185          if (vlist[j-1].x != vlist[j].x || vlist[j-1].y != vlist[j].y) {
186 #ifdef _TGIF_DBG /* debug, do not translate */
187             TgAssert(vlist[j+1].x != vlist[j].x || vlist[j+1].y != vlist[j].y,
188                   "half smooth detected in GetStructuredSplinePolyTickMarkVs()",
189                   NULL);
190 #endif /* _TGIF_DBG */
191             num_vs++;
192             last_was_smooth = TRUE;
193          } else if (last_was_smooth) {
194             num_vs++;
195             last_was_smooth = FALSE;
196          }
197       }
198    }
199    vs = (IntPoint*)malloc((num_vs+1)*sizeof(IntPoint));
200    if (vs == NULL) FailAllocMessage();
201    memset(vs, 0, (num_vs+1)*sizeof(IntPoint));
202 
203    if (xformed_vs != NULL) {
204       vs[0].x = xformed_vs[0].x;
205       vs[0].y = xformed_vs[0].y;
206    } else {
207       vs[0].x = vlist[0].x;
208       vs[0].y = vlist[0].y;
209    }
210    index = 1;
211    last_was_smooth = FALSE;
212    for (i=0, j=0; i < num_hinge_vs; i++, j+=3) {
213       int num_pts_in_seg=0;
214 
215       if (i == 0) {
216          if (xformed_vs != NULL) {
217             tmp_vs[0].x = xformed_vs[0].x;
218             tmp_vs[0].y = xformed_vs[0].y;
219          } else {
220             tmp_vs[0].x = vlist[0].x;
221             tmp_vs[0].y = vlist[0].y;
222          }
223          if (vlist[0].x != vlist[1].x || vlist[0].y != vlist[1].y) {
224             last_was_smooth = TRUE;
225             if (xformed_vs != NULL) {
226                tmp_vs[1].x = xformed_vs[1].x;
227                tmp_vs[1].y = xformed_vs[1].y;
228             } else {
229                tmp_vs[1].x = vlist[1].x;
230                tmp_vs[1].y = vlist[1].y;
231             }
232          }
233       } else if (i == num_hinge_vs-1) {
234          if (vlist[n-1].x != vlist[n-2].x || vlist[n-1].y != vlist[n-2].y) {
235             if (last_was_smooth) {
236                num_pts_in_seg = 4;
237             } else {
238                num_pts_in_seg = 3;
239             }
240             if (xformed_vs != NULL) {
241                tmp_vs[num_pts_in_seg-2].x = xformed_vs[j-1].x;
242                tmp_vs[num_pts_in_seg-2].y = xformed_vs[j-1].y;
243                tmp_vs[num_pts_in_seg-1].x = xformed_vs[j].x;
244                tmp_vs[num_pts_in_seg-1].y = xformed_vs[j].y;
245             } else {
246                tmp_vs[num_pts_in_seg-2].x = vlist[j-1].x;
247                tmp_vs[num_pts_in_seg-2].y = vlist[j-1].y;
248                tmp_vs[num_pts_in_seg-1].x = vlist[j].x;
249                tmp_vs[num_pts_in_seg-1].y = vlist[j].y;
250             }
251             SetAStructuredSplineTickMark(tmp_vs, num_pts_in_seg, &vs[index++]);
252          } else if (last_was_smooth) {
253             if (xformed_vs != NULL) {
254                tmp_vs[2].x = xformed_vs[j].x;
255                tmp_vs[2].y = xformed_vs[j].y;
256             } else {
257                tmp_vs[2].x = vlist[j].x;
258                tmp_vs[2].y = vlist[j].y;
259             }
260             SetAStructuredSplineTickMark(tmp_vs, 3, &vs[index++]);
261          }
262          if (poly_ptr != NULL) {
263             if (xformed_vs != NULL) {
264                SetAStructuredSplineTickMark(&xformed_vs[j], 1, &vs[index++]);
265             } else {
266                SetAStructuredSplineTickMark(&vlist[j], 1, &vs[index++]);
267             }
268          }
269          /* all done */
270       } else {
271          if (vlist[j-1].x != vlist[j].x || vlist[j-1].y != vlist[j].y) {
272             if (last_was_smooth) {
273                num_pts_in_seg = 4;
274             } else {
275                num_pts_in_seg = 3;
276             }
277             if (xformed_vs != NULL) {
278                tmp_vs[num_pts_in_seg-2].x = xformed_vs[j-1].x;
279                tmp_vs[num_pts_in_seg-2].y = xformed_vs[j-1].y;
280                tmp_vs[num_pts_in_seg-1].x = xformed_vs[j].x;
281                tmp_vs[num_pts_in_seg-1].y = xformed_vs[j].y;
282             } else {
283                tmp_vs[num_pts_in_seg-2].x = vlist[j-1].x;
284                tmp_vs[num_pts_in_seg-2].y = vlist[j-1].y;
285                tmp_vs[num_pts_in_seg-1].x = vlist[j].x;
286                tmp_vs[num_pts_in_seg-1].y = vlist[j].y;
287             }
288             SetAStructuredSplineTickMark(tmp_vs, num_pts_in_seg, &vs[index++]);
289 
290             last_was_smooth = TRUE;
291             if (xformed_vs != NULL) {
292                tmp_vs[1].x = xformed_vs[j+1].x;
293                tmp_vs[1].y = xformed_vs[j+1].y;
294             } else {
295                tmp_vs[1].x = vlist[j+1].x;
296                tmp_vs[1].y = vlist[j+1].y;
297             }
298          } else if (last_was_smooth) {
299             if (xformed_vs != NULL) {
300                tmp_vs[2].x = xformed_vs[j].x;
301                tmp_vs[2].y = xformed_vs[j].y;
302             } else {
303                tmp_vs[2].x = vlist[j].x;
304                tmp_vs[2].y = vlist[j].y;
305             }
306             SetAStructuredSplineTickMark(tmp_vs, 3, &vs[index++]);
307 
308             last_was_smooth = FALSE;
309          }
310          if (xformed_vs != NULL) {
311             tmp_vs[0].x = xformed_vs[j].x;
312             tmp_vs[0].y = xformed_vs[j].y;
313             SetAStructuredSplineTickMark(&xformed_vs[j], 1, &vs[index++]);
314          } else {
315             tmp_vs[0].x = vlist[j].x;
316             tmp_vs[0].y = vlist[j].y;
317             SetAStructuredSplineTickMark(&vlist[j], 1, &vs[index++]);
318          }
319       }
320    }
321    if (xformed_vs != NULL) free(xformed_vs);
322    *pn_N = num_vs;
323 
324    return vs;
325 }
326 
MakeStructuredSplinePolyVertex(pn_N,ppszSmooth,NumVs,Vs)327 IntPoint *MakeStructuredSplinePolyVertex(pn_N, ppszSmooth, NumVs, Vs)
328    int *pn_N, NumVs; /* NumVs is poly_ptr->n */
329    char **ppszSmooth;
330    IntPoint *Vs; /* Vs is poly_ptr->vlist */
331 {
332    int i=0, j=0, k=0, num_hinge_vs=(NumVs+2)/3, num_vs=0;
333    IntPoint *vs=NULL;
334    char *ssmooth=NULL;
335 
336 #ifdef _TGIF_DBG /* debug, do not translate */
337    TgAssert((NumVs+2)%3 == 0,
338          "invalid NumVs in MakeStructuredSplineVertex()", NULL);
339 #endif /* _TGIF_DBG */
340    num_vs = num_hinge_vs;
341    for (i=0, j=0; i < num_hinge_vs; i++, j+=3) {
342       if (i == 0) {
343          if (Vs[0].x != Vs[1].x || Vs[0].y != Vs[1].y) {
344             num_vs++;
345          }
346       } else if (i == num_hinge_vs-1) {
347          if (Vs[NumVs-1].x != Vs[NumVs-2].x || Vs[NumVs-1].y != Vs[NumVs-2].y) {
348             num_vs++;
349          }
350       } else {
351          if (Vs[j-1].x != Vs[j].x || Vs[j-1].y != Vs[j].y) {
352             num_vs++;
353          }
354          if (Vs[j+1].x != Vs[j].x || Vs[j+1].y != Vs[j].y) {
355             num_vs++;
356          }
357       }
358    }
359    vs = (IntPoint*)malloc((num_vs+2)*sizeof(IntPoint));
360    if (vs == NULL) FailAllocMessage();
361    ssmooth = (char*)malloc((num_vs+2)*sizeof(char));
362    if (ssmooth == NULL) FailAllocMessage();
363    memset(ssmooth, 0, (num_vs+2)*sizeof(char));
364 
365    for (i=0, j=0, k=0; i < num_hinge_vs; i++, j+=3, k++) {
366       if (i == 0) {
367          vs[k].x = Vs[0].x;
368          vs[k].y = Vs[0].y;
369          ssmooth[k] = FALSE;
370          if (Vs[0].x != Vs[1].x || Vs[0].y != Vs[1].y) {
371             k++;
372             vs[k].x = Vs[1].x;
373             vs[k].y = Vs[1].y;
374             ssmooth[k] = TRUE;
375          }
376       } else if (i == num_hinge_vs-1) {
377          if (Vs[NumVs-1].x != Vs[NumVs-2].x || Vs[NumVs-1].y != Vs[NumVs-2].y) {
378             vs[k].x = Vs[NumVs-2].x;
379             vs[k].y = Vs[NumVs-2].y;
380             ssmooth[k] = TRUE;
381             k++;
382          }
383          vs[k].x = Vs[NumVs-1].x;
384          vs[k].y = Vs[NumVs-1].y;
385          ssmooth[k] = FALSE;
386       } else {
387          if (Vs[j-1].x != Vs[j].x || Vs[j-1].y != Vs[j].y) {
388             vs[k].x = Vs[j-1].x;
389             vs[k].y = Vs[j-1].y;
390             ssmooth[k] = TRUE;
391             k++;
392          }
393          vs[k].x = Vs[j].x;
394          vs[k].y = Vs[j].y;
395          ssmooth[k] = FALSE;
396          if (Vs[j+1].x != Vs[j].x || Vs[j+1].y != Vs[j].y) {
397             k++;
398             vs[k].x = Vs[j+1].x;
399             vs[k].y = Vs[j+1].y;
400             ssmooth[k] = TRUE;
401          }
402       }
403    }
404 #ifdef _TGIF_DBG /* debug, do not translate */
405    TgAssert(k == num_vs,
406          "k != num_vs in MakeStructuredSplineVertex()", NULL);
407 #endif /* _TGIF_DBG */
408    *pn_N = num_vs;
409    *ppszSmooth = ssmooth;
410 
411    return vs;
412 }
413 
MakeStructuredSplinePolygonVertex(pn_N,ppszSmooth,NumVs,Vs)414 IntPoint *MakeStructuredSplinePolygonVertex(pn_N, ppszSmooth, NumVs, Vs)
415    int *pn_N, NumVs;
416    char **ppszSmooth;
417    IntPoint *Vs;
418 {
419    int i=0, j=0, k=0, num_hinge_vs=(NumVs+2)/3, num_vs=0;
420    IntPoint *vs=NULL;
421    char *ssmooth=NULL;
422 
423 #ifdef _TGIF_DBG /* debug, do not translate */
424    TgAssert((NumVs+2)%3 == 0,
425          "invalid NumVs in MakeStructuredSplinePolygonVertex()", NULL);
426    TgAssert(Vs[0].x == Vs[NumVs-1].x && Vs[0].y == Vs[NumVs-1].y,
427          "first and last points not identical in MakeStructuredSplinePolygonVertex()",
428          NULL);
429 #endif /* _TGIF_DBG */
430    num_vs = num_hinge_vs;
431    for (i=0, j=0; i < num_hinge_vs; i++, j+=3) {
432       if (i == 0) {
433          if (Vs[0].x != Vs[1].x || Vs[0].y != Vs[1].y) {
434             num_vs++;
435          }
436       } else if (i == num_hinge_vs-1) {
437          if (Vs[NumVs-1].x != Vs[NumVs-2].x || Vs[NumVs-1].y != Vs[NumVs-2].y) {
438             num_vs++;
439          }
440       } else {
441          if (Vs[j-1].x != Vs[j].x || Vs[j-1].y != Vs[j].y) {
442             num_vs++;
443          }
444          if (Vs[j+1].x != Vs[j].x || Vs[j+1].y != Vs[j].y) {
445             num_vs++;
446          }
447       }
448    }
449    vs = (IntPoint*)malloc((num_vs+2)*sizeof(IntPoint));
450    if (vs == NULL) FailAllocMessage();
451    ssmooth = (char*)malloc((num_vs+2)*sizeof(char));
452    if (ssmooth == NULL) FailAllocMessage();
453    memset(ssmooth, 0, (num_vs+2)*sizeof(char));
454 
455    for (i=0, j=0, k=0; i < num_hinge_vs; i++, j+=3, k++) {
456       if (i == 0) {
457          vs[k].x = Vs[0].x;
458          vs[k].y = Vs[0].y;
459          ssmooth[k] = FALSE;
460          if (Vs[0].x != Vs[1].x || Vs[0].y != Vs[1].y) {
461             k++;
462             vs[k].x = Vs[1].x;
463             vs[k].y = Vs[1].y;
464             ssmooth[k] = TRUE;
465          }
466       } else if (i == num_hinge_vs-1) {
467          if (Vs[NumVs-1].x != Vs[NumVs-2].x || Vs[NumVs-1].y != Vs[NumVs-2].y) {
468             vs[k].x = Vs[NumVs-2].x;
469             vs[k].y = Vs[NumVs-2].y;
470             ssmooth[k] = TRUE;
471             k++;
472          }
473          vs[k].x = Vs[NumVs-1].x;
474          vs[k].y = Vs[NumVs-1].y;
475          ssmooth[k] = FALSE;
476       } else {
477          if (Vs[j-1].x != Vs[j].x || Vs[j-1].y != Vs[j].y) {
478             vs[k].x = Vs[j-1].x;
479             vs[k].y = Vs[j-1].y;
480             ssmooth[k] = TRUE;
481             k++;
482          }
483          vs[k].x = Vs[j].x;
484          vs[k].y = Vs[j].y;
485          ssmooth[k] = FALSE;
486          if (Vs[j+1].x != Vs[j].x || Vs[j+1].y != Vs[j].y) {
487             k++;
488             vs[k].x = Vs[j+1].x;
489             vs[k].y = Vs[j+1].y;
490             ssmooth[k] = TRUE;
491          }
492       }
493    }
494 #ifdef _TGIF_DBG /* debug, do not translate */
495    TgAssert(k == num_vs,
496          "k != num_vs in MakeStructuredSplinePolygonVertex()", NULL);
497 #endif /* _TGIF_DBG */
498    *pn_N = num_vs;
499    *ppszSmooth = ssmooth;
500 
501    return vs;
502 }
503 
504 static XPoint *splineVs=NULL;
505 static DoublePoint *splineDoubleVs=NULL;
506 
507 static
AddSplinePt(N,MaxN,X,Y)508 int AddSplinePt(N, MaxN, X, Y)
509    int *N, *MaxN, X, Y;
510 {
511    if (*N == *MaxN) {
512       splineVs = (XPoint*)realloc(splineVs, (*MaxN)*2*sizeof(XPoint)+1);
513       if (splineVs == NULL) {
514          return FailAllocMessage();
515       }
516       *MaxN = (*MaxN) * 2;
517    }
518    splineVs[*N].x = X;
519    splineVs[*N].y = Y;
520    (*N)++;
521    return TRUE;
522 }
523 
524 static
AddDoubleSplinePt(N,MaxN,X,Y)525 int AddDoubleSplinePt(N, MaxN, X, Y)
526    int *N, *MaxN;
527    double X, Y;
528 {
529    if (*N == *MaxN) {
530       splineDoubleVs = (DoublePoint*)realloc(splineDoubleVs,
531             (*MaxN)*2*sizeof(DoublePoint)+1);
532       if (splineDoubleVs == NULL) {
533          return FailAllocMessage();
534       }
535       *MaxN = (*MaxN) << 1;
536    }
537    splineDoubleVs[*N].x = X;
538    splineDoubleVs[*N].y = Y;
539    (*N)++;
540    return TRUE;
541 }
542 
543 static
SetSplineVs(N,MaxN,X1,Y1,X2,Y2,X3,Y3,X4,Y4)544 void SetSplineVs(N, MaxN, X1, Y1, X2, Y2, X3, Y3, X4, Y4)
545    int *N, *MaxN;
546    double X1, Y1, X2, Y2, X3, Y3, X4, Y4;
547    /* X1, Y1, X2, Y2, X3, Y3, X4, Y4 are screen offsets */
548 {
549    if (tighterStructSplines) {
550       double mx1, my1, mx2, my2, mx3, my3, mx12, my12, mx23, my23, mx4, my4;
551 
552       MidPoint(X1, Y1, X2, Y2, &mx1, &my1);
553       MidPoint(X2, Y2, X3, Y3, &mx2, &my2);
554       MidPoint(X3, Y3, X4, Y4, &mx3, &my3);
555 
556       MidPoint(mx1, my1, mx2, my2, &mx12, &my12);
557       MidPoint(mx2, my2, mx3, my3, &mx23, &my23);
558 
559       MidPoint(mx12, my12, mx23, my23, &mx4, &my4);
560 
561       if (fabs(X1 - mx4) < splineTol && fabs(Y1 - my4) < splineTol) {
562          AddSplinePt(N, MaxN, round(mx4), round(my4));
563       } else {
564          SetSplineVs(N, MaxN, X1, Y1, mx1, my1, mx12, my12, mx4, my4);
565       }
566       if (fabs(mx4 - X4) < splineTol && fabs(my4 - Y4) < splineTol) {
567          AddSplinePt(N, MaxN, round(X4), round(Y4));
568       } else {
569          SetSplineVs(N, MaxN, mx4, my4, mx23, my23, mx3, my3, X4, Y4);
570       }
571    } else {
572       double x, y;
573 
574       x = (X2 + X3) / 2.0;
575       y = (Y2 + Y3) / 2.0;
576       if (fabs(X1 - x) < splineTol && fabs(Y1 - y) < splineTol) {
577          AddSplinePt(N, MaxN, round(x), round(y));
578       } else {
579          SetSplineVs(N, MaxN, X1, Y1, ((X1+X2)/2.0), ((Y1+Y2)/2.0),
580                ((3.0*X2+X3)/4.0), ((3.0*Y2+Y3)/4.0), x, y);
581       }
582       if (fabs(x - X4) < splineTol && fabs(y - Y4) < splineTol) {
583          AddSplinePt(N, MaxN, round(X4), round(Y4));
584       } else {
585          SetSplineVs(N, MaxN, x, y, ((X2+3.0*X3)/4.0), ((Y2+3.0*Y3)/4.0),
586                ((X3+X4)/2.0), ((Y3+Y4)/2.0), X4, Y4);
587       }
588    }
589 }
590 
591 static
SetDoubleSplineVs(N,MaxN,X1,Y1,X2,Y2,X3,Y3,X4,Y4)592 void SetDoubleSplineVs(N, MaxN, X1, Y1, X2, Y2, X3, Y3, X4, Y4)
593    int *N, *MaxN;
594    double X1, Y1, X2, Y2, X3, Y3, X4, Y4;
595    /* X1, Y1, X2, Y2, X3, Y3, X4, Y4 are screen offsets */
596 {
597    if (tighterStructSplines) {
598       double mx1, my1, mx2, my2, mx3, my3, mx12, my12, mx23, my23, mx4, my4;
599 
600       MidPoint(X1, Y1, X2, Y2, &mx1, &my1);
601       MidPoint(X2, Y2, X3, Y3, &mx2, &my2);
602       MidPoint(X3, Y3, X4, Y4, &mx3, &my3);
603 
604       MidPoint(mx1, my1, mx2, my2, &mx12, &my12);
605       MidPoint(mx2, my2, mx3, my3, &mx23, &my23);
606 
607       MidPoint(mx12, my12, mx23, my23, &mx4, &my4);
608 
609       if (fabs(X1 - mx4) < splineTol && fabs(Y1 - my4) < splineTol) {
610          AddDoubleSplinePt(N, MaxN, mx4, my4);
611       } else {
612          SetDoubleSplineVs(N, MaxN, X1, Y1, mx1, my1, mx12, my12, mx4, my4);
613       }
614       if (fabs(mx4 - X4) < splineTol && fabs(my4 - Y4) < splineTol) {
615          AddDoubleSplinePt(N, MaxN, round(X4), round(Y4));
616       } else {
617          SetDoubleSplineVs(N, MaxN, mx4, my4, mx23, my23, mx3, my3, X4, Y4);
618       }
619    } else {
620       double x, y;
621 
622       x = (X2 + X3) / 2.0;
623       y = (Y2 + Y3) / 2.0;
624       if (fabs(X1 - x) < splineTol && fabs(Y1 - y) < splineTol) {
625          AddDoubleSplinePt(N, MaxN, x, y);
626       } else {
627          SetDoubleSplineVs(N, MaxN, X1, Y1, ((X1+X2)/2.0), ((Y1+Y2)/2.0),
628                ((3.0*X2+X3)/4.0), ((3.0*Y2+Y3)/4.0), x, y);
629       }
630       if (fabs(x - X4) < splineTol && fabs(y - Y4) < splineTol) {
631          AddDoubleSplinePt(N, MaxN, X4, Y4);
632       } else {
633          SetDoubleSplineVs(N, MaxN, x, y, ((X2+3.0*X3)/4.0), ((Y2+3.0*Y3)/4.0),
634                ((X3+X4)/2.0), ((Y3+Y4)/2.0), X4, Y4);
635       }
636    }
637 }
638 
MakeSplinePolyVertex(Level,Curved,N,XOff,YOff,NumVs,Vs)639 XPoint *MakeSplinePolyVertex(Level, Curved, N, XOff, YOff, NumVs, Vs)
640    int Level, Curved, *N, XOff, YOff, NumVs;
641    IntPoint *Vs;
642 {
643    double mx1, my1, mx2, my2, mx3, my3, mx4, my4;
644    double x0, y0, x1, y1, x2, y2, x3, y3;
645    int i, x_off, y_off, max_n, saved_tighter_splines=tighterStructSplines;
646 
647    if (Level == 0 && Curved != LT_STRUCT_SPLINE && saved_tighter_splines) {
648       tighterStructSplines = FALSE;
649    }
650    x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
651    y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
652 
653    splineVs = NULL;
654 
655    switch (NumVs) {
656    case 0:
657    case 1:
658       break;
659    case 2:
660       splineVs = (XPoint*)malloc((NumVs+1)*sizeof(XPoint));
661       if (splineVs == NULL) {
662          FailAllocMessage();
663          *N = 0;
664          tighterStructSplines = saved_tighter_splines;
665          return splineVs;
666       }
667       memset(splineVs, 0, (NumVs+1)*sizeof(XPoint));
668       splineVs[0].x = ZOOMED_SIZE(Vs[0].x-x_off);
669       splineVs[0].y = ZOOMED_SIZE(Vs[0].y-y_off);
670       splineVs[1].x = ZOOMED_SIZE(Vs[1].x-x_off);
671       splineVs[1].y = ZOOMED_SIZE(Vs[1].y-y_off);
672       *N = 2;
673       break;
674    case 3:
675       if (tighterStructSplines) {
676          mx1 = ZOOMED_SIZE(Vs->x-x_off); my1 = ZOOMED_SIZE((Vs++)->y-y_off);
677          x1 = ZOOMED_SIZE(Vs->x-x_off);  y1 = ZOOMED_SIZE((Vs++)->y-y_off);
678          mx2 = (mx1+2.0*x1)/3.0;         my2 = (my1+2.0*y1)/3.0;
679          mx4 = ZOOMED_SIZE(Vs->x-x_off); my4 = ZOOMED_SIZE(Vs->y-y_off);
680          mx3 = (2.0*x1+mx4)/3.0;         my3 = (2.0*y1+my4)/3.0;
681          max_n = 100;
682          splineVs = (XPoint*)malloc((max_n+1)*sizeof(XPoint));
683          if (splineVs == NULL) {
684             FailAllocMessage();
685             *N = 0;
686             tighterStructSplines = saved_tighter_splines;
687             return splineVs;
688          }
689          memset(splineVs, 0, (max_n+1)*sizeof(XPoint));
690          splineVs[0].x = mx1;
691          splineVs[0].y = my1;
692          *N = 1;
693          SetSplineVs(N, &max_n, mx1, my1, mx2, my2, mx3, my3, mx4, my4);
694       } else {
695          mx1 = ZOOMED_SIZE(Vs->x-x_off); my1 = ZOOMED_SIZE((Vs++)->y-y_off);
696          x1 = ZOOMED_SIZE(Vs->x-x_off);  y1 = ZOOMED_SIZE((Vs++)->y-y_off);
697          mx2 = (mx1+x1)/2.0;             my2 = (my1+y1)/2.0;
698          mx4 = ZOOMED_SIZE(Vs->x-x_off); my4 = ZOOMED_SIZE(Vs->y-y_off);
699          mx3 = (x1+mx4)/2.0;             my3 = (y1+my4)/2.0;
700          max_n = 100;
701          splineVs = (XPoint*)malloc((max_n+1)*sizeof(XPoint));
702          if (splineVs == NULL) {
703             FailAllocMessage();
704             *N = 0;
705             tighterStructSplines = saved_tighter_splines;
706             return splineVs;
707          }
708          memset(splineVs, 0, (max_n+1)*sizeof(XPoint));
709          splineVs[0].x = mx1;
710          splineVs[0].y = my1;
711          *N = 1;
712          SetSplineVs(N, &max_n, mx1, my1, mx2, my2, mx3, my3, mx4, my4);
713       }
714       break;
715    default:
716       if (tighterStructSplines) {
717          /* must only have 4 points */
718          double mx1, my1, mx2, my2, mx3, my3, mx12, my12, mx23, my23, mx4, my4;
719 
720          x0 = ZOOMED_SIZE(Vs->x-x_off);  y0 = ZOOMED_SIZE((Vs++)->y-y_off);
721          x1 = ZOOMED_SIZE(Vs->x-x_off);  y1 = ZOOMED_SIZE((Vs++)->y-y_off);
722          x2 = ZOOMED_SIZE(Vs->x-x_off);  y2 = ZOOMED_SIZE((Vs++)->y-y_off);
723          x3 = ZOOMED_SIZE(Vs->x-x_off);  y3 = ZOOMED_SIZE(Vs->y-y_off);
724 
725          MidPoint(x0, y0, x1, y1, &mx1, &my1);
726          MidPoint(x1, y1, x2, y2, &mx2, &my2);
727          MidPoint(x2, y2, x3, y3, &mx3, &my3);
728 
729          MidPoint(mx1, my1, mx2, my2, &mx12, &my12);
730          MidPoint(mx2, my2, mx3, my3, &mx23, &my23);
731 
732          MidPoint(mx12, my12, mx23, my23, &mx4, &my4);
733 
734          max_n = 100;
735          splineVs = (XPoint *)malloc((max_n+1)*sizeof(XPoint));
736          if (splineVs == NULL) {
737             FailAllocMessage();
738             *N = 0;
739             tighterStructSplines = saved_tighter_splines;
740             return splineVs;
741          }
742          memset(splineVs, 0, (max_n+1)*sizeof(XPoint));
743          splineVs[0].x = x0;
744          splineVs[0].y = y0;
745          *N = 1;
746          SetSplineVs(N, &max_n, x0, y0, mx1, my1, mx12, my12, mx4, my4);
747          SetSplineVs(N, &max_n, mx4, my4, mx23, my23, mx3, my3, x3, y3);
748       } else {
749          mx1 = ZOOMED_SIZE(Vs->x-x_off); my1 = ZOOMED_SIZE((Vs++)->y-y_off);
750          x1 = ZOOMED_SIZE(Vs->x-x_off);  y1 = ZOOMED_SIZE((Vs++)->y-y_off);
751          x2 = ZOOMED_SIZE(Vs->x-x_off);  y2 = ZOOMED_SIZE((Vs++)->y-y_off);
752          mx2 = (mx1+x1)/2.0;             my2 = (my1+y1)/2.0;
753          mx3 = (3.0*x1+x2)/4.0;          my3 = (3.0*y1+y2)/4.0;
754          mx4 = (x1+x2)/2.0;              my4 = (y1+y2)/2.0;
755          max_n = 100;
756          splineVs = (XPoint *)malloc((max_n+1)*sizeof(XPoint));
757          if (splineVs == NULL) {
758             FailAllocMessage();
759             *N = 0;
760             tighterStructSplines = saved_tighter_splines;
761             return splineVs;
762          }
763          memset(splineVs, 0, (max_n+1)*sizeof(XPoint));
764          splineVs[0].x = mx1;
765          splineVs[0].y = my1;
766          *N = 1;
767          SetSplineVs(N, &max_n, mx1, my1, mx2, my2, mx3, my3, mx4, my4);
768 
769          for (i=2; i < NumVs-2; i++, Vs++) {
770             mx1 = mx4;                     my1 = my4;
771             mx2 = (x1 + 3.0*x2) / 4.0;     my2 = (y1 + 3.0*y2) / 4.0;
772             x1 = x2;                       y1 = y2;
773             x2 = ZOOMED_SIZE(Vs->x-x_off); y2 = ZOOMED_SIZE(Vs->y-y_off);
774             mx3 = (3.0*x1 + x2) / 4.0;     my3 = (3.0*y1 + y2) / 4.0;
775             mx4 = (x1 + x2) / 2.0;         my4 = (y1 + y2) / 2.0;
776             SetSplineVs(N, &max_n, mx1, my1, mx2, my2, mx3, my3, mx4, my4);
777          }
778          mx1 = mx4;                      my1 = my4;
779          mx2 = (x1 + 3.0*x2) / 4.0;      my2 = (y1 + 3.0*y2) / 4.0;
780          x1 = x2;                        y1 = y2;
781          mx4 = ZOOMED_SIZE(Vs->x-x_off); my4 = ZOOMED_SIZE(Vs->y-y_off);
782          mx3 = (x1 + mx4) / 2.0;         my3 = (y1 + my4) / 2.0;
783          SetSplineVs(N, &max_n, mx1, my1, mx2, my2, mx3, my3, mx4, my4);
784       }
785       break;
786    }
787    tighterStructSplines = saved_tighter_splines;
788 
789    return splineVs;
790 }
791 
792 typedef struct MultiSplineRec {
793    XPoint *vlist;
794    int n;
795 } *MultiSplineRecPtr;
796 
MakeMultiSplinePolyVertex(Curved,N,Smooth,XOff,YOff,NumVs,Vs)797 XPoint *MakeMultiSplinePolyVertex(Curved, N, Smooth, XOff, YOff, NumVs, Vs)
798    int *N, XOff, YOff, NumVs;
799    char *Smooth;
800    IntPoint *Vs;
801 {
802    register int i, j;
803    int segments=1, has_smooth_point=FALSE, start_index, seg_index;
804    int total=0;
805    XPoint *xpptr=NULL;
806    struct MultiSplineRec *msptr=NULL;
807 
808    if (Smooth == NULL) {
809       return MakeSplinePolyVertex(0, Curved, N, XOff, YOff, NumVs, Vs);
810    }
811    if (Smooth[0] || Smooth[NumVs-1]) {
812       FatalUnexpectedError(
813             TgLoadCachedString(CSTID_CORRUPTED_POLY_MKMULTISPLINE),
814             TgLoadCachedString(CSTID_FIX_ATTEMPTED));
815       Smooth[0] = Smooth[NumVs-1] = FALSE;
816    }
817    for (i=1; i < NumVs-1; i++) {
818       if (Smooth[i]) {
819          has_smooth_point = TRUE;
820       } else {
821          segments++;
822       }
823    }
824    if (!has_smooth_point) {
825       *N = NumVs;
826       return MakePolyVertex(XOff, YOff, NumVs, Vs);
827    }
828    if (segments == 1) {
829       return MakeSplinePolyVertex(0, Curved, N, XOff, YOff, NumVs, Vs);
830    }
831    msptr = (struct MultiSplineRec *)malloc(segments *
832          sizeof(struct MultiSplineRec));
833    if (msptr == NULL) {
834       FailAllocMessage();
835       return NULL;
836    }
837    memset(msptr, 0, segments*sizeof(struct MultiSplineRec));
838 
839    start_index = 0;
840    seg_index = 0;
841    for (i=1; i <= NumVs-1; i++) {
842       if (!Smooth[i]) {
843          msptr[seg_index].vlist = MakeSplinePolyVertex(0, Curved,
844                &msptr[seg_index].n, XOff, YOff, i-start_index+1,
845                &Vs[start_index]);
846          total += msptr[seg_index].n-1;
847          seg_index++;
848          start_index = i;
849       }
850    }
851    if (total > 0) total++;
852    splineVs = (XPoint *)malloc((total+2)*sizeof(XPoint));
853    if (splineVs == NULL) FailAllocMessage();
854    memset(splineVs, 0, (total+2)*sizeof(XPoint));
855    xpptr = splineVs;
856    for (i=0; i < segments; i++) {
857       if (msptr[i].vlist != NULL) {
858          for (j=0; j < msptr[i].n; j++) {
859             xpptr->x = msptr[i].vlist[j].x;
860             xpptr->y = msptr[i].vlist[j].y;
861             xpptr++;
862          }
863          xpptr--;
864          free(msptr[i].vlist);
865       }
866    }
867    free(msptr);
868    *N = total;
869    return splineVs;
870 }
871 
MakeSplinePolygonVertex(Level,Curved,N,XOff,YOff,NumVs,Vs)872 XPoint *MakeSplinePolygonVertex(Level, Curved, N, XOff, YOff, NumVs, Vs)
873    int Level, Curved, *N, XOff, YOff, NumVs;
874    IntPoint *Vs;
875 {
876    double mx1, my1, mx2, my2, mx3, my3, mx4, my4, x1, y1, x2, y2;
877    int i, x_off, y_off, max_n, saved_tighter_splines=tighterStructSplines;
878 
879 #ifdef _TGIF_DBG /* debug, do not translate */
880    TgAssert(Curved != LT_STRUCT_SPLINE,
881          "Curved == LT_STRUCT_SPLINE in MakeSplinePolygonVertex()", NULL);
882 #endif /* _TGIF_DBG */
883 
884    if (Level == 0 && Curved != LT_STRUCT_SPLINE && saved_tighter_splines) {
885       tighterStructSplines = FALSE;
886    }
887    x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
888    y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
889 
890    splineVs = NULL;
891 
892    if (NumVs <= 3) {
893       splineVs = (XPoint *)malloc(5*sizeof(XPoint));
894       if (splineVs == NULL) {
895          FailAllocMessage();
896          *N = 0;
897          tighterStructSplines = saved_tighter_splines;
898          return splineVs;
899       }
900       memset(splineVs, 0, 5*sizeof(XPoint));
901       splineVs[0].x = ZOOMED_SIZE(Vs[0].x-x_off);
902       splineVs[0].y = ZOOMED_SIZE(Vs[0].y-y_off);
903       splineVs[1].x = ZOOMED_SIZE(Vs[1].x-x_off);
904       splineVs[1].y = ZOOMED_SIZE(Vs[1].y-y_off);
905       *N = 2;
906       tighterStructSplines = saved_tighter_splines;
907       return splineVs;
908    }
909    Vs[NumVs].x = Vs[1].x; Vs[NumVs].y = Vs[1].y;
910    x1 = ZOOMED_SIZE(Vs->x-x_off); y1 = ZOOMED_SIZE((Vs++)->y-y_off);
911    x2 = ZOOMED_SIZE(Vs->x-x_off); y2 = ZOOMED_SIZE((Vs++)->y-y_off);
912    mx4 = (x1 + x2) / 2.0;         my4 = (y1 + y2) / 2.0;
913 
914    max_n = 100;
915    splineVs = (XPoint*)malloc((max_n+1)*sizeof(XPoint));
916    if (splineVs == NULL) {
917       FailAllocMessage();
918       *N = 0;
919       tighterStructSplines = saved_tighter_splines;
920       return splineVs;
921    }
922    memset(splineVs, 0, (max_n+1)*sizeof(XPoint));
923    splineVs[0].x = mx4;
924    splineVs[0].y = my4;
925    *N = 1;
926 
927    for (i=1; i < NumVs; i++, Vs++) {
928       mx1 = mx4;                     my1 = my4;
929       mx2 = (x1+3.0*x2)/4.0;         my2 = (y1+3.0*y2)/4.0;
930       x1 = x2;                       y1 = y2;
931       x2 = ZOOMED_SIZE(Vs->x-x_off); y2 = ZOOMED_SIZE(Vs->y-y_off);
932       mx3 = (3.0*x1+x2)/4.0;         my3 = (3.0*y1+y2)/4.0;
933       mx4 = (x1+x2)/2.0;             my4 = (y1+y2)/2.0;
934       SetSplineVs(N, &max_n, mx1, my1, mx2, my2, mx3, my3, mx4, my4);
935    }
936    tighterStructSplines = saved_tighter_splines;
937 
938    return splineVs;
939 }
940 
941 static
DoMakeDoubleIntSplinePolygonVertex(N,XOff,YOff,NumVs,Vs)942 XPoint *DoMakeDoubleIntSplinePolygonVertex(N, XOff, YOff, NumVs, Vs)
943    int *N, XOff, YOff, NumVs;
944    DoublePoint *Vs;
945 {
946    double mx1, my1, mx2, my2, mx3, my3, mx4, my4, x1, y1, x2, y2, x, y;
947    double dx_off, dy_off;
948    int i, max_n, x_off, y_off;
949 
950    x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
951    y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
952 
953    dx_off = (double)x_off;
954    dy_off = (double)y_off;
955 
956    splineVs = NULL;
957 
958    if (NumVs <= 3) {
959       splineVs = (XPoint *)malloc(5*sizeof(XPoint));
960       if (splineVs == NULL) {
961          FailAllocMessage();
962          *N = 0;
963          return splineVs;
964       }
965       memset(splineVs, 0, 5*sizeof(XPoint));
966       x = ZOOMED_DOUBLE_SIZE(Vs[0].x-dx_off);
967       y = ZOOMED_DOUBLE_SIZE(Vs[0].y-dy_off);
968       splineVs[0].x = round(x);
969       splineVs[0].y = round(y);
970       x = ZOOMED_DOUBLE_SIZE(Vs[1].x-dx_off);
971       y = ZOOMED_DOUBLE_SIZE(Vs[1].y-dy_off);
972       splineVs[1].x = round(x);
973       splineVs[1].y = round(y);
974       *N = 2;
975       return splineVs;
976    }
977 
978    Vs[NumVs].x = Vs[1].x; Vs[NumVs].y = Vs[1].y;
979    x1 = ZOOMED_DOUBLE_SIZE(Vs->x-dx_off);
980    y1 = ZOOMED_DOUBLE_SIZE((Vs++)->y-dy_off);
981    x2 = ZOOMED_DOUBLE_SIZE(Vs->x-dx_off);
982    y2 = ZOOMED_DOUBLE_SIZE((Vs++)->y-dy_off);
983    mx4 = (x1 + x2) / 2.0;
984    my4 = (y1 + y2) / 2.0;
985 
986    max_n = 100;
987    splineDoubleVs = (DoublePoint*)malloc((max_n+1)*sizeof(DoublePoint));
988    if (splineDoubleVs == NULL) {
989       FailAllocMessage();
990       *N = 0;
991       return NULL;
992    }
993    memset(splineDoubleVs, 0, (max_n+1)*sizeof(DoublePoint));
994    splineDoubleVs[0].x = mx4;
995    splineDoubleVs[0].y = my4;
996    *N = 1;
997 
998    for (i=1; i < NumVs; i++, Vs++) {
999       mx1 = mx4;                             my1 = my4;
1000       mx2 = (x1+3.0*x2)/4.0;                 my2 = (y1+3.0*y2)/4.0;
1001       x1 = x2;                               y1 = y2;
1002       x2 = ZOOMED_DOUBLE_SIZE(Vs->x-dx_off); y2 = ZOOMED_DOUBLE_SIZE(Vs->y-dy_off);
1003       mx3 = (3.0*x1+x2)/4.0;                 my3 = (3.0*y1+y2)/4.0;
1004       mx4 = (x1+x2)/2.0;                     my4 = (y1+y2)/2.0;
1005       SetDoubleSplineVs(N, &max_n, mx1, my1, mx2, my2, mx3, my3, mx4, my4);
1006    }
1007    splineVs = (XPoint*)malloc(((*N)+2)*sizeof(XPoint));
1008    if (splineVs == NULL) {
1009       FailAllocMessage();
1010       free(splineDoubleVs);
1011       splineDoubleVs = NULL;
1012       *N = 0;
1013       return NULL;
1014    }
1015    memset(splineVs, 0, ((*N)+2)*sizeof(XPoint));
1016    for (i=0; i < *N; i++) {
1017       splineVs[i].x = round(splineDoubleVs[i].x);
1018       splineVs[i].y = round(splineDoubleVs[i].y);
1019    }
1020    free(splineDoubleVs);
1021    splineDoubleVs = NULL;
1022    return splineVs;
1023 }
1024 
MakeMultiSplinePolygonVertex(Curved,N,Smooth,XOff,YOff,NumVs,Vs)1025 XPoint *MakeMultiSplinePolygonVertex(Curved, N, Smooth, XOff, YOff, NumVs, Vs)
1026    int Curved, *N, XOff, YOff, NumVs;
1027    char *Smooth;
1028    IntPoint *Vs;
1029 {
1030    register int i, j;
1031    int num_smooth_points=0, num_hinge_points=0;
1032    int start_index, seg_index, tmp_index;
1033    int total=0, once_around=FALSE;
1034    XPoint *xpptr=NULL;
1035    IntPoint *tmp_vs=NULL;
1036    struct MultiSplineRec *msptr=NULL;
1037 
1038    if (Smooth == NULL) {
1039       return MakeSplinePolygonVertex(0, Curved, N, XOff, YOff, NumVs, Vs);
1040    }
1041    for (i=1; i < NumVs; i++) {
1042       if (Smooth[i]) {
1043          num_smooth_points++;
1044       } else {
1045          num_hinge_points++;
1046       }
1047    }
1048    if (num_smooth_points == 0) {
1049       *N = NumVs;
1050       return MakePolygonVertex(XOff, YOff, NumVs, Vs);
1051    }
1052    if (num_hinge_points == 0) {
1053       return MakeSplinePolygonVertex(0, Curved, N, XOff, YOff, NumVs, Vs);
1054    }
1055    msptr = (struct MultiSplineRec *)malloc(num_hinge_points *
1056          sizeof(struct MultiSplineRec));
1057    if (msptr == NULL) FailAllocMessage();
1058    memset(msptr, 0, num_hinge_points*sizeof(struct MultiSplineRec));
1059 
1060    for (i=0; i < NumVs; i++) {
1061       if (!Smooth[i]) {
1062          break;
1063       }
1064    }
1065    tmp_vs = (IntPoint*)malloc((NumVs+1)*sizeof(IntPoint));
1066    if (tmp_vs == NULL) FailAllocMessage();
1067    memset(tmp_vs, 0, (NumVs+1)*sizeof(IntPoint));
1068    start_index = i;
1069    seg_index = 0;
1070 
1071    tmp_vs[0].x = Vs[start_index].x;
1072    tmp_vs[0].y = Vs[start_index].y;
1073    tmp_index = 1;
1074    for (i=start_index+1; !(once_around && i==start_index+1); i++, tmp_index++) {
1075       tmp_vs[tmp_index].x = Vs[i].x;
1076       tmp_vs[tmp_index].y = Vs[i].y;
1077       if (!Smooth[i]) {
1078          msptr[seg_index].vlist = MakeSplinePolyVertex(0, Curved,
1079                &msptr[seg_index].n, XOff, YOff, tmp_index+1, tmp_vs);
1080          total += msptr[seg_index].n-1;
1081          seg_index++;
1082          start_index = (i==NumVs-1 ? 0 : i);
1083          tmp_vs[0].x = Vs[start_index].x;
1084          tmp_vs[0].y = Vs[start_index].y;
1085          tmp_index = 0;
1086       }
1087       if (i == NumVs-1) {
1088          i = 0;
1089          once_around = TRUE;
1090       }
1091    }
1092    if (tmp_vs != NULL) free(tmp_vs);
1093    if (total > 0) total++;
1094    splineVs = (XPoint*)malloc((total+2)*sizeof(XPoint));
1095    if (splineVs == NULL) FailAllocMessage();
1096    memset(splineVs, 0, (total+2)*sizeof(XPoint));
1097    xpptr = splineVs;
1098    for (i=0; i < num_hinge_points; i++) {
1099       if (msptr[i].vlist != NULL) {
1100          for (j=0; j < msptr[i].n; j++) {
1101             xpptr->x = msptr[i].vlist[j].x;
1102             xpptr->y = msptr[i].vlist[j].y;
1103             xpptr++;
1104          }
1105          xpptr--;
1106          free(msptr[i].vlist);
1107       }
1108    }
1109    free(msptr);
1110    *N = total;
1111    return splineVs;
1112 }
1113 
1114 struct MtxRec {
1115    double *x, *y, *dx, *dy;
1116    double **mtx;
1117 } mtxInfo;
1118 
1119 static
OpenSetupMatrix(NumPts,Vs)1120 void OpenSetupMatrix(NumPts, Vs)
1121    int NumPts;
1122    IntPoint *Vs;
1123 {
1124    register int i;
1125 
1126    mtxInfo.x = (double*)malloc(NumPts*sizeof(double));
1127    mtxInfo.y = (double*)malloc(NumPts*sizeof(double));
1128    mtxInfo.dx = (double*)malloc(NumPts*sizeof(double));
1129    mtxInfo.dy = (double*)malloc(NumPts*sizeof(double));
1130    if (mtxInfo.x == NULL || mtxInfo.y == NULL || mtxInfo.dx == NULL ||
1131          mtxInfo.dy == NULL) {
1132       FailAllocMessage();
1133    }
1134    for (i=0; i < NumPts; i++) {
1135       mtxInfo.x[i] = mtxInfo.dx[i] = ((double)(Vs[i].x))*((double)theSum);
1136       mtxInfo.y[i] = mtxInfo.dy[i] = ((double)(Vs[i].y))*((double)theSum);
1137    }
1138    mtxInfo.mtx = (double**)malloc(NumPts*sizeof(double*));
1139    if (mtxInfo.mtx == NULL) FailAllocMessage();
1140    memset(mtxInfo.mtx, 0, NumPts*sizeof(double*));
1141    for (i=0; i < NumPts; i++) {
1142       mtxInfo.mtx[i] = (double*)malloc(3*sizeof(double));
1143       if (mtxInfo.mtx[i] == NULL) FailAllocMessage();
1144       memset(mtxInfo.mtx[i], 0, 3*sizeof(double));
1145    }
1146    mtxInfo.mtx[0][0] = mtxInfo.mtx[NumPts-1][2] = (double)0.0;
1147    mtxInfo.mtx[0][1] = mtxInfo.mtx[NumPts-1][1] = (double)theSum;
1148    mtxInfo.mtx[0][2] = mtxInfo.mtx[NumPts-1][0] = (double)0.0;
1149    for (i=1; i < NumPts-1; i++) {
1150       mtxInfo.mtx[i][0] = (double)1.0;
1151       mtxInfo.mtx[i][1] = (double)SUM_MINUS_2;
1152       mtxInfo.mtx[i][2] = (double)1.0;
1153    }
1154 }
1155 
1156 static
TriGaussian(NumPts)1157 void TriGaussian(NumPts)
1158    int NumPts;
1159 {
1160    register int i;
1161    register double val;
1162 
1163    for (i=1; i<NumPts-1; i++) {
1164       val = (-mtxInfo.mtx[i-1][1]);
1165       mtxInfo.mtx[i][0] = (double)0.0;
1166       mtxInfo.mtx[i][1] = (mtxInfo.mtx[i][1]*val+mtxInfo.mtx[i-1][2])/theSum;
1167       mtxInfo.mtx[i][2] = val/theSum;
1168       mtxInfo.x[i] = (mtxInfo.x[i]*val+mtxInfo.x[i-1])/theSum;
1169       mtxInfo.y[i] = (mtxInfo.y[i]*val+mtxInfo.y[i-1])/theSum;
1170    }
1171    mtxInfo.x[i] = mtxInfo.x[i]/mtxInfo.mtx[i][1];
1172    mtxInfo.y[i] = mtxInfo.y[i]/mtxInfo.mtx[i][1];
1173    for (i--; i>=0; i--) {
1174       mtxInfo.x[i] = (mtxInfo.x[i]-mtxInfo.x[i+1]*mtxInfo.mtx[i][2]) /
1175             mtxInfo.mtx[i][1];
1176       mtxInfo.y[i] = (mtxInfo.y[i]-mtxInfo.y[i+1]*mtxInfo.mtx[i][2]) /
1177             mtxInfo.mtx[i][1];
1178    }
1179 }
1180 
1181 static
FreeMtxInfo(NumPts)1182 void FreeMtxInfo(NumPts)
1183    int NumPts;
1184 {
1185    register int i;
1186 
1187    if (mtxInfo.x != NULL) free(mtxInfo.x);
1188    if (mtxInfo.y != NULL) free(mtxInfo.y);
1189    if (mtxInfo.dx != NULL) free(mtxInfo.dx);
1190    if (mtxInfo.dy != NULL) free(mtxInfo.dy);
1191    if (mtxInfo.mtx != NULL) {
1192       for (i=0; i < NumPts; i++) {
1193          if (mtxInfo.mtx[i] != NULL) free(mtxInfo.mtx[i]);
1194       }
1195       free(mtxInfo.mtx);
1196    }
1197    memset(&mtxInfo, 0, sizeof(struct MtxRec));
1198 }
1199 
1200 static
OpenControlPts(NumPts,N)1201 IntPoint *OpenControlPts(NumPts, N)
1202    int NumPts, *N;
1203 {
1204    register int i;
1205    int index=0;
1206    double half=theSum/((double)2.0);
1207    double weight=half-((double)1.0);
1208    IntPoint *v;
1209 
1210    v = (IntPoint*)malloc((((NumPts-2)<<1)+2)*sizeof(IntPoint));
1211    if (v == NULL) FailAllocMessage();
1212    memset(v, 0, (((NumPts-2)<<1)+2)*sizeof(IntPoint));
1213 
1214    v[index].x = (int)(mtxInfo.x[0]);
1215    v[index].y = (int)(mtxInfo.y[0]);
1216    index++;
1217    v[index].x = (int)((mtxInfo.x[0]+weight*mtxInfo.x[1])/half);
1218    v[index].y = (int)((mtxInfo.y[0]+weight*mtxInfo.y[1])/half);
1219    index++;
1220    for (i=1; i<NumPts-2; i++) {
1221       v[index].x = (int)((weight*mtxInfo.x[i]+mtxInfo.x[i+1])/half);
1222       v[index].y = (int)((weight*mtxInfo.y[i]+mtxInfo.y[i+1])/half);
1223       index++;
1224       v[index].x = (int)((mtxInfo.x[i]+weight*mtxInfo.x[i+1])/half);
1225       v[index].y = (int)((mtxInfo.y[i]+weight*mtxInfo.y[i+1])/half);
1226       index++;
1227    }
1228    v[index].x = (int)((weight*mtxInfo.x[i]+mtxInfo.x[i+1])/half);
1229    v[index].y = (int)((weight*mtxInfo.y[i]+mtxInfo.y[i+1])/half);
1230    index++;
1231    v[index].x = (int)(mtxInfo.x[NumPts-1]);
1232    v[index].y = (int)(mtxInfo.y[NumPts-1]);
1233    index++;
1234 
1235    FreeMtxInfo(NumPts);
1236 
1237    *N = index;
1238    return v;
1239 }
1240 
MakeIntSplinePolyVertex(N,CntrlN,CntrlVs,XOff,YOff,NumVs,Vs)1241 XPoint *MakeIntSplinePolyVertex(N, CntrlN, CntrlVs, XOff, YOff, NumVs, Vs)
1242    int *N, *CntrlN, XOff, YOff, NumVs;
1243    IntPoint **CntrlVs, *Vs;
1244 {
1245    int x_off, y_off;
1246 
1247    x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
1248    y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
1249 
1250    splineVs = NULL;
1251 
1252    switch (NumVs) {
1253    case 0:
1254    case 1:
1255       break;
1256    case 2:
1257       *CntrlVs = (IntPoint*)malloc((NumVs+1)*sizeof(IntPoint));
1258       if (*CntrlVs == NULL) FailAllocMessage();
1259       memset(*CntrlVs, 0, (NumVs+1)*sizeof(IntPoint));
1260       splineVs = (XPoint*)malloc((NumVs+1)*sizeof(XPoint));
1261       if (splineVs == NULL) {
1262          FailAllocMessage();
1263          *N = 0;
1264          return splineVs;
1265       }
1266       memset(splineVs, 0, (NumVs+1)*sizeof(XPoint));
1267       splineVs[0].x = ZOOMED_SIZE(Vs[0].x-x_off);
1268       splineVs[0].y = ZOOMED_SIZE(Vs[0].y-y_off);
1269       splineVs[1].x = ZOOMED_SIZE(Vs[1].x-x_off);
1270       splineVs[1].y = ZOOMED_SIZE(Vs[1].y-y_off);
1271       (*CntrlVs)[0].x = Vs[0].x;
1272       (*CntrlVs)[0].y = Vs[0].y;
1273       (*CntrlVs)[1].x = Vs[1].x;
1274       (*CntrlVs)[1].y = Vs[1].y;
1275       *N = *CntrlN = 2;
1276       break;
1277    default:
1278       OpenSetupMatrix(NumVs, Vs);
1279       TriGaussian(NumVs);
1280       *CntrlVs = OpenControlPts(NumVs, CntrlN);
1281 
1282       return MakeSplinePolyVertex(0, LT_INTSPLINE, N, XOff, YOff, *CntrlN,
1283             *CntrlVs);
1284    }
1285    return splineVs;
1286 }
1287 
1288 static
ClosedSetupMatrix(NumPts,Vs)1289 void ClosedSetupMatrix(NumPts, Vs)
1290    int NumPts;
1291    IntPoint *Vs;
1292 {
1293    register int i;
1294    register double val;
1295 
1296    mtxInfo.x = (double*)malloc(NumPts*sizeof(double));
1297    mtxInfo.y = (double*)malloc(NumPts*sizeof(double));
1298    mtxInfo.dx = (double*)malloc(NumPts*sizeof(double));
1299    mtxInfo.dy = (double*)malloc(NumPts*sizeof(double));
1300    if (mtxInfo.x == NULL || mtxInfo.y == NULL || mtxInfo.dx == NULL ||
1301          mtxInfo.dy == NULL) {
1302       FailAllocMessage();
1303    }
1304    for (i=0; i < NumPts; i++) {
1305       mtxInfo.x[i] = mtxInfo.dx[i] = ((double)(Vs[i].x))*((double)theSum);
1306       mtxInfo.y[i] = mtxInfo.dy[i] = ((double)(Vs[i].y))*((double)theSum);
1307    }
1308    /* the first NumPts-2 rows have an extra column */
1309    mtxInfo.mtx = (double**)malloc(NumPts*sizeof(double*));
1310    if (mtxInfo.mtx == NULL) FailAllocMessage();
1311    memset(mtxInfo.mtx, 0, NumPts*sizeof(double*));
1312    for (i=0; i < NumPts; i++) {
1313       mtxInfo.mtx[i] = (double*)malloc(4*sizeof(double));
1314       if (mtxInfo.mtx[i] == NULL) FailAllocMessage();
1315       memset(mtxInfo.mtx[i], 0, 4*sizeof(double));
1316    }
1317    mtxInfo.mtx[0][0] = mtxInfo.mtx[NumPts-1][2] = (double)1.0;
1318    mtxInfo.mtx[0][1] = mtxInfo.mtx[NumPts-1][1] = (double)SUM_MINUS_2;
1319    mtxInfo.mtx[0][2] = mtxInfo.mtx[NumPts-1][0] = (double)1.0;
1320    mtxInfo.mtx[0][3] = (double)1.0;
1321    /* use mtx[NumPts-1][3] as mtx[NumPts-1][i] where i is moving to right */
1322    mtxInfo.mtx[NumPts-1][3] = (double)0.0;
1323    for (i=1; i < NumPts-1; i++) {
1324       mtxInfo.mtx[i][0] = (double)1.0;
1325       mtxInfo.mtx[i][1] = (double)SUM_MINUS_2;
1326       mtxInfo.mtx[i][2] = (double)1.0;
1327       mtxInfo.mtx[i][3] = (double)0.0;
1328    }
1329    val = (-mtxInfo.mtx[0][1]);
1330    if (NumPts == 3) {
1331       mtxInfo.mtx[NumPts-1][0] =
1332             (mtxInfo.mtx[NumPts-1][0]*val+mtxInfo.mtx[0][2])/theSum;
1333    } else {
1334       mtxInfo.mtx[NumPts-1][0] = mtxInfo.mtx[NumPts-1][0]*val/theSum;
1335    }
1336    mtxInfo.mtx[NumPts-1][1] =
1337          (mtxInfo.mtx[NumPts-1][1]*val+mtxInfo.mtx[0][3])/theSum;
1338    /* use mtx[NumPts-1][3] as mtx[NumPts-1][i] where i moves to right */
1339    mtxInfo.mtx[NumPts-1][3] = mtxInfo.mtx[0][2]/theSum;
1340    mtxInfo.x[NumPts-1] = (mtxInfo.x[NumPts-1]*val+mtxInfo.x[0])/theSum;
1341    mtxInfo.y[NumPts-1] = (mtxInfo.y[NumPts-1]*val+mtxInfo.y[0])/theSum;
1342 }
1343 
1344 static
DoubleClosedSetupMatrix(NumPts,Vs)1345 void DoubleClosedSetupMatrix(NumPts, Vs)
1346    int NumPts;
1347    DoublePoint *Vs;
1348 {
1349    register int i;
1350    register double val;
1351 
1352    mtxInfo.x = (double*)malloc(NumPts*sizeof(double));
1353    mtxInfo.y = (double*)malloc(NumPts*sizeof(double));
1354    mtxInfo.dx = (double*)malloc(NumPts*sizeof(double));
1355    mtxInfo.dy = (double*)malloc(NumPts*sizeof(double));
1356    if (mtxInfo.x == NULL || mtxInfo.y == NULL || mtxInfo.dx == NULL ||
1357          mtxInfo.dy == NULL) {
1358       FailAllocMessage();
1359    }
1360    for (i=0; i < NumPts; i++) {
1361       mtxInfo.x[i] = mtxInfo.dx[i] = ((double)(Vs[i].x))*((double)theSum);
1362       mtxInfo.y[i] = mtxInfo.dy[i] = ((double)(Vs[i].y))*((double)theSum);
1363    }
1364    /* the first NumPts-2 rows have an extra column */
1365    mtxInfo.mtx = (double**)malloc(NumPts*sizeof(double*));
1366    if (mtxInfo.mtx == NULL) FailAllocMessage();
1367    memset(mtxInfo.mtx, 0, NumPts*sizeof(double*));
1368    for (i=0; i < NumPts; i++) {
1369       mtxInfo.mtx[i] = (double*)malloc(4*sizeof(double));
1370       if (mtxInfo.mtx[i] == NULL) FailAllocMessage();
1371       memset(mtxInfo.mtx[i], 0, 4*sizeof(double));
1372    }
1373    mtxInfo.mtx[0][0] = mtxInfo.mtx[NumPts-1][2] = (double)1.0;
1374    mtxInfo.mtx[0][1] = mtxInfo.mtx[NumPts-1][1] = (double)SUM_MINUS_2;
1375    mtxInfo.mtx[0][2] = mtxInfo.mtx[NumPts-1][0] = (double)1.0;
1376    mtxInfo.mtx[0][3] = (double)1.0;
1377    /* use mtx[NumPts-1][3] as mtx[NumPts-1][i] where i is moving to right */
1378    mtxInfo.mtx[NumPts-1][3] = (double)0.0;
1379    for (i=1; i < NumPts-1; i++) {
1380       mtxInfo.mtx[i][0] = (double)1.0;
1381       mtxInfo.mtx[i][1] = (double)SUM_MINUS_2;
1382       mtxInfo.mtx[i][2] = (double)1.0;
1383       mtxInfo.mtx[i][3] = (double)0.0;
1384    }
1385    val = (-mtxInfo.mtx[0][1]);
1386    if (NumPts == 3) {
1387       mtxInfo.mtx[NumPts-1][0] =
1388             (mtxInfo.mtx[NumPts-1][0]*val+mtxInfo.mtx[0][2])/theSum;
1389    } else {
1390       mtxInfo.mtx[NumPts-1][0] = mtxInfo.mtx[NumPts-1][0]*val/theSum;
1391    }
1392    mtxInfo.mtx[NumPts-1][1] =
1393          (mtxInfo.mtx[NumPts-1][1]*val+mtxInfo.mtx[0][3])/theSum;
1394    /* use mtx[NumPts-1][3] as mtx[NumPts-1][i] where i moves to right */
1395    mtxInfo.mtx[NumPts-1][3] = mtxInfo.mtx[0][2]/theSum;
1396    mtxInfo.x[NumPts-1] = (mtxInfo.x[NumPts-1]*val+mtxInfo.x[0])/theSum;
1397    mtxInfo.y[NumPts-1] = (mtxInfo.y[NumPts-1]*val+mtxInfo.y[0])/theSum;
1398 }
1399 
1400 static int gaussIteration=0;
1401 
1402 #ifdef NOT_DEFINED
1403 #ifdef _TGIF_DBG
1404 static
DebugClosedMatrix(NumPts)1405 void DebugClosedMatrix(NumPts)
1406    int NumPts;
1407 {
1408    int j, i;
1409 
1410    /* mtxInfo.mtx[0][3] is actually mtxInfo.mtx[0][NumPts-1]           */
1411    /* mtxInfo.mtx[NumPts-1][3] is actually mtxInfo.mtx[NumPts-1][i+1]  */
1412    /*       where i is the current iteration in gaussian elimincation; */
1413    /*       before gaussian() is called, i is 0                        */
1414    printf("|  %+8.2f  %+8.2f  ", mtxInfo.mtx[0][1], mtxInfo.mtx[0][2]);
1415    for (j=2; j<NumPts-1; j++) printf("          ");
1416    printf("%+8.2f  |  (%+8.2f,%+8.2f)\n", mtxInfo.mtx[0][3],
1417          mtxInfo.x[0], mtxInfo.y[0]);
1418    for (i=1; i<NumPts-1; i++) {
1419       if (i == NumPts-2) {
1420          printf("|  ");
1421          for (j=1; j<i; j++) printf("          ");
1422          printf("%+8.2f  %+8.2f  %+8.2f  ", mtxInfo.mtx[i][0],
1423                mtxInfo.mtx[i][1], mtxInfo.mtx[i][2]);
1424          for (j=i+2; j<NumPts; j++) printf("          ");
1425          printf("|  (%+8.2f,%+8.2f)\n", mtxInfo.x[i], mtxInfo.y[i]);
1426       } else {
1427          printf("|  ");
1428          for (j=1; j<i; j++) printf("          ");
1429          printf("%+8.2f  %+8.2f  %+8.2f  ", mtxInfo.mtx[i][0],
1430                mtxInfo.mtx[i][1], mtxInfo.mtx[i][2]);
1431          for (j=i+2; j<NumPts-1; j++) printf("          ");
1432          printf("%+8.2f  |  (%+8.2f,%+8.2f)\n", mtxInfo.mtx[i][3],
1433                mtxInfo.x[i], mtxInfo.y[i]);
1434       }
1435    }
1436    printf("|  ");
1437    if (gaussIteration+2 < i) {
1438       for (j=1; j<gaussIteration+2; j++) printf("          ");
1439       printf("%+8.2f  ", mtxInfo.mtx[i][3]);
1440       for (j=gaussIteration+3; j<i; j++) printf("          ");
1441    } else {
1442       for (j=1; j<i; j++) printf("          ");
1443    }
1444    printf("%+8.2f  %+8.2f  ", mtxInfo.mtx[i][0], mtxInfo.mtx[i][1]);
1445    printf("|  (%+8.2f,%+8.2f)\n", mtxInfo.x[i], mtxInfo.y[i]);
1446 }
1447 #endif /* _TGIF_DBG */
1448 #endif /* NOT_DEFINED */
1449 
1450 static
Gaussian(NumPts)1451 void Gaussian(NumPts)
1452    int NumPts;
1453 {
1454    register int i;
1455    register double val;
1456 
1457    gaussIteration = 0;
1458 #ifdef _TGIF_DBG
1459    /* DebugClosedMatrix(NumPts); */
1460 #endif /* _TGIF_DBG */
1461    for (i=1; i<NumPts-1; i++) {
1462       val = (-mtxInfo.mtx[i-1][1]);
1463       mtxInfo.mtx[i][0] = (double)0.0;
1464       mtxInfo.mtx[i][1] = (mtxInfo.mtx[i][1]*val+mtxInfo.mtx[i-1][2])/theSum;
1465       if (i == NumPts-2) {
1466          mtxInfo.mtx[i][2] = (mtxInfo.mtx[i][2]*val+mtxInfo.mtx[i-1][3])/theSum;
1467       } else {
1468          mtxInfo.mtx[i][2] = val/theSum;
1469       }
1470       mtxInfo.x[i] = (mtxInfo.x[i]*val+mtxInfo.x[i-1])/theSum;
1471       mtxInfo.y[i] = (mtxInfo.y[i]*val+mtxInfo.y[i-1])/theSum;
1472       if (i != NumPts-2) {
1473          mtxInfo.mtx[i][3] = mtxInfo.mtx[i-1][3]/theSum;;
1474       }
1475       val = (-mtxInfo.mtx[i][1])/mtxInfo.mtx[NumPts-1][3];
1476       if (i < NumPts-2) {
1477          if (i < NumPts-3) {
1478             mtxInfo.mtx[NumPts-1][0] = mtxInfo.mtx[NumPts-1][0]*val/theSum;
1479          } else {
1480             mtxInfo.mtx[NumPts-1][0] =
1481                   (mtxInfo.mtx[NumPts-1][0]*val+mtxInfo.mtx[i][2])/theSum;
1482          }
1483          mtxInfo.mtx[NumPts-1][1] =
1484                (mtxInfo.mtx[NumPts-1][1]*val+mtxInfo.mtx[i][3])/theSum;
1485          mtxInfo.mtx[NumPts-1][3] = mtxInfo.mtx[i][2]/theSum;
1486          mtxInfo.x[NumPts-1] = (mtxInfo.x[NumPts-1]*val+mtxInfo.x[i])/theSum;
1487          mtxInfo.y[NumPts-1] = (mtxInfo.y[NumPts-1]*val+mtxInfo.y[i])/theSum;
1488       }
1489       gaussIteration++;
1490 #ifdef _TGIF_DBG
1491       /* DebugClosedMatrix(NumPts); */
1492 #endif /* _TGIF_DBG */
1493    }
1494    val = (-mtxInfo.mtx[i-1][1])/mtxInfo.mtx[i][0];
1495    mtxInfo.mtx[i][0] = (double)0.0;
1496    mtxInfo.mtx[i][1] = (mtxInfo.mtx[i][1]*val+mtxInfo.mtx[i-1][2])/theSum;
1497    mtxInfo.x[i] = (mtxInfo.x[i]*val+mtxInfo.x[i-1])/theSum;
1498    mtxInfo.y[i] = (mtxInfo.y[i]*val+mtxInfo.y[i-1])/theSum;
1499 
1500    mtxInfo.x[i] = mtxInfo.x[i]/mtxInfo.mtx[i][1];
1501    mtxInfo.y[i] = mtxInfo.y[i]/mtxInfo.mtx[i][1];
1502    for (i--; i>=0; i--) {
1503       if (i == NumPts-2) {
1504          mtxInfo.x[i] = (mtxInfo.x[i]-mtxInfo.x[i+1]*mtxInfo.mtx[i][2]) /
1505                mtxInfo.mtx[i][1];
1506          mtxInfo.y[i] = (mtxInfo.y[i]-mtxInfo.y[i+1]*mtxInfo.mtx[i][2]) /
1507                mtxInfo.mtx[i][1];
1508       } else {
1509          mtxInfo.x[i] = (mtxInfo.x[i]-mtxInfo.x[i+1]*mtxInfo.mtx[i][2] -
1510                mtxInfo.x[NumPts-1]*mtxInfo.mtx[i][3])/mtxInfo.mtx[i][1];
1511          mtxInfo.y[i] = (mtxInfo.y[i]-mtxInfo.y[i+1]*mtxInfo.mtx[i][2] -
1512                mtxInfo.y[NumPts-1]*mtxInfo.mtx[i][3])/mtxInfo.mtx[i][1];
1513       }
1514    }
1515 #ifdef _TGIF_DBG
1516    /* DebugClosedMatrix(NumPts); */
1517 #endif /* _TGIF_DBG */
1518 }
1519 
1520 static
ClosedControlPts(NumPts,N)1521 IntPoint *ClosedControlPts(NumPts, N)
1522    int NumPts, *N;
1523 {
1524    register int i;
1525    int index=0;
1526    double half=theSum/((double)2.0);
1527    double weight=half-((double)1.0);
1528    IntPoint *v;
1529 
1530    v = (IntPoint*)malloc(((NumPts<<1)+2)*sizeof(IntPoint));
1531    if (v == NULL) FailAllocMessage();
1532    memset(v, 0, ((NumPts<<1)+2)*sizeof(IntPoint));
1533    for (i=0; i<NumPts; i++) {
1534       v[index].x = (int)((weight*mtxInfo.x[i]+mtxInfo.x[(i+1) % NumPts])/half);
1535       v[index].y = (int)((weight*mtxInfo.y[i]+mtxInfo.y[(i+1) % NumPts])/half);
1536       index++;
1537       v[index].x = (int)((mtxInfo.x[i]+weight*mtxInfo.x[(i+1) % NumPts])/half);
1538       v[index].y = (int)((mtxInfo.y[i]+weight*mtxInfo.y[(i+1) % NumPts])/half);
1539       index++;
1540    }
1541    v[index].x = (int)((weight*mtxInfo.x[0]+mtxInfo.x[1])/half);
1542    v[index].y = (int)((weight*mtxInfo.y[0]+mtxInfo.y[1])/half);
1543    index++;
1544 
1545    FreeMtxInfo(NumPts);
1546 
1547    *N = index;
1548    return v;
1549 }
1550 
1551 static
DoubleClosedControlPts(NumPts,N)1552 DoublePoint *DoubleClosedControlPts(NumPts, N)
1553    int NumPts, *N;
1554 {
1555    register int i;
1556    int index=0;
1557    double half=theSum/((double)2.0);
1558    double weight=half-((double)1.0);
1559    DoublePoint *v;
1560 
1561    v = (DoublePoint*)malloc(((NumPts<<1)+2)*sizeof(DoublePoint));
1562    if (v == NULL) FailAllocMessage();
1563    memset(v, 0, ((NumPts<<1)+2)*sizeof(DoublePoint));
1564    for (i=0; i<NumPts; i++) {
1565       v[index].x = ((weight*mtxInfo.x[i]+mtxInfo.x[(i+1) % NumPts])/half);
1566       v[index].y = ((weight*mtxInfo.y[i]+mtxInfo.y[(i+1) % NumPts])/half);
1567       index++;
1568       v[index].x = ((mtxInfo.x[i]+weight*mtxInfo.x[(i+1) % NumPts])/half);
1569       v[index].y = ((mtxInfo.y[i]+weight*mtxInfo.y[(i+1) % NumPts])/half);
1570       index++;
1571    }
1572    v[index].x = ((weight*mtxInfo.x[0]+mtxInfo.x[1])/half);
1573    v[index].y = ((weight*mtxInfo.y[0]+mtxInfo.y[1])/half);
1574    index++;
1575 
1576    FreeMtxInfo(NumPts);
1577 
1578    *N = index;
1579    return v;
1580 }
1581 
MakeIntSplinePolygonVertex(N,CntrlN,CntrlVs,XOff,YOff,NumVs,Vs)1582 XPoint *MakeIntSplinePolygonVertex(N, CntrlN, CntrlVs, XOff, YOff, NumVs, Vs)
1583    int *N, *CntrlN, XOff, YOff, NumVs;
1584    IntPoint **CntrlVs, *Vs;
1585 {
1586    int x_off, y_off;
1587 
1588    x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
1589    y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
1590 
1591    splineVs = NULL;
1592 
1593    if (NumVs <= 3) {
1594       splineVs = (XPoint *)malloc(5*sizeof(XPoint));
1595       if (splineVs == NULL) {
1596          FailAllocMessage();
1597          *N = 0;
1598          return (splineVs);
1599       }
1600       memset(splineVs, 0, 5*sizeof(XPoint));
1601       splineVs[0].x = ZOOMED_SIZE(Vs[0].x-x_off);
1602       splineVs[0].y = ZOOMED_SIZE(Vs[0].y-y_off);
1603       splineVs[1].x = ZOOMED_SIZE(Vs[1].x-x_off);
1604       splineVs[1].y = ZOOMED_SIZE(Vs[1].y-y_off);
1605       *N = *CntrlN = 2;
1606       return splineVs;
1607    }
1608    gaussIteration = 0;
1609    NumVs--; /* drop the duplicated end point */
1610    ClosedSetupMatrix(NumVs, Vs);
1611    Gaussian(NumVs);
1612    *CntrlVs = ClosedControlPts(NumVs, CntrlN);
1613 
1614    return MakeSplinePolygonVertex(0, LT_INTSPLINE, N, XOff, YOff, *CntrlN,
1615          *CntrlVs);
1616 }
1617 
MakeDoubleIntSplinePolygonVertex(N,CntrlN,CntrlVs,XOff,YOff,NumVs,Vs)1618 XPoint *MakeDoubleIntSplinePolygonVertex(N, CntrlN, CntrlVs, XOff, YOff,
1619       NumVs, Vs)
1620    int *N, *CntrlN, XOff, YOff, NumVs;
1621    DoublePoint **CntrlVs, *Vs;
1622 {
1623    int x_off=0, y_off=0;
1624    int saved_tighter_splines=tighterStructSplines;
1625    XPoint *pxp=NULL;
1626 
1627    x_off = (zoomedIn ? XOff : (XOff>>zoomScale)<<zoomScale);
1628    y_off = (zoomedIn ? YOff : (YOff>>zoomScale)<<zoomScale);
1629 
1630    splineVs = NULL;
1631 
1632    if (NumVs <= 3) {
1633       double x, y;
1634 
1635       splineVs = (XPoint *)malloc(5*sizeof(XPoint));
1636       if (splineVs == NULL) {
1637          FailAllocMessage();
1638          *N = 0;
1639          return splineVs;
1640       }
1641       memset(splineVs, 0, 5*sizeof(XPoint));
1642       x = ZOOMED_DOUBLE_SIZE(Vs[0].x-((double)x_off));
1643       y = ZOOMED_DOUBLE_SIZE(Vs[0].y-((double)y_off));
1644       splineVs[0].x = round(x);
1645       splineVs[0].y = round(y);
1646       x = ZOOMED_DOUBLE_SIZE(Vs[1].x-((double)x_off));
1647       y = ZOOMED_DOUBLE_SIZE(Vs[1].y-((double)y_off));
1648       splineVs[1].x = round(x);
1649       splineVs[1].y = round(y);
1650       *N = *CntrlN = 2;
1651       return splineVs;
1652    }
1653    gaussIteration = 0;
1654    NumVs--; /* drop the duplicated end point */
1655    DoubleClosedSetupMatrix(NumVs, Vs);
1656    Gaussian(NumVs);
1657    *CntrlVs = DoubleClosedControlPts(NumVs, CntrlN);
1658 
1659    if (saved_tighter_splines) {
1660       tighterStructSplines = FALSE;
1661    }
1662    pxp = DoMakeDoubleIntSplinePolygonVertex(N, XOff, YOff, *CntrlN, *CntrlVs);
1663    tighterStructSplines = saved_tighter_splines;
1664 
1665    return pxp;
1666 }
1667 
DumpCurvedPolyPoints(FP,Curved,NumPts,V,Indent)1668 void DumpCurvedPolyPoints(FP, Curved, NumPts, V, Indent)
1669    FILE *FP;
1670    int Curved, NumPts, Indent;
1671    register IntPoint *V;
1672 {
1673    register int j, i;
1674    double x1, y1, x2, y2;
1675    double mx1, my1, mx2, my2, mx3, my3, mx4, my4;
1676    int saved_tighter_splines=tighterStructSplines;
1677 
1678    if (Curved != LT_STRUCT_SPLINE && saved_tighter_splines) {
1679       tighterStructSplines = FALSE;
1680    }
1681    switch (NumPts) {
1682    case 0:
1683    case 1:
1684    case 2:
1685       break;
1686    case 3:
1687       mx1 = V->x; my1 = (V++)->y;
1688       x1 = V->x; y1 = (V++)->y;
1689       x2 = V->x; y2 = (V++)->y;
1690       mx2 = compCurveToFactor*mx1 + curveToFactor*x1;
1691       my2 = compCurveToFactor*my1 + curveToFactor*y1;
1692       mx3 = curveToFactor*x1 + compCurveToFactor*x2;
1693       my3 = curveToFactor*y1 + compCurveToFactor*y2;
1694       for (j = 0; j < Indent; j++) fprintf(FP, " ");
1695       fprintf(FP, "%.2f %.2f %.2f %.2f\n", mx2, my2, mx3, my3);
1696       break;
1697    default:
1698       if (tighterStructSplines) {
1699 #ifdef _TGIF_DBG /* debug, do not translate */
1700          TgAssert(NumPts <= 4, "NumPts > 4 in DumpCurvedPolyPoints()", NULL);
1701 #endif /* _TGIF_DBG */
1702          mx1 = V->x; my1 = (V++)->y;
1703          x1 = V->x;  y1 = (V++)->y;
1704          x2 = V->x;  y2 = (V++)->y;
1705          mx4 = V->x; my4 = V->y;
1706          for (j = 0; j < Indent; j++) fprintf(FP, " ");
1707          fprintf(FP, "%.2f %.2f %.2f %.2f\n", x1, y1, x2, y2);
1708       } else {
1709          mx1 = V->x; my1 = (V++)->y;
1710          x1 = V->x; y1 = (V++)->y;
1711          x2 = V->x; y2 = (V++)->y;
1712          mx2 = (mx1 + 2.0*x1) / 3.0; my2 = (my1 + 2.0*y1) / 3.0;
1713          mx3 = (5.0*x1 + x2) / 6.0; my3 = (5.0*y1 + y2) / 6.0;
1714          mx4 = (x1 + x2) / 2.0; my4 = (y1 + y2) / 2.0;
1715          for (j = 0; j < Indent; j++) fprintf(FP, " ");
1716          fprintf(FP, "%.2f %.2f %.2f %.2f %.2f %.2f %s\n",
1717                mx2, my2, mx3, my3, mx4, my4, gPsCmd[PS_CURVETO]);
1718 
1719          for (i=2; i < NumPts-2; i++, V++) {
1720             mx2 = (x1 + 5.0*x2) / 6.0; my2 = (y1 + 5.0*y2) / 6.0;
1721             x1 = x2; y1 = y2;
1722 #ifdef stellar
1723             mx3 = (5.0*x1 + V->x) / 6.0; my3 = (5.0*y1 + V->y) / 6.0;
1724             mx4 = (x1 + V->x) / 2.0; my4 = (y1 + V->y) / 2.0;
1725 #else
1726             x2 = V->x; y2 = V->y;
1727             mx3 = (5.0*x1 + x2) / 6.0; my3 = (5.0*y1 + y2) / 6.0;
1728             mx4 = (x1 + x2) / 2.0; my4 = (y1 + y2) / 2.0;
1729 #endif
1730             for (j = 0; j < Indent; j++) fprintf(FP, " ");
1731             fprintf(FP, "%.2f %.2f %.2f %.2f %.2f %.2f %s\n",
1732                   mx2, my2, mx3, my3, mx4, my4, gPsCmd[PS_CURVETO]);
1733 #ifdef stellar
1734             x2 = V->x; y2 = V->y;
1735 #endif
1736          }
1737          mx2 = (x1 + 5.0*x2) / 6.0; my2 = (y1 + 5.0*y2) / 6.0;
1738          x1 = x2; y1 = y2;
1739          mx3 = (2.0*x1 + V->x) / 3.0; my3 = (2.0*y1 + V->y) / 3.0;
1740          for (j = 0; j < Indent; j++) fprintf(FP, " ");
1741          fprintf(FP, "%.2f %.2f %.2f %.2f\n", mx2, my2, mx3, my3);
1742       }
1743       break;
1744    }
1745    tighterStructSplines = saved_tighter_splines;
1746 }
1747 
DumpCurvedPolygonPoints(FP,Curved,NumPts,V,Indent)1748 void DumpCurvedPolygonPoints(FP, Curved, NumPts, V, Indent)
1749    FILE *FP;
1750    int Curved, NumPts, Indent;
1751    register IntPoint *V;
1752 {
1753    register int j;
1754    double mx2, my2, mx3, my3, mx4, my4, x1, y1, x2, y2;
1755    int i;
1756    int saved_tighter_splines=tighterStructSplines;
1757 
1758    if (Curved != LT_STRUCT_SPLINE && saved_tighter_splines) {
1759       tighterStructSplines = FALSE;
1760    }
1761    V[NumPts].x = V[1].x; V[NumPts].y = V[1].y;
1762    x1 = V->x;             y1 = (V++)->y;
1763    x2 = V->x;             y2 = (V++)->y;
1764    mx4 = (x1 + x2) / 2.0; my4 = (y1 + y2) / 2.0;
1765    for (j = 0; j < Indent; j++) fprintf(FP, " ");
1766    fprintf(FP, "%.2f %.2f %s\n", mx4, my4, gPsCmd[PS_MOVETO]);
1767 
1768    for (i=1; i < NumPts; i++, V++) {
1769       mx2 = (x1+5.0*x2)/6.0;   my2 = (y1+5.0*y2)/6.0;
1770       x1 = x2;                 y1 = y2;
1771 #ifdef stellar
1772       mx3 = (5.0*x1+V->x)/6.0; my3 = (5.0*y1+V->y)/6.0;
1773       mx4 = (x1+V->x)/2.0;     my4 = (y1+V->y)/2.0;
1774 #else
1775       x2 = V->x;               y2 = V->y;
1776       mx3 = (5.0*x1+x2)/6.0;   my3 = (5.0*y1+y2)/6.0;
1777       mx4 = (x1+x2)/2.0;       my4 = (y1+y2)/2.0;
1778 #endif
1779       for (j = 0; j < Indent; j++) fprintf(FP, " ");
1780       fprintf(FP, "%.2f %.2f %.2f %.2f %.2f %.2f %s\n",
1781             mx2, my2, mx3, my3, mx4, my4, gPsCmd[PS_CURVETO]);
1782 #ifdef stellar
1783       x2 = V->x;               y2 = V->y;
1784 #endif
1785    }
1786    tighterStructSplines = saved_tighter_splines;
1787 }
1788 
DumpMultiCurvedPolyPoints(FP,Smooth,Style,Curved,NumPts,V,Indent)1789 void DumpMultiCurvedPolyPoints(FP, Smooth, Style, Curved, NumPts, V, Indent)
1790    FILE *FP;
1791    char *Smooth;
1792    int Style, Curved, NumPts, Indent;
1793    register IntPoint *V;
1794 {
1795    register int i, j;
1796    int segments=1, has_smooth_point=FALSE, start_index;
1797 
1798    if (Curved == LT_INTSPLINE || Smooth == NULL) {
1799       DumpCurvedPolyPoints(FP, Curved, NumPts, V, Indent);
1800       return;
1801    }
1802    if (Smooth[0] || Smooth[NumPts-1]) {
1803       FatalUnexpectedError(
1804             TgLoadCachedString(CSTID_CORRUPTED_POLY_DMPMULTICURVE),
1805             TgLoadCachedString(CSTID_FIX_ATTEMPTED));
1806       Smooth[0] = Smooth[NumPts-1] = FALSE;
1807    }
1808    for (i=1; i < NumPts-1; i++) {
1809       if (Smooth[i]) {
1810          has_smooth_point = TRUE;
1811       } else {
1812          segments++;
1813       }
1814    }
1815    if (!has_smooth_point) {
1816       /* simple polyline */
1817       if (Style & LS_RIGHT) {
1818          DumpPoints(FP, NumPts-1, V, Indent);
1819       } else {
1820          DumpPoints(FP, NumPts, V, Indent);
1821       }
1822       return;
1823    }
1824    if (segments == 1) {
1825       /* simple spline */
1826       if (Style & LS_RIGHT) {
1827          if (NumPts != 2) {
1828             DumpCurvedPolyPoints(FP, Curved, NumPts, V, Indent);
1829          } else {
1830             DumpPoints(FP, NumPts-1, V, Indent);
1831          }
1832       } else if (NumPts != 2) {
1833          DumpCurvedPolyPoints(FP, Curved, NumPts, V, Indent);
1834          for (i=0; i < Indent; i++) fprintf(FP, " ");
1835          fprintf(FP, "%1d %1d %s\n", V[NumPts-1].x, V[NumPts-1].y,
1836                gPsCmd[PS_CURVETO]);
1837       } else {
1838          DumpPoints(FP, NumPts, V, Indent);
1839       }
1840       return;
1841    }
1842    start_index = 0;
1843    for (i=1; i <= NumPts-1; i++) {
1844       if (!Smooth[i]) {
1845          int num_tmp_vs=i-start_index+1;
1846 
1847          if (num_tmp_vs == 2) {
1848             if (!(i == NumPts-1 && (Style & LS_RIGHT))) {
1849                DumpPoints(FP, num_tmp_vs, &V[start_index], Indent);
1850             }
1851          } else {
1852             DumpCurvedPolyPoints(FP, Curved, num_tmp_vs, &V[start_index],
1853                   Indent);
1854             if (!(i == NumPts-1 && (Style & LS_RIGHT))) {
1855                for (j=0; j < Indent; j++) fprintf(FP, " ");
1856                fprintf(FP, "%1d %1d %s\n", V[i].x, V[i].y, gPsCmd[PS_CURVETO]);
1857             }
1858          }
1859          start_index = i;
1860       }
1861    }
1862 }
1863 
DumpMultiCurvedPolygonPoints(FP,Smooth,Curved,NumPts,V,Indent)1864 void DumpMultiCurvedPolygonPoints(FP, Smooth, Curved, NumPts, V, Indent)
1865    FILE *FP;
1866    char *Smooth;
1867    int Curved, NumPts, Indent;
1868    register IntPoint *V;
1869 {
1870    register int i, j;
1871    int num_smooth_points=0, num_hinge_points=0, tmp_index;
1872    int start_index, once_around=FALSE;
1873    IntPoint *tmp_vs=NULL;
1874 
1875    if (Curved == LT_INTSPLINE || Smooth == NULL) {
1876       DumpCurvedPolygonPoints(FP, Curved, NumPts, V, Indent);
1877       return;
1878    }
1879    for (i=1; i < NumPts; i++) {
1880       if (Smooth[i]) {
1881          num_smooth_points++;
1882       } else {
1883          num_hinge_points++;
1884       }
1885    }
1886    if (num_smooth_points == 0) {
1887       /* simple polygon */
1888       for (j=0; j < Indent; j++) fprintf(FP, " ");
1889       fprintf(FP, "%1d %1d %s\n", V[0].x, V[0].y, gPsCmd[PS_MOVETO]);
1890       DumpPoints(FP, NumPts-1, V, Indent);
1891       return;
1892    }
1893    if (num_hinge_points == 0) {
1894       DumpCurvedPolygonPoints(FP, Curved, NumPts, V, Indent);
1895       return;
1896    }
1897    tmp_vs = (IntPoint*)malloc((NumPts+1)*sizeof(IntPoint));
1898    if (tmp_vs == NULL) FailAllocMessage();
1899    memset(tmp_vs, 0, (NumPts+1)*sizeof(IntPoint));
1900 
1901    for (i=0; i < NumPts; i++) {
1902       if (!Smooth[i]) {
1903          break;
1904       }
1905    }
1906    for (j=0; j < Indent; j++) fprintf(FP, " ");
1907    fprintf(FP, "%1d %1d %s\n", V[i].x, V[i].y, gPsCmd[PS_MOVETO]);
1908    start_index = i;
1909    tmp_vs[0].x = V[start_index].x;
1910    tmp_vs[0].y = V[start_index].y;
1911    tmp_index = 1;
1912    for (i=start_index+1; !(once_around && i==start_index+1); i++, tmp_index++) {
1913       tmp_vs[tmp_index].x = V[i].x;
1914       tmp_vs[tmp_index].y = V[i].y;
1915       if (!Smooth[i]) {
1916          if (tmp_index == 1) {
1917             DumpPoints(FP, tmp_index+1, tmp_vs, Indent);
1918          } else {
1919             DumpCurvedPolyPoints(FP, Curved, tmp_index+1, tmp_vs, Indent);
1920             for (j=0; j < Indent; j++) fprintf(FP, " ");
1921             fprintf(FP, "%1d %1d %s\n", V[i].x, V[i].y, gPsCmd[PS_CURVETO]);
1922          }
1923          start_index = (i==NumPts-1 ? 0 : i);
1924          tmp_vs[0].x = V[start_index].x;
1925          tmp_vs[0].y = V[start_index].y;
1926          tmp_index = 0;
1927       }
1928       if (i == NumPts-1) {
1929          i = 0;
1930          once_around = TRUE;
1931       }
1932    }
1933    if (tmp_vs != NULL) free(tmp_vs);
1934 }
1935 
1936