1 /* Copyright (C) 2000-2008 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "pfaedit.h"
28 #include <math.h>
29 #include "ustring.h"
30 #include "chardata.h"
31 #include <unistd.h>
32 #include <time.h>
33 #include <stdlib.h>
34 
35 int new_em_size = 1000;
36 int new_fonts_are_order2 = false;
37 int loaded_fonts_same_as_new = false;
38 int default_fv_row_count = 4;
39 int default_fv_col_count = 16;
40 int default_fv_font_size = 24;
41 int default_fv_antialias=true;
42 int default_fv_bbsized=true;
43 int snaptoint=0;
44 
45 /*#define DEBUG	1*/
46 
RealNear(real a,real b)47 int RealNear(real a,real b) {
48     real d;
49 
50 #if 0 /* def FONTFORGE_CONFIG_USE_DOUBLE*/
51     if ( a==0 )
52 return( b>-1e-8 && b<1e-8 );
53     if ( b==0 )
54 return( a>-1e-8 && a<1e-8 );
55 
56     d = a/(1024*1024.);
57     if ( d<0 ) d = -d;
58 return( b>a-d && b<a+d );
59 #else		/* For floats */
60     if ( a==0 )
61 return( b>-1e-5 && b<1e-5 );
62     if ( b==0 )
63 return( a>-1e-5 && a<1e-5 );
64 
65     d = a/(1024*64.);
66     if ( d<0 ) d = -d;
67 return( b>a-d && b<a+d );
68 #endif
69 }
70 
RealNearish(real a,real b)71 int RealNearish(real a,real b) {
72 
73     if ( a-b<.001 && a-b>-.001 )
74 return( true );
75 return( false );
76 }
77 
RealApprox(real a,real b)78 int RealApprox(real a,real b) {
79 
80     if ( a==0 ) {
81 	if ( b<.0001 && b>-.0001 )
82 return( true );
83     } else if ( b==0 ) {
84 	if ( a<.0001 && a>-.0001 )
85 return( true );
86     } else {
87 	a /= b;
88 	if ( a>=.95 && a<=1.05 )
89 return( true );
90     }
91 return( false );
92 }
93 
RealWithin(real a,real b,real fudge)94 int RealWithin(real a,real b,real fudge) {
95 
96 return( b>=a-fudge && b<=a+fudge );
97 }
98 
RealRatio(real a,real b,real fudge)99 int RealRatio(real a,real b,real fudge) {
100 
101     if ( b==0 )
102 return( RealWithin(a,b,fudge));
103 
104 return( RealWithin(a/b,1.0,fudge));
105 }
106 
MinMaxWithin(Spline * spline)107 static int MinMaxWithin(Spline *spline) {
108     extended dx, dy;
109     int which;
110     extended t1, t2;
111     extended w;
112     /* We know that this "spline" is basically one dimensional. As long as its*/
113     /*  extrema are between the start and end points on that line then we can */
114     /*  treat it as a line. If the extrema are way outside the line segment */
115     /*  then it's a line that backtracks on itself */
116 
117     if ( (dx = spline->to->me.x - spline->from->me.x)<0 ) dx = -dx;
118     if ( (dy = spline->to->me.y - spline->from->me.y)<0 ) dy = -dy;
119     which = dx<dy;
120     SplineFindExtrema(&spline->splines[which],&t1,&t2);
121     if ( t1==-1 )
122 return( true );
123     w = ((spline->splines[which].a*t1 + spline->splines[which].b)*t1
124 	     + spline->splines[which].c)*t1 + spline->splines[which].d;
125     if ( RealNear(w, (&spline->to->me.x)[which]) || RealNear(w, (&spline->from->me.x)[which]) )
126 	/* Close enough */;
127     else if ( (w<(&spline->to->me.x)[which] && w<(&spline->from->me.x)[which]) ||
128 	    (w>(&spline->to->me.x)[which] && w>(&spline->from->me.x)[which]) )
129 return( false );		/* Outside */
130 
131     w = ((spline->splines[which].a*t2 + spline->splines[which].b)*t2
132 	     + spline->splines[which].c)*t2 + spline->splines[which].d;
133     if ( RealNear(w, (&spline->to->me.x)[which]) || RealNear(w, (&spline->from->me.x)[which]) )
134 	/* Close enough */;
135     else if ( (w<(&spline->to->me.x)[which] && w<(&spline->from->me.x)[which]) ||
136 	    (w>(&spline->to->me.x)[which] && w>(&spline->from->me.x)[which]) )
137 return( false );		/* Outside */
138 
139 return( true );
140 }
141 
SplineIsLinear(Spline * spline)142 int SplineIsLinear(Spline *spline) {
143     double t1,t2, t3,t4;
144     int ret;
145 
146     if ( spline->knownlinear )
147 return( true );
148     if ( spline->knowncurved )
149 return( false );
150 
151     if ( spline->splines[0].a==0 && spline->splines[0].b==0 &&
152 	    spline->splines[1].a==0 && spline->splines[1].b==0 )
153 return( true );
154 
155     /* Something is linear if the control points lie on the line between the */
156     /*  two base points */
157 
158     /* Vertical lines */
159     if ( RealNear(spline->from->me.x,spline->to->me.x) ) {
160 	ret = RealNear(spline->from->me.x,spline->from->nextcp.x) &&
161 	    RealNear(spline->from->me.x,spline->to->prevcp.x);
162 	if ( ! ((spline->from->nextcp.y >= spline->from->me.y &&
163 		  spline->from->nextcp.y <= spline->to->me.y &&
164 		  spline->to->prevcp.y >= spline->from->me.y &&
165 		  spline->to->prevcp.y <= spline->to->me.y ) ||
166 		 (spline->from->nextcp.y <= spline->from->me.y &&
167 		  spline->from->nextcp.y >= spline->to->me.y &&
168 		  spline->to->prevcp.y <= spline->from->me.y &&
169 		  spline->to->prevcp.y >= spline->to->me.y )) )
170 	    ret = MinMaxWithin(spline);
171     /* Horizontal lines */
172     } else if ( RealNear(spline->from->me.y,spline->to->me.y) ) {
173 	ret = RealNear(spline->from->me.y,spline->from->nextcp.y) &&
174 	    RealNear(spline->from->me.y,spline->to->prevcp.y);
175 	if ( ! ((spline->from->nextcp.x >= spline->from->me.x &&
176 		  spline->from->nextcp.x <= spline->to->me.x &&
177 		  spline->to->prevcp.x >= spline->from->me.x &&
178 		  spline->to->prevcp.x <= spline->to->me.x) ||
179 		 (spline->from->nextcp.x <= spline->from->me.x &&
180 		  spline->from->nextcp.x >= spline->to->me.x &&
181 		  spline->to->prevcp.x <= spline->from->me.x &&
182 		  spline->to->prevcp.x >= spline->to->me.x)) )
183 	    ret = MinMaxWithin(spline);
184     } else {
185 	ret = true;
186 	t1 = (spline->from->nextcp.y-spline->from->me.y)/(spline->to->me.y-spline->from->me.y);
187 	t2 = (spline->from->nextcp.x-spline->from->me.x)/(spline->to->me.x-spline->from->me.x);
188 	t3 = (spline->to->me.y-spline->to->prevcp.y)/(spline->to->me.y-spline->from->me.y);
189 	t4 = (spline->to->me.x-spline->to->prevcp.x)/(spline->to->me.x-spline->from->me.x);
190 	ret = (RealApprox(t1,t2) || (RealApprox(t1,0) && RealApprox(t2,0))) &&
191 		(RealApprox(t3,t4) || (RealApprox(t3,0) && RealApprox(t4,0)));
192 	if ( ret ) {
193 	    if ( t1<0 || t2<0 || t3<0 || t4<0 ||
194 		    t1>1 || t2>1 || t3>1 || t4>1 )
195 		ret = MinMaxWithin(spline);
196 	}
197     }
198     spline->knowncurved = !ret;
199     spline->knownlinear = ret;
200     if ( ret ) {
201 	/* A few places that if the spline is knownlinear then its splines[?] */
202 	/*  are linear. So give the linear version and not that suggested by */
203 	/*  the control points */
204 	spline->splines[0].a = spline->splines[0].b = 0;
205 	spline->splines[0].d = spline->from->me.x;
206 	spline->splines[0].c = spline->to->me.x-spline->from->me.x;
207 	spline->splines[1].a = spline->splines[1].b = 0;
208 	spline->splines[1].d = spline->from->me.y;
209 	spline->splines[1].c = spline->to->me.y-spline->from->me.y;
210     }
211 return( ret );
212 }
213 
SplineIsLinearMake(Spline * spline)214 int SplineIsLinearMake(Spline *spline) {
215 
216     if ( spline->islinear )
217 return( true );
218     if ( SplineIsLinear(spline)) {
219 	spline->islinear = spline->from->nonextcp = spline->to->noprevcp = true;
220 	spline->from->nextcp = spline->from->me;
221 	if ( spline->from->nonextcp && spline->from->noprevcp )
222 	    spline->from->pointtype = pt_corner;
223 	else if ( spline->from->pointtype == pt_curve || spline->from->pointtype == pt_hvcurve )
224 	    spline->from->pointtype = pt_tangent;
225 	spline->to->prevcp = spline->to->me;
226 	if ( spline->to->nonextcp && spline->to->noprevcp )
227 	    spline->to->pointtype = pt_corner;
228 	else if ( spline->to->pointtype == pt_curve || spline->to->pointtype == pt_hvcurve )
229 	    spline->to->pointtype = pt_tangent;
230 	SplineRefigure(spline);
231     }
232 return( spline->islinear );
233 }
234 
IsLinearApprox(SplinePoint * from,SplinePoint * to,TPoint * mid,int cnt,int order2)235 static Spline *IsLinearApprox(SplinePoint *from, SplinePoint *to,
236 	TPoint *mid, int cnt, int order2) {
237     double vx, vy, slope;
238     int i;
239 
240     vx = to->me.x-from->me.x; vy = to->me.y-from->me.y;
241     if ( vx==0 && vy==0 ) {
242 	for ( i=0; i<cnt; ++i )
243 	    if ( mid[i].x != from->me.x || mid[i].y != from->me.y )
244 return( NULL );
245     } else if ( fabs(vx)>fabs(vy) ) {
246 	slope = vy/vx;
247 	for ( i=0; i<cnt; ++i )
248 	    if ( !RealWithin(mid[i].y,from->me.y+slope*(mid[i].x-from->me.x),.7) )
249 return( NULL );
250     } else {
251 	slope = vx/vy;
252 	for ( i=0; i<cnt; ++i )
253 	    if ( !RealWithin(mid[i].x,from->me.x+slope*(mid[i].y-from->me.y),.7) )
254 return( NULL );
255     }
256     from->nonextcp = to->noprevcp = true;
257 return( SplineMake(from,to,order2) );
258 }
259 
260 /* Least squares tells us that:
261 	| S(xi*ti^3) |	 | S(ti^6) S(ti^5) S(ti^4) S(ti^3) |   | a |
262 	| S(xi*ti^2) | = | S(ti^5) S(ti^4) S(ti^3) S(ti^2) | * | b |
263 	| S(xi*ti)   |	 | S(ti^4) S(ti^3) S(ti^2) S(ti)   |   | c |
264 	| S(xi)	     |   | S(ti^3) S(ti^2) S(ti)   n       |   | d |
265  and the definition of a spline tells us:
266 	| x1         | = |   1        1       1       1    | * (a b c d)
267 	| x0         | = |   0        0       0       1    | * (a b c d)
268 So we're a bit over specified. Let's use the last two lines of least squares
269 and the 2 from the spline defn. So d==x0. Now we've got three unknowns
270 and only three equations...
271 
272 For order2 splines we've got
273 	| S(xi*ti^2) |	 | S(ti^4) S(ti^3) S(ti^2) |   | b |
274 	| S(xi*ti)   | = | S(ti^3) S(ti^2) S(ti)   | * | c |
275 	| S(xi)	     |   | S(ti^2) S(ti)   n       |   | d |
276  and the definition of a spline tells us:
277 	| x1         | = |   1       1       1    | * (b c d)
278 	| x0         | = |   0       0       1    | * (b c d)
279 =>
280     d = x0
281     b+c = x1-x0
282     S(ti^2)*b + S(ti)*c = S(xi)-n*x0
283     S(ti^2)*b + S(ti)*(x1-x0-b) = S(xi)-n*x0
284     [ S(ti^2)-S(ti) ]*b = S(xi)-S(ti)*(x1-x0) - n*x0
285 */
_ApproximateSplineFromPoints(SplinePoint * from,SplinePoint * to,TPoint * mid,int cnt,BasePoint * nextcp,BasePoint * prevcp,int order2)286 static int _ApproximateSplineFromPoints(SplinePoint *from, SplinePoint *to,
287 	TPoint *mid, int cnt, BasePoint *nextcp, BasePoint *prevcp,
288 	int order2) {
289     double tt, ttn;
290     int i, j, ret;
291     double vx[3], vy[3], m[3][3];
292     double ts[7], xts[4], yts[4];
293     BasePoint nres, pres;
294     int nrescnt=0, prescnt=0;
295     double nmin, nmax, pmin, pmax, test, ptest;
296     double bx, by, cx, cy;
297 
298     memset(&nres,0,sizeof(nres)); memset(&pres,0,sizeof(pres));
299 
300     /* Add the initial and end points */
301     ts[0] = 2; for ( i=1; i<7; ++i ) ts[i] = 1;
302     xts[0] = from->me.x+to->me.x; yts[0] = from->me.y+to->me.y;
303     xts[3] = xts[2] = xts[1] = to->me.x; yts[3] = yts[2] = yts[1] = to->me.y;
304     nmin = pmin = 0; nmax = pmax = (to->me.x-from->me.x)*(to->me.x-from->me.x)+(to->me.y-from->me.y)*(to->me.y-from->me.y);
305     for ( i=0; i<cnt; ++i ) {
306 	xts[0] += mid[i].x;
307 	yts[0] += mid[i].y;
308 	++ts[0];
309 	tt = mid[i].t;
310 	xts[1] += tt*mid[i].x;
311 	yts[1] += tt*mid[i].y;
312 	ts[1] += tt;
313 	ts[2] += (ttn=tt*tt);
314 	xts[2] += ttn*mid[i].x;
315 	yts[2] += ttn*mid[i].y;
316 	ts[3] += (ttn*=tt);
317 	xts[3] += ttn*mid[i].x;
318 	yts[3] += ttn*mid[i].y;
319 	ts[4] += (ttn*=tt);
320 	ts[5] += (ttn*=tt);
321 	ts[6] += (ttn*=tt);
322 
323 	test = (mid[i].x-from->me.x)*(to->me.x-from->me.x) + (mid[i].y-from->me.y)*(to->me.y-from->me.y);
324 	if ( test<nmin ) nmin=test;
325 	if ( test>nmax ) nmax=test;
326 	test = (mid[i].x-to->me.x)*(from->me.x-to->me.x) + (mid[i].y-to->me.y)*(from->me.y-to->me.y);
327 	if ( test<pmin ) pmin=test;
328 	if ( test>pmax ) pmax=test;
329     }
330     pmin *= 1.2; pmax *= 1.2; nmin *= 1.2; nmax *= 1.2;
331 
332     for ( j=0; j<3; ++j ) {
333 	if ( order2 ) {
334 	    if ( RealNear(ts[j+2],ts[j+1]) )
335     continue;
336 	    /* This produces really bad results!!!! But I don't see what I can do to improve it */
337 	    bx = (xts[j]-ts[j+1]*(to->me.x-from->me.x) - ts[j]*from->me.x) / (ts[j+2]-ts[j+1]);
338 	    by = (yts[j]-ts[j+1]*(to->me.y-from->me.y) - ts[j]*from->me.y) / (ts[j+2]-ts[j+1]);
339 	    cx = to->me.x-from->me.x-bx;
340 	    cy = to->me.y-from->me.y-by;
341 
342 	    nextcp->x = from->me.x + cx/2;
343 	    nextcp->y = from->me.y + cy/2;
344 	    *prevcp = *nextcp;
345 	} else {
346 	    vx[0] = xts[j+1]-ts[j+1]*from->me.x;
347 	    vx[1] = xts[j]-ts[j]*from->me.x;
348 	    vx[2] = to->me.x-from->me.x;		/* always use the defn of spline */
349 
350 	    vy[0] = yts[j+1]-ts[j+1]*from->me.y;
351 	    vy[1] = yts[j]-ts[j]*from->me.y;
352 	    vy[2] = to->me.y-from->me.y;
353 
354 	    m[0][0] = ts[j+4]; m[0][1] = ts[j+3]; m[0][2] = ts[j+2];
355 	    m[1][0] = ts[j+3]; m[1][1] = ts[j+2]; m[1][2] = ts[j+1];
356 	    m[2][0] = 1;  m[2][1] = 1;  m[2][2] = 1;
357 
358 	    /* Remove a terms from rows 0 and 1 */
359 	    vx[0] -= ts[j+4]*vx[2];
360 	    vy[0] -= ts[j+4]*vy[2];
361 	    m[0][0] = 0; m[0][1] -= ts[j+4]; m[0][2] -= ts[j+4];
362 	    vx[1] -= ts[j+3]*vx[2];
363 	    vy[1] -= ts[j+3]*vy[2];
364 	    m[1][0] = 0; m[1][1] -= ts[j+3]; m[1][2] -= ts[j+3];
365 
366 	    if ( fabs(m[1][1])<fabs(m[0][1]) ) {
367 		double temp;
368 		temp = vx[1]; vx[1] = vx[0]; vx[0] = temp;
369 		temp = vy[1]; vy[1] = vy[0]; vy[0] = temp;
370 		temp = m[1][1]; m[1][1] = m[0][1]; m[0][1] = temp;
371 		temp = m[1][2]; m[1][2] = m[0][2]; m[0][2] = temp;
372 	    }
373 	    /* remove b terms from rows 0 and 2 (first normalize row 1 so m[1][1] is 1*/
374 	    vx[1] /= m[1][1];
375 	    vy[1] /= m[1][1];
376 	    m[1][2] /= m[1][1];
377 	    m[1][1] = 1;
378 	    vx[0] -= m[0][1]*vx[1];
379 	    vy[0] -= m[0][1]*vy[1];
380 	    m[0][2] -= m[0][1]*m[1][2]; m[0][1] = 0;
381 	    vx[2] -= m[2][1]*vx[1];
382 	    vy[2] -= m[2][1]*vy[1];
383 	    m[2][2] -= m[2][1]*m[1][2]; m[2][1] = 0;
384 
385 	    vx[0] /= m[0][2];			/* This is cx */
386 	    vy[0] /= m[0][2];			/* This is cy */
387 	    /*m[0][2] = 1;*/
388 
389 	    vx[1] -= m[1][2]*vx[0];		/* This is bx */
390 	    vy[1] -= m[1][2]*vy[0];		/* This is by */
391 	    /* m[1][2] = 0; */
392 	    vx[2] -= m[2][2]*vx[0];		/* This is ax */
393 	    vy[2] -= m[2][2]*vy[0];		/* This is ay */
394 	    /* m[2][2] = 0; */
395 
396 	    nextcp->x = from->me.x + vx[0]/3;
397 	    nextcp->y = from->me.y + vy[0]/3;
398 	    prevcp->x = nextcp->x + (vx[0]+vx[1])/3;
399 	    prevcp->y = nextcp->y + (vy[0]+vy[1])/3;
400 	}
401 
402 	test = (nextcp->x-from->me.x)*(to->me.x-from->me.x) +
403 		(nextcp->y-from->me.y)*(to->me.y-from->me.y);
404 	ptest = (prevcp->x-to->me.x)*(from->me.x-to->me.x) +
405 		(prevcp->y-to->me.y)*(from->me.y-to->me.y);
406 	if ( order2 &&
407 		(test<nmin || test>nmax || ptest<pmin || ptest>pmax))
408     continue;
409 	if ( test>=nmin && test<=nmax ) {
410 	    nres.x += nextcp->x; nres.y += nextcp->y;
411 	    ++nrescnt;
412 	}
413 	if ( test>=pmin && test<=pmax ) {
414 	    pres.x += prevcp->x; pres.y += prevcp->y;
415 	    ++prescnt;
416 	}
417 	if ( nrescnt==1 && prescnt==1 )
418     break;
419     }
420 
421     ret = 0;
422     if ( nrescnt>0 ) {
423 	ret |= 1;
424 	nextcp->x = nres.x/nrescnt;
425 	nextcp->y = nres.y/nrescnt;
426     } else
427 	*nextcp = from->nextcp;
428     if ( prescnt>0 ) {
429 	ret |= 2;
430 	prevcp->x = pres.x/prescnt;
431 	prevcp->y = pres.y/prescnt;
432     } else
433 	*prevcp = to->prevcp;
434     if ( order2 && ret!=3 ) {
435 	nextcp->x = (nextcp->x + prevcp->x)/2;
436 	nextcp->y = (nextcp->y + prevcp->y)/2;
437     }
438     if ( order2 )
439 	*prevcp = *nextcp;
440 return( ret );
441 }
442 
TestForLinear(SplinePoint * from,SplinePoint * to)443 static void TestForLinear(SplinePoint *from,SplinePoint *to) {
444     BasePoint off, cpoff, cpoff2;
445     double len, co, co2;
446 
447     /* Did we make a line? */
448     off.x = to->me.x-from->me.x; off.y = to->me.y-from->me.y;
449     len = sqrt(off.x*off.x + off.y*off.y);
450     if ( len!=0 ) {
451 	off.x /= len; off.y /= len;
452 	cpoff.x = from->nextcp.x-from->me.x; cpoff.y = from->nextcp.y-from->me.y;
453 	len = sqrt(cpoff.x*cpoff.x + cpoff.y*cpoff.y);
454 	if ( len!=0 ) {
455 	    cpoff.x /= len; cpoff.y /= len;
456 	}
457 	cpoff2.x = to->prevcp.x-from->me.x; cpoff2.y = to->prevcp.y-from->me.y;
458 	len = sqrt(cpoff2.x*cpoff2.x + cpoff2.y*cpoff2.y);
459 	if ( len!=0 ) {
460 	    cpoff2.x /= len; cpoff2.y /= len;
461 	}
462 	co = cpoff.x*off.y - cpoff.y*off.x; co2 = cpoff2.x*off.y - cpoff2.y*off.x;
463 	if ( co<.05 && co>-.05 && co2<.05 && co2>-.05 ) {
464 	    from->nextcp = from->me; from->nonextcp = true;
465 	    to->prevcp = to->me; to->noprevcp = true;
466 	} else {
467 	    Spline temp;
468 	    memset(&temp,0,sizeof(temp));
469 	    temp.from = from; temp.to = to;
470 	    SplineRefigure(&temp);
471 	    if ( SplineIsLinear(&temp)) {
472 		from->nextcp = from->me; from->nonextcp = true;
473 		to->prevcp = to->me; to->noprevcp = true;
474 	    }
475 	}
476     }
477 }
478 
479 /* Find a spline which best approximates the list of intermediate points we */
480 /*  are given. No attempt is made to fix the slopes */
ApproximateSplineFromPoints(SplinePoint * from,SplinePoint * to,TPoint * mid,int cnt,int order2)481 Spline *ApproximateSplineFromPoints(SplinePoint *from, SplinePoint *to,
482 	TPoint *mid, int cnt, int order2) {
483     int ret;
484     Spline *spline;
485     BasePoint nextcp, prevcp;
486 
487     if ( (spline = IsLinearApprox(from,to,mid,cnt,order2))!=NULL )
488 return( spline );
489 
490     ret = _ApproximateSplineFromPoints(from,to,mid,cnt,&nextcp,&prevcp,order2);
491 
492     if ( ret&1 ) {
493 	from->nextcp = nextcp;
494 	from->nonextcp = false;
495     } else {
496 	from->nextcp = from->me;
497 	from->nonextcp = true;
498     }
499     if ( ret&2 ) {
500 	to->prevcp = prevcp;
501 	to->noprevcp = false;
502     } else {
503 	to->prevcp = to->me;
504 	to->noprevcp = true;
505     }
506     TestForLinear(from,to);
507     spline = SplineMake(from,to,order2);
508 return( spline );
509 }
510 
ClosestSplineSolve(Spline1D * sp,double sought,double close_to_t)511 static double ClosestSplineSolve(Spline1D *sp,double sought,double close_to_t) {
512     /* We want to find t so that spline(t) = sought */
513     /*  find the value which is closest to close_to_t */
514     /* on error return closetot */
515     Spline1D temp;
516     extended ts[3];
517     int i;
518     double t, best, test;
519 
520     temp = *sp;
521     temp.d -= sought;
522     CubicSolve(&temp,ts);
523     best = 9e20; t= close_to_t;
524     for ( i=0; i<3; ++i ) if ( ts[i]!=-1 ) {
525 	if ( (test=ts[i]-close_to_t)<0 ) test = -test;
526 	if ( test<best ) {
527 	    best = test;
528 	    t = ts[i];
529 	}
530     }
531 
532 return( t );
533 }
534 
535 struct dotbounds {
536     BasePoint unit;
537     BasePoint base;
538     double len;
539     double min,max;		/* If min<0 || max>len the spline extends beyond its endpoints */
540 };
541 
SigmaDeltas(Spline * spline,TPoint * mid,int cnt,DBounds * b,struct dotbounds * db)542 static double SigmaDeltas(Spline *spline,TPoint *mid, int cnt, DBounds *b, struct dotbounds *db) {
543     int i, lasti;
544     double xdiff, ydiff, sum, temp, t, lastt;
545     SplinePoint *to = spline->to, *from = spline->from;
546     extended ts[2], x,y;
547     struct dotbounds db2;
548     double dot;
549 
550     if ( (xdiff = to->me.x-from->me.x)<0 ) xdiff = -xdiff;
551     if ( (ydiff = to->me.y-from->me.y)<0 ) ydiff = -ydiff;
552 
553     sum = 0; lastt = -1; lasti = -1;
554     for ( i=0; i<cnt; ++i ) {
555 	if ( ydiff>2*xdiff ) {
556 	    t = ClosestSplineSolve(&spline->splines[1],mid[i].y,mid[i].t);
557 	} else if ( xdiff>2*ydiff ) {
558 	    t = ClosestSplineSolve(&spline->splines[0],mid[i].x,mid[i].t);
559 	} else {
560 	    t = (ClosestSplineSolve(&spline->splines[1],mid[i].y,mid[i].t) +
561 		    ClosestSplineSolve(&spline->splines[0],mid[i].x,mid[i].t))/2;
562 	}
563 	if ( t==lastt )		/* These last* values appear to be debugging */
564 	    t = lastt + (mid[i].t - mid[lasti].t);
565 	else {
566 	    lastt = t;
567 	    lasti = i;
568 	}
569 	temp = mid[i].x - ( ((spline->splines[0].a*t+spline->splines[0].b)*t+spline->splines[0].c)*t + spline->splines[0].d );
570 	sum += temp*temp;
571 	temp = mid[i].y - ( ((spline->splines[1].a*t+spline->splines[1].b)*t+spline->splines[1].c)*t + spline->splines[1].d );
572 	sum += temp*temp;
573     }
574 
575     /* Ok, we've got distances from a set of points on the old spline to the */
576     /*  new one. Let's do the reverse: find the extrema of the new and see how*/
577     /*  close they get to the bounding box of the old */
578     /* And get really unhappy if the spline extends beyond the end-points */
579     db2.min = 0; db2.max = db->len;
580     SplineFindExtrema(&spline->splines[0],&ts[0],&ts[1]);
581     for ( i=0; i<2; ++i ) {
582 	if ( ts[i]!=-1 ) {
583 	    x = ((spline->splines[0].a*ts[i]+spline->splines[0].b)*ts[i]+spline->splines[0].c)*ts[i] + spline->splines[0].d;
584 	    y = ((spline->splines[1].a*ts[i]+spline->splines[1].b)*ts[i]+spline->splines[1].c)*ts[i] + spline->splines[1].d;
585 	    if ( x<b->minx )
586 		sum += (x-b->minx)*(x-b->minx);
587 	    else if ( x>b->maxx )
588 		sum += (x-b->maxx)*(x-b->maxx);
589 	    dot = (x-db->base.x)*db->unit.x + (y-db->base.y)*db->unit.y;
590 	    if ( dot<db2.min ) db2.min = dot;
591 	    if ( dot>db2.max ) db2.max = dot;
592 	}
593     }
594     SplineFindExtrema(&spline->splines[1],&ts[0],&ts[1]);
595     for ( i=0; i<2; ++i ) {
596 	if ( ts[i]!=-1 ) {
597 	    x = ((spline->splines[0].a*ts[i]+spline->splines[0].b)*ts[i]+spline->splines[0].c)*ts[i] + spline->splines[0].d;
598 	    y = ((spline->splines[1].a*ts[i]+spline->splines[1].b)*ts[i]+spline->splines[1].c)*ts[i] + spline->splines[1].d;
599 	    if ( y<b->miny )
600 		sum += (y-b->miny)*(y-b->miny);
601 	    else if ( y>b->maxy )
602 		sum += (y-b->maxy)*(y-b->maxy);
603 	    dot = (x-db->base.x)*db->unit.x + (y-db->base.y)*db->unit.y;
604 	    if ( dot<db2.min ) db2.min = dot;
605 	    if ( dot>db2.max ) db2.max = dot;
606 	}
607     }
608 
609     /* Big penalty for going beyond the range of the desired spline */
610     if ( db->min==0 && db2.min<0 )
611 	sum += 10000 + db2.min*db2.min;
612     else if ( db2.min<db->min )
613 	sum += 100 + (db2.min-db->min)*(db2.min-db->min);
614     if ( db->max==db->len && db2.max>db->len )
615 	sum += 10000 + (db2.max-db->max)*(db2.max-db->max);
616     else if ( db2.max>db->max )
617 	sum += 100 + (db2.max-db->max)*(db2.max-db->max);
618 
619 return( sum );
620 }
621 
ApproxBounds(DBounds * b,TPoint * mid,int cnt,struct dotbounds * db)622 static void ApproxBounds(DBounds *b,TPoint *mid, int cnt, struct dotbounds *db) {
623     int i;
624     double dot;
625 
626     b->minx = b->maxx = mid[0].x;
627     b->miny = b->maxy = mid[0].y;
628     db->min = 0; db->max = db->len;
629     for ( i=1; i<cnt; ++i ) {
630 	if ( mid[i].x>b->maxx ) b->maxx = mid[i].x;
631 	if ( mid[i].x<b->minx ) b->minx = mid[i].x;
632 	if ( mid[i].y>b->maxy ) b->maxy = mid[i].y;
633 	if ( mid[i].y<b->miny ) b->miny = mid[i].y;
634 	dot = (mid[i].x-db->base.x)*db->unit.x + (mid[i].y-db->base.y)*db->unit.y;
635 	if ( dot<db->min ) db->min = dot;
636 	if ( dot>db->max ) db->max = dot;
637     }
638 }
639 
GoodCurve(SplinePoint * sp,int check_prev)640 static int GoodCurve(SplinePoint *sp, int check_prev ) {
641     double dx, dy, lenx, leny;
642 
643     if ( sp->pointtype!=pt_curve && sp->pointtype!=pt_hvcurve )
644 return( false );
645     if ( check_prev ) {
646 	dx = sp->me.x - sp->prevcp.x;
647 	dy = sp->me.y - sp->prevcp.y;
648     } else {
649 	dx = sp->me.x - sp->nextcp.x;
650 	dy = sp->me.y - sp->nextcp.y;
651     }
652     /* If the cp is very close to the base point the point might as well be a corner */
653     if ( dx<0 ) dx = -dx;
654     if ( dy<0 ) dy = -dy;
655     if ( dx+dy<1 )
656 return( false );
657 
658     if ( check_prev ) {
659 	if ( sp->prev==NULL )
660 return( true );
661 	lenx = sp->me.x - sp->prev->from->me.x;
662 	leny = sp->me.y - sp->prev->from->me.y;
663     } else {
664 	if ( sp->next==NULL )
665 return( true );
666 	lenx = sp->me.x - sp->next->to->me.x;
667 	leny = sp->me.y - sp->next->to->me.y;
668     }
669     if ( lenx<0 ) lenx = -lenx;
670     if ( leny<0 ) leny = -leny;
671     if ( 50*(dx+dy) < lenx+leny )
672 return( false );
673 
674 return( true );
675 }
676 
677 #if 0
678 static int totcnt_cnt, nocnt_cnt, incr_cnt, curdiff_cnt;
679 #endif
680 
681 /* I used to do a least squares aproach adding two more to the above set of equations */
682 /*  which held the slopes constant. But that didn't work very well. So instead*/
683 /*  Then I tried doing the approximation, and then forcing the control points */
684 /*  to be in line (witht the original slopes), getting a better approximation */
685 /*  to "t" for each data point and then calculating an error array, approximating*/
686 /*  it, and using that to fix up the final result */
687 /* Then I tried checking various possible cp lengths in the desired directions*/
688 /*  finding the best one or two, and doing a 2D binary search using that as a */
689 /*  starting point. */
690 /* And sometimes a least squares approach will give us the right answer, so   */
691 /*  try that too. */
692 /* This still isn't as good as I'd like it... But I haven't been able to */
693 /*  improve it further yet */
694 #define TRY_CNT		2
695 #define DECIMATION	5
ApproximateSplineFromPointsSlopes(SplinePoint * from,SplinePoint * to,TPoint * mid,int cnt,int order2)696 Spline *ApproximateSplineFromPointsSlopes(SplinePoint *from, SplinePoint *to,
697 	TPoint *mid, int cnt, int order2) {
698     BasePoint tounit, fromunit, ftunit;
699     double flen,tlen,ftlen;
700     Spline *spline, temp;
701     BasePoint nextcp;
702     int bettern, betterp;
703     double offn, offp, incrn, incrp, trylen;
704     int nocnt = 0, totcnt;
705     double curdiff, bestdiff[TRY_CNT];
706     int i,j,besti[TRY_CNT],bestj[TRY_CNT],k,l;
707     double fdiff, tdiff, fmax, tmax, fdotft, tdotft;
708     DBounds b;
709     struct dotbounds db;
710     double offn_, offp_, finaldiff;
711 
712     /* If all the selected points are at the same spot, and one of the */
713     /*  end-points is also at that spot, then just copy the control point */
714     /* But our caller seems to have done that for us */
715 
716     /* If the two end-points are corner points then allow the slope to vary */
717     /* Or if one end-point is a tangent but the point defining the tangent's */
718     /*  slope is being removed then allow the slope to vary */
719     /* Except if the slope is horizontal or vertical then keep it fixed */
720     if ( ( !from->nonextcp && ( from->nextcp.x==from->me.x || from->nextcp.y==from->me.y)) ||
721 	    (!to->noprevcp && ( to->prevcp.x==to->me.x || to->prevcp.y==to->me.y)) )
722 	/* Preserve the slope */;
723     else if ( ((from->pointtype == pt_corner && from->nonextcp) ||
724 		(from->pointtype == pt_tangent &&
725 			((from->nonextcp && from->noprevcp) || !from->noprevcp))) &&
726 	    ((to->pointtype == pt_corner && to->noprevcp) ||
727 		(to->pointtype == pt_tangent &&
728 			((to->nonextcp && to->noprevcp) || !to->nonextcp))) ) {
729 	from->pointtype = to->pointtype = pt_corner;
730 return( ApproximateSplineFromPoints(from,to,mid,cnt,order2) );
731     }
732 
733     /* If we are going to honour the slopes of a quadratic spline, there is */
734     /*  only one possibility */
735     if ( order2 ) {
736 	if ( from->nonextcp )
737 	    from->nextcp = from->next->to->me;
738 	if ( to->noprevcp )
739 	    to->prevcp = to->prev->from->me;
740 	from->nonextcp = to->noprevcp = false;
741 	fromunit.x = from->nextcp.x-from->me.x; fromunit.y = from->nextcp.y-from->me.y;
742 	tounit.x = to->prevcp.x-to->me.x; tounit.y = to->prevcp.y-to->me.y;
743 
744 	if ( !IntersectLines(&nextcp,&from->nextcp,&from->me,&to->prevcp,&to->me) ||
745 		(nextcp.x-from->me.x)*fromunit.x + (nextcp.y-from->me.y)*fromunit.y < 0 ||
746 		(nextcp.x-to->me.x)*tounit.x + (nextcp.y-to->me.y)*tounit.y < 0 ) {
747 	    /* If the slopes don't intersect then use a line */
748 	    /*  (or if the intersection is patently absurd) */
749 	    from->nonextcp = to->noprevcp = true;
750 	    from->nextcp = from->me;
751 	    to->prevcp = to->me;
752 	    TestForLinear(from,to);
753 	} else {
754 	    from->nextcp = to->prevcp = nextcp;
755 	    from->nonextcp = to->noprevcp = false;
756 	}
757 return( SplineMake2(from,to));
758     }
759     /* From here down we are only working with cubic splines */
760 
761     if ( cnt==0 ) {
762 	/* Just use what we've got, no data to improve it */
763 	/* But we do sometimes get some cps which are too big */
764 	double len = sqrt((to->me.x-from->me.x)*(to->me.x-from->me.x) + (to->me.y-from->me.y)*(to->me.y-from->me.y));
765 	if ( len==0 ) {
766 	    from->nonextcp = to->noprevcp = true;
767 	    from->nextcp = from->me;
768 	    to->prevcp = to->me;
769 	} else {
770 	    BasePoint noff, poff;
771 	    double nlen, plen;
772 	    noff.x = from->nextcp.x-from->me.x; noff.y = from->nextcp.y-from->me.y;
773 	    poff.x = to->me.x-to->prevcp.x; poff.y = to->me.y-to->prevcp.y;
774 	    nlen = sqrt(noff.x*noff.x + noff.y+noff.y);
775 	    plen = sqrt(poff.x*poff.x + poff.y+poff.y);
776 	    if ( nlen>len/3 ) {
777 		noff.x *= len/3/nlen; noff.y *= len/3/nlen;
778 		from->nextcp.x = from->me.x + noff.x;
779 		from->nextcp.y = from->me.y + noff.y;
780 	    }
781 	    if ( plen>len/3 ) {
782 		poff.x *= len/3/plen; poff.y *= len/3/plen;
783 		to->prevcp.x = to->me.x + poff.x;
784 		to->prevcp.y = to->me.y + poff.y;
785 	    }
786 	}
787 return( SplineMake3(from,to));
788     }
789 
790     if ( to->prev!=NULL && (( to->noprevcp && to->nonextcp ) || to->prev->knownlinear )) {
791 	tounit.x = to->prev->from->me.x-to->me.x; tounit.y = to->prev->from->me.y-to->me.y;
792     } else if ( !to->noprevcp || to->pointtype == pt_corner ) {
793 	tounit.x = to->prevcp.x-to->me.x; tounit.y = to->prevcp.y-to->me.y;
794     } else {
795 	tounit.x = to->me.x-to->nextcp.x; tounit.y = to->me.y-to->nextcp.y;
796     }
797     tlen = sqrt(tounit.x*tounit.x + tounit.y*tounit.y);
798     if ( from->next!=NULL && (( from->noprevcp && from->nonextcp ) || from->next->knownlinear) ) {
799 	fromunit.x = from->next->to->me.x-from->me.x; fromunit.y = from->next->to->me.y-from->me.y;
800     } else if ( !from->nonextcp || from->pointtype == pt_corner ) {
801 	fromunit.x = from->nextcp.x-from->me.x; fromunit.y = from->nextcp.y-from->me.y;
802     } else {
803 	fromunit.x = from->me.x-from->prevcp.x; fromunit.y = from->me.y-from->prevcp.y;
804     }
805     flen = sqrt(fromunit.x*fromunit.x + fromunit.y*fromunit.y);
806     if ( tlen==0 || flen==0 ) {
807 	if ( from->next!=NULL )
808 	    temp = *from->next;
809 	else {
810 	    memset(&temp,0,sizeof(temp));
811 	    temp.from = from; temp.to = to;
812 	    SplineRefigure(&temp);
813 	    from->next = to->prev = NULL;
814 	}
815     }
816     if ( tlen==0 ) {
817 	if ( (to->pointtype==pt_curve || to->pointtype==pt_hvcurve) &&
818 		to->next && !to->nonextcp ) {
819 	    tounit.x = to->me.x-to->nextcp.x; tounit.y = to->me.y-to->nextcp.y;
820 /* Doesn't work
821 	} else if ( to->pointtype==pt_tangent && to->next ) {
822 	    tounit.x = to->me.x-to->next->to->me.x; tounit.y = to->me.y-to->next->to->me.y;
823 */
824 	} else {
825 	    tounit.x = -( (3*temp.splines[0].a*.9999+2*temp.splines[0].b)*.9999+temp.splines[0].c );
826 	    tounit.y = -( (3*temp.splines[1].a*.9999+2*temp.splines[1].b)*.9999+temp.splines[1].c );
827 	}
828 	tlen = sqrt(tounit.x*tounit.x + tounit.y*tounit.y);
829     }
830     tounit.x /= tlen; tounit.y /= tlen;
831 
832     if ( flen==0 ) {
833 	if ( (from->pointtype==pt_curve || from->pointtype==pt_hvcurve) &&
834 		from->prev && !from->noprevcp ) {
835 	    fromunit.x = from->me.x-from->prevcp.x; fromunit.y = from->me.y-from->prevcp.y;
836 /*
837 	} else if ( from->pointtype==pt_tangent && from->prev ) {
838 	    fromunit.x = from->me.x-from->prev->from->me.x; fromunit.y = from->me.y-from->prev->from->me.y;
839 */
840 	} else {
841 	    fromunit.x = ( (3*temp.splines[0].a*.0001+2*temp.splines[0].b)*.0001+temp.splines[0].c );
842 	    fromunit.y = ( (3*temp.splines[1].a*.0001+2*temp.splines[1].b)*.0001+temp.splines[1].c );
843 	}
844 	flen = sqrt(fromunit.x*fromunit.x + fromunit.y*fromunit.y);
845     }
846     fromunit.x /= flen; fromunit.y /= flen;
847 
848     trylen = (to->me.x-from->me.x)*fromunit.x + (to->me.y-from->me.y)*fromunit.y;
849     if ( trylen>flen ) flen = trylen;
850 
851     trylen = (from->me.x-to->me.x)*tounit.x + (from->me.y-to->me.y)*tounit.y;
852     if ( trylen>tlen ) tlen = trylen;
853 
854     ftunit.x = (to->me.x-from->me.x); ftunit.y = (to->me.y-from->me.y);
855     ftlen = sqrt(ftunit.x*ftunit.x + ftunit.y*ftunit.y);
856     if ( ftlen!=0 ) {
857 	ftunit.x /= ftlen; ftunit.y /= ftlen;
858     }
859     fdotft = fromunit.x*ftunit.x + fromunit.y*ftunit.y;
860     fmax = fdotft>0 ? ftlen/fdotft : 1e10;
861     tdotft = -tounit.x*ftunit.x - tounit.y*ftunit.y;
862     tmax = tdotft>0 ? ftlen/tdotft : 1e10;
863     /* At fmax, tmax the control points will stretch beyond the other endpoint*/
864     /*  when projected along the line between the two endpoints */
865 
866     db.base = from->me;
867     db.unit.x = (to->me.x-from->me.x); db.unit.y = (to->me.y-from->me.y);
868     db.len = sqrt(db.unit.x*db.unit.x + db.unit.y*db.unit.y);
869     if ( db.len!=0 ) {
870 	db.unit.x /= db.len;
871 	db.unit.y /= db.len;
872     }
873     ApproxBounds(&b,mid,cnt,&db);
874 
875     for ( k=0; k<TRY_CNT; ++k ) {
876 	bestdiff[k] = 1e20;
877 	besti[k] = -1; bestj[k] = -1;
878     }
879     fdiff = flen/DECIMATION;
880     tdiff = tlen/DECIMATION;
881     from->nextcp = from->me;
882     from->nonextcp = false;
883     to->noprevcp = false;
884     memset(&temp,0,sizeof(Spline));
885     temp.from = from; temp.to = to;
886     for ( i=1; i<DECIMATION; ++i ) {
887 	from->nextcp.x += fdiff*fromunit.x; from->nextcp.y += fdiff*fromunit.y;
888 	to->prevcp = to->me;
889 	for ( j=1; j<DECIMATION; ++j ) {
890 	    to->prevcp.x += tdiff*tounit.x; to->prevcp.y += tdiff*tounit.y;
891 	    SplineRefigure(&temp);
892 	    curdiff = SigmaDeltas(&temp,mid,cnt,&b,&db);
893 	    for ( k=0; k<TRY_CNT; ++k ) {
894 		if ( curdiff<bestdiff[k] ) {
895 		    for ( l=TRY_CNT-1; l>k; --l ) {
896 			bestdiff[l] = bestdiff[l-1];
897 			besti[l] = besti[l-1];
898 			bestj[l] = bestj[l-1];
899 		    }
900 		    bestdiff[k] = curdiff;
901 		    besti[k] = i; bestj[k]=j;
902 	    break;
903 		}
904 	    }
905 	}
906     }
907 
908     finaldiff = 1e20;
909     offn_ = offp_ = -1;
910     spline = SplineMake(from,to,false);
911     for ( k=-1; k<TRY_CNT; ++k ) {
912 	if ( k<0 ) {
913 	    BasePoint nextcp, prevcp;
914 	    double temp1, temp2;
915 	    int ret = _ApproximateSplineFromPoints(from,to,mid,cnt,&nextcp,&prevcp,false);
916 	    /* sometimes least squares gives us the right answer */
917 	    if ( !(ret&1) || !(ret&2))
918     continue;
919 	    temp1 = (prevcp.x-to->me.x)*tounit.x + (prevcp.y-to->me.y)*tounit.y;
920 	    temp2 = (nextcp.x-from->me.x)*fromunit.x + (nextcp.y-from->me.y)*fromunit.y;
921 	    if ( temp1<=0 || temp2<=0 )		/* A nice solution... but the control points are diametrically opposed to what they should be */
922     continue;
923 	    tlen = temp1; flen = temp2;
924 	} else {
925 	    if ( bestj[k]<0 || besti[k]<0 )
926     continue;
927 	    tlen = bestj[k]*tdiff; flen = besti[k]*fdiff;
928 	}
929 	to->prevcp.x = to->me.x + tlen*tounit.x; to->prevcp.y = to->me.y + tlen*tounit.y;
930 	from->nextcp.x = from->me.x + flen*fromunit.x; from->nextcp.y = from->me.y + flen*fromunit.y;
931 	SplineRefigure(spline);
932 
933 	bettern = betterp = false;
934 	incrn = tdiff/2.0; incrp = fdiff/2.0;
935 	offn = flen; offp = tlen;
936 	nocnt = 0;
937 	curdiff = SigmaDeltas(spline,mid,cnt,&b,&db);
938 	totcnt = 0;
939 	forever {
940 	    double fadiff, fsdiff;
941 	    double tadiff, tsdiff;
942 
943 	    from->nextcp.x = from->me.x + (offn+incrn)*fromunit.x; from->nextcp.y = from->me.y + (offn+incrn)*fromunit.y;
944 	    to->prevcp.x = to->me.x + offp*tounit.x; to->prevcp.y = to->me.y + offp*tounit.y;
945 	    SplineRefigure(spline);
946 	    fadiff = SigmaDeltas(spline,mid,cnt,&b,&db);
947 	    from->nextcp.x = from->me.x + (offn-incrn)*fromunit.x; from->nextcp.y = from->me.y + (offn-incrn)*fromunit.y;
948 	    SplineRefigure(spline);
949 	    fsdiff = SigmaDeltas(spline,mid,cnt,&b,&db);
950 	    from->nextcp.x = from->me.x + offn*fromunit.x; from->nextcp.y = from->me.y + offn*fromunit.y;
951 	    if ( offn-incrn<=0 )
952 		fsdiff += 1e10;
953 
954 	    to->prevcp.x = to->me.x + (offp+incrp)*tounit.x; to->prevcp.y = to->me.y + (offp+incrp)*tounit.y;
955 	    SplineRefigure(spline);
956 	    tadiff = SigmaDeltas(spline,mid,cnt,&b,&db);
957 	    to->prevcp.x = to->me.x + (offp-incrp)*tounit.x; to->prevcp.y = to->me.y + (offp-incrp)*tounit.y;
958 	    SplineRefigure(spline);
959 	    tsdiff = SigmaDeltas(spline,mid,cnt,&b,&db);
960 	    to->prevcp.x = to->me.x + offp*tounit.x; to->prevcp.y = to->me.y + offp*tounit.y;
961 	    if ( offp-incrp<=0 )
962 		tsdiff += 1e10;
963 
964 	    if ( offn>=incrn && fsdiff<curdiff &&
965 		    (fsdiff<fadiff && fsdiff<tsdiff && fsdiff<tadiff)) {
966 		offn -= incrn;
967 		if ( bettern>0 )
968 		    incrn /= 2;
969 		bettern = -1;
970 		nocnt = 0;
971 		curdiff = fsdiff;
972 	    } else if ( offn+incrn<fmax && fadiff<curdiff &&
973 		    (fadiff<=fsdiff && fadiff<tsdiff && fadiff<tadiff)) {
974 		offn += incrn;
975 		if ( bettern<0 )
976 		    incrn /= 2;
977 		bettern = 1;
978 		nocnt = 0;
979 		curdiff = fadiff;
980 	    } else if ( offp>=incrp && tsdiff<curdiff &&
981 		    (tsdiff<=fsdiff && tsdiff<=fadiff && tsdiff<tadiff)) {
982 		offp -= incrp;
983 		if ( betterp>0 )
984 		    incrp /= 2;
985 		betterp = -1;
986 		nocnt = 0;
987 		curdiff = tsdiff;
988 	    } else if ( offp+incrp<tmax && tadiff<curdiff &&
989 		    (tadiff<=fsdiff && tadiff<=fadiff && tadiff<=tsdiff)) {
990 		offp += incrp;
991 		if ( betterp<0 )
992 		    incrp /= 2;
993 		betterp = 1;
994 		nocnt = 0;
995 		curdiff = tadiff;
996 	    } else {
997 		if ( ++nocnt > 6 )
998 	break;
999 		incrn /= 2;
1000 		incrp /= 2;
1001 	    }
1002 	    if ( curdiff<1 )
1003 	break;
1004 	    if ( incrp<tdiff/1024 || incrn<fdiff/1024 )
1005 	break;
1006 	    if ( ++totcnt>200 )
1007 	break;
1008 	    if ( offn<0 || offp<0 ) {
1009 		IError("Approximation got inverse control points");
1010 	break;
1011 	    }
1012 	}
1013 #if 0
1014  if ( nocnt>6 )
1015   nocnt_cnt++;
1016  else if ( curdiff<1 )
1017   curdiff_cnt++;
1018  else if ( totcnt>200 )
1019   totcnt_cnt++;
1020  else
1021   incr_cnt++;
1022 #endif
1023 	if ( curdiff<finaldiff ) {
1024 	    finaldiff = curdiff;
1025 	    offn_ = offn;
1026 	    offp_ = offp;
1027 	}
1028     }
1029 
1030     to->noprevcp = offp_==0;
1031     from->nonextcp = offn_==0;
1032     to->prevcp.x = to->me.x + offp_*tounit.x; to->prevcp.y = to->me.y + offp_*tounit.y;
1033     from->nextcp.x = from->me.x + offn_*fromunit.x; from->nextcp.y = from->me.y + offn_*fromunit.y;
1034     /* I used to check for a spline very close to linear (and if so, make it */
1035     /*  linear). But in when stroking a path with an eliptical pen we transform*/
1036     /*  the coordinate system and our normal definitions of "close to linear" */
1037     /*  don't apply */
1038     /*TestForLinear(from,to);*/
1039     SplineRefigure(spline);
1040 
1041 return( spline );
1042 }
1043 #undef TRY_CNT
1044 #undef DECIMATION
1045 
1046     /* calculating the actual length of a spline is hard, this gives a very */
1047     /*  rough (but quick) approximation */
SplineLenApprox(Spline * spline)1048 static double SplineLenApprox(Spline *spline) {
1049     double len, slen, temp;
1050 
1051     if ( (temp = spline->to->me.x-spline->from->me.x)<0 ) temp = -temp;
1052     len = temp;
1053     if ( (temp = spline->to->me.y-spline->from->me.y)<0 ) temp = -temp;
1054     len += temp;
1055     if ( !spline->to->noprevcp || !spline->from->nonextcp ) {
1056 	if ( (temp = spline->from->nextcp.x-spline->from->me.x)<0 ) temp = -temp;
1057 	slen = temp;
1058 	if ( (temp = spline->from->nextcp.y-spline->from->me.y)<0 ) temp = -temp;
1059 	slen += temp;
1060 	if ( (temp = spline->to->prevcp.x-spline->from->nextcp.x)<0 ) temp = -temp;
1061 	slen += temp;
1062 	if ( (temp = spline->to->prevcp.y-spline->from->nextcp.y)<0 ) temp = -temp;
1063 	slen += temp;
1064 	if ( (temp = spline->to->me.x-spline->to->prevcp.x)<0 ) temp = -temp;
1065 	slen += temp;
1066 	if ( (temp = spline->to->me.y-spline->to->prevcp.y)<0 ) temp = -temp;
1067 	slen += temp;
1068 	len = (len + slen)/2;
1069     }
1070 return( len );
1071 }
1072 
SplineLength(Spline * spline)1073 double SplineLength(Spline *spline) {
1074     /* I ignore the constant term. It's just an unneeded addition */
1075     double len, t;
1076     double lastx = 0, lasty = 0;
1077     double curx, cury;
1078 
1079     len = 0;
1080     for ( t=1.0/128; t<=1.0001 ; t+=1.0/128 ) {
1081 	curx = ((spline->splines[0].a*t+spline->splines[0].b)*t+spline->splines[0].c)*t;
1082 	cury = ((spline->splines[1].a*t+spline->splines[1].b)*t+spline->splines[1].c)*t;
1083 	len += sqrt( (curx-lastx)*(curx-lastx) + (cury-lasty)*(cury-lasty) );
1084 	lastx = curx; lasty = cury;
1085     }
1086 return( len );
1087 }
1088 
1089 
SplinesFigureTPsBetween(SplinePoint * from,SplinePoint * to,int * tot)1090 static TPoint *SplinesFigureTPsBetween(SplinePoint *from, SplinePoint *to,
1091 	int *tot) {
1092     int cnt, i, j, pcnt;
1093     double len, slen, lbase;
1094     SplinePoint *np;
1095     TPoint *tp;
1096     double _lens[10], *lens = _lens;
1097     int _cnts[10], *cnts = _cnts;
1098     /* I used just to give every spline 10 points. But that gave much more */
1099     /*  weight to small splines than to big ones */
1100 
1101     cnt = 0;
1102     for ( np = from->next->to; ; np = np->next->to ) {
1103 	++cnt;
1104 	if ( np==to )
1105     break;
1106     }
1107     if ( cnt>10 ) {
1108 	lens = galloc(cnt*sizeof(double));
1109 	cnts = galloc(cnt*sizeof(int));
1110     }
1111     cnt = 0; len = 0;
1112     for ( np = from->next->to; ; np = np->next->to ) {
1113 	lens[cnt] = SplineLenApprox(np->prev);
1114 	len += lens[cnt];
1115 	++cnt;
1116 	if ( np==to )
1117     break;
1118     }
1119     if ( len!=0 ) {
1120 	pcnt = 0;
1121 	for ( i=0; i<cnt; ++i ) {
1122 	    int pnts = rint( (10*cnt*lens[i])/len );
1123 	    if ( pnts<2 ) pnts = 2;
1124 	    cnts[i] = pnts;
1125 	    pcnt += pnts;
1126 	}
1127     } else
1128 	pcnt = 2*cnt;
1129 
1130     tp = galloc((pcnt+1)*sizeof(TPoint)); i = 0;
1131     if ( len==0 ) {
1132 	for ( i=0; i<=pcnt; ++i ) {
1133 	    tp[i].t = i/(pcnt);
1134 	    tp[i].x = from->me.x;
1135 	    tp[i].y = from->me.y;
1136 	}
1137     } else {
1138 	lbase = 0;
1139 	for ( i=cnt=0, np = from->next->to; ; np = np->next->to, ++cnt ) {
1140 	    slen = SplineLenApprox(np->prev);
1141 	    for ( j=0; j<cnts[cnt]; ++j ) {
1142 		double t = j/(double) cnts[cnt];
1143 		tp[i].t = (lbase+ t*slen)/len;
1144 		tp[i].x = ((np->prev->splines[0].a*t+np->prev->splines[0].b)*t+np->prev->splines[0].c)*t + np->prev->splines[0].d;
1145 		tp[i++].y = ((np->prev->splines[1].a*t+np->prev->splines[1].b)*t+np->prev->splines[1].c)*t + np->prev->splines[1].d;
1146 	    }
1147 	    lbase += slen;
1148 	    if ( np==to )
1149 	break;
1150 	}
1151     }
1152     if ( cnts!=_cnts ) free(cnts);
1153     if ( lens!=_lens ) free(lens);
1154 
1155     *tot = i;
1156 
1157 return( tp );
1158 }
1159 
SplinePointReCatagorize(SplinePoint * sp,int oldpt)1160 static void SplinePointReCatagorize(SplinePoint *sp,int oldpt) {
1161     SplinePointCatagorize(sp);
1162     if ( sp->pointtype!=oldpt ) {
1163 	if ( sp->pointtype==pt_curve && oldpt==pt_hvcurve &&
1164 		((sp->nextcp.x == sp->me.x && sp->nextcp.y != sp->me.y ) ||
1165 		 (sp->nextcp.y == sp->me.y && sp->nextcp.x != sp->me.x )))
1166 	    sp->pointtype = pt_hvcurve;
1167     }
1168 }
1169 
SplinesRemoveBetween(SplineChar * sc,SplinePoint * from,SplinePoint * to,int type)1170 void SplinesRemoveBetween(SplineChar *sc, SplinePoint *from, SplinePoint *to,int type) {
1171     int tot;
1172     TPoint *tp;
1173     SplinePoint *np, oldfrom;
1174     int oldfpt = from->pointtype, oldtpt = to->pointtype;
1175     Spline *sp;
1176     int order2 = from->next->order2;
1177 
1178     oldfrom = *from;
1179     tp = SplinesFigureTPsBetween(from,to,&tot);
1180 
1181     if ( type==1 )
1182 	ApproximateSplineFromPointsSlopes(from,to,tp,tot-1,order2);
1183     else
1184 	ApproximateSplineFromPoints(from,to,tp,tot-1,order2);
1185 
1186     /* Have to do the frees after the approximation because the approx */
1187     /*  uses the splines to determine slopes */
1188     for ( sp = oldfrom.next; ; ) {
1189 	np = sp->to;
1190 	SplineFree(sp);
1191 	if ( np==to )
1192     break;
1193 	sp = np->next;
1194 	SplinePointMDFree(sc,np);
1195     }
1196 
1197     free(tp);
1198 
1199     SplinePointReCatagorize(from,oldfpt);
1200     SplinePointReCatagorize(to,oldtpt);
1201 }
1202 
1203 
RemoveStupidControlPoints(SplineSet * spl)1204 static void RemoveStupidControlPoints(SplineSet *spl) {
1205     double len, normal, dir;
1206     Spline *s, *first;
1207     BasePoint unit, off;
1208 
1209     /* Also remove really stupid control points: Tiny offsets pointing in */
1210     /*  totally the wrong direction. Some of the TeX fonts we get have these */
1211     /* We get equally bad results with a control point that points beyond the */
1212     /*  other end point */
1213     first = NULL;
1214     for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
1215 	unit.x = s->to->me.x-s->from->me.x;
1216 	unit.y = s->to->me.y-s->from->me.y;
1217 	len = sqrt(unit.x*unit.x+unit.y*unit.y);
1218 	if ( len!=0 ) {
1219 	    int refigure = false;
1220 	    unit.x /= len; unit.y /= len;
1221 	    if ( !s->from->nonextcp ) {
1222 		off.x = s->from->nextcp.x-s->from->me.x;
1223 		off.y = s->from->nextcp.y-s->from->me.y;
1224 		if ((normal = off.x*unit.y - off.y*unit.x)<0 ) normal = -normal;
1225 		dir = off.x*unit.x + off.y*unit.y;
1226 		if (( normal<dir && normal<1 && dir<0 ) || (normal<.5 && dir<-.5) ||
1227 			(normal<.1 && dir>len)) {
1228 		    s->from->nextcp = s->from->me;
1229 		    s->from->nonextcp = true;
1230 		    refigure = true;
1231 		}
1232 	    }
1233 	    if ( !s->to->noprevcp ) {
1234 		off.x = s->to->me.x - s->to->prevcp.x;
1235 		off.y = s->to->me.y - s->to->prevcp.y;
1236 		if ((normal = off.x*unit.y - off.y*unit.x)<0 ) normal = -normal;
1237 		dir = off.x*unit.x + off.y*unit.y;
1238 		if (( normal<-dir && normal<1 && dir<0 ) || (normal<.5 && dir>-.5 && dir<0) ||
1239 			(normal<.1 && dir>len)) {
1240 		    s->to->prevcp = s->to->me;
1241 		    s->to->noprevcp = true;
1242 		    refigure = true;
1243 		}
1244 	    }
1245 	    if ( refigure )
1246 		SplineRefigure(s);
1247 	}
1248 	if ( first==NULL ) first = s;
1249     }
1250 }
1251 
SSRemoveStupidControlPoints(SplineSet * base)1252 void SSRemoveStupidControlPoints(SplineSet *base) {
1253     SplineSet *spl;
1254 
1255     for (spl=base; spl!=NULL; spl=spl->next )
1256 	RemoveStupidControlPoints(spl);
1257 }
1258 
OverlapClusterCpAngles(SplineSet * spl,double within)1259 static void OverlapClusterCpAngles(SplineSet *spl,double within) {
1260     double len, nlen, plen;
1261     double startoff, endoff;
1262     SplinePoint *sp, *nsp, *psp;
1263     BasePoint *nbp, *pbp;
1264     BasePoint pdir, ndir, fpdir, fndir;
1265     int nbad, pbad;
1266 
1267     /* If we have a junction point (right mid of 3) where the two splines */
1268     /*  are almost, but not quite moving in the same direction as they go */
1269     /*  away from the point, and if there is a tiny overlap because of this */
1270     /*  "almost" same, then we will probably get a bit confused in remove */
1271     /*  overlap */
1272 
1273     for ( sp = spl->first; ; ) {
1274 	if ( sp->next==NULL )
1275     break;
1276 	nsp = sp->next->to;
1277 	if (( !sp->nonextcp || !sp->noprevcp ) && sp->prev!=NULL ) {
1278 	    psp = sp->prev->from;
1279 	    nbp = !sp->nonextcp ? &sp->nextcp : !nsp->noprevcp ? &nsp->prevcp : &nsp->me;
1280 	    pbp = !sp->noprevcp ? &sp->prevcp : !psp->nonextcp ? &psp->nextcp : &psp->me;
1281 
1282 	    pdir.x = pbp->x-sp->me.x; pdir.y = pbp->y-sp->me.y;
1283 	    ndir.x = nbp->x-sp->me.x; ndir.y = nbp->y-sp->me.y;
1284 	    fpdir.x = psp->me.x-sp->me.x; fpdir.y = psp->me.y-sp->me.y;
1285 	    fndir.x = nsp->me.x-sp->me.x; fndir.y = nsp->me.y-sp->me.y;
1286 
1287 	    plen = sqrt(pdir.x*pdir.x+pdir.y*pdir.y);
1288 	    if ( plen!=0 ) {
1289 		pdir.x /= plen; pdir.y /= plen;
1290 	    }
1291 
1292 	    nlen = sqrt(ndir.x*ndir.x+ndir.y*ndir.y);
1293 	    if ( nlen!=0 ) {
1294 		ndir.x /= nlen; ndir.y /= nlen;
1295 	    }
1296 
1297 	    nbad = pbad = false;
1298 	    if ( !sp->nonextcp && plen!=0 && nlen!=0 ) {
1299 		len = sqrt(fndir.x*fndir.x+fndir.y*fndir.y);
1300 		if ( len!=0 ) {
1301 		    fndir.x /= len; fndir.y /= len;
1302 		    startoff = ndir.x*pdir.y - ndir.y*pdir.x;
1303 		    endoff = fndir.x*pdir.y - fndir.y*pdir.x;
1304 		    if (( (startoff<0 && endoff>0) || (startoff>0 && endoff<0)) &&
1305 			    startoff > -within && startoff < within )
1306 			nbad = true;
1307 		}
1308 	    }
1309 	    if ( !sp->noprevcp && plen!=0 && nlen!=0 ) {
1310 		len = sqrt(fpdir.x*fpdir.x+fpdir.y*fpdir.y);
1311 		if ( len!=0 ) {
1312 		    fpdir.x /= len; fpdir.y /= len;
1313 		    startoff = pdir.x*ndir.y - pdir.y*ndir.x;
1314 		    endoff = fpdir.x*ndir.y - fpdir.y*ndir.x;
1315 		    if (( (startoff<0 && endoff>0) || (startoff>0 && endoff<0)) &&
1316 			    startoff > -within && startoff < within )
1317 			pbad = true;
1318 		}
1319 	    }
1320 	    if ( nbad && pbad ) {
1321 		if ( ndir.x==0 || ndir.y==0 )
1322 		    nbad = false;
1323 		else if ( pdir.x==0 || pdir.y==0 )
1324 		    pbad = false;
1325 	    }
1326 	    if ( nbad && pbad ) {
1327 		if ( ndir.x*pdir.x + ndir.y*pdir.y > 0 ) {
1328 		    ndir.x = pdir.x = (ndir.x + pdir.x)/2;
1329 		    ndir.y = pdir.y = (ndir.x + pdir.x)/2;
1330 		} else {
1331 		    ndir.x = (ndir.x - pdir.x)/2;
1332 		    ndir.y = (ndir.y - pdir.y)/2;
1333 		    pdir.x = -ndir.x; pdir.y = -ndir.y;
1334 		}
1335 		sp->nextcp.x = sp->me.x + nlen*ndir.x;
1336 		sp->nextcp.y = sp->me.y + nlen*ndir.y;
1337 		sp->prevcp.x = sp->me.x + plen*pdir.x;
1338 		sp->prevcp.y = sp->me.y + plen*pdir.y;
1339 		SplineRefigure(sp->next); SplineRefigure(sp->prev);
1340 	    } else if ( nbad ) {
1341 		if ( ndir.x*pdir.x + ndir.y*pdir.y < 0 ) {
1342 		    pdir.x = -pdir.x;
1343 		    pdir.y = -pdir.y;
1344 		}
1345 		sp->nextcp.x = sp->me.x + nlen*pdir.x;
1346 		sp->nextcp.y = sp->me.y + nlen*pdir.y;
1347 		SplineRefigure(sp->next);
1348 	    } else if ( pbad ) {
1349 		if ( ndir.x*pdir.x + ndir.y*pdir.y < 0 ) {
1350 		    ndir.x = -ndir.x;
1351 		    ndir.y = -ndir.y;
1352 		}
1353 		sp->prevcp.x = sp->me.x + plen*ndir.x;
1354 		sp->prevcp.y = sp->me.y + plen*ndir.y;
1355 		SplineRefigure(sp->prev);
1356 	    }
1357 	}
1358 	if ( nsp==spl->first )
1359     break;
1360 	sp = nsp;
1361     }
1362 }
1363 
SSOverlapClusterCpAngles(SplineSet * base,double within)1364 void SSOverlapClusterCpAngles(SplineSet *base,double within) {
1365     SplineSet *spl;
1366 
1367     for (spl=base; spl!=NULL; spl=spl->next )
1368 	OverlapClusterCpAngles(spl,within);
1369 }
1370 
1371 
SplineAddExtrema(Spline * s,int always,real lenbound,real offsetbound,DBounds * b)1372 Spline *SplineAddExtrema(Spline *s,int always,real lenbound, real offsetbound,
1373 	DBounds *b) {
1374     /* First find the extrema, if any */
1375     bigreal t[4], min;
1376     uint8 rmfrom[4], rmto[4];
1377     int p, i,j, p_s, mini;
1378     SplinePoint *sp;
1379     real len = 0; /* Init variable to silence compiler warnings */
1380 
1381     if ( !always ) {
1382 	real xlen, ylen;
1383 	xlen = (s->from->me.x-s->to->me.x);
1384 	ylen = (s->from->me.y-s->to->me.y);
1385 	len = xlen*xlen + ylen*ylen;
1386 	lenbound *= lenbound;
1387 	if ( len < lenbound ) {
1388 	    len = SplineLength(s);
1389 	    len *= len;
1390 	}
1391     }
1392 
1393     memset(rmfrom,0,sizeof(rmfrom));
1394     memset(rmto,0,sizeof(rmto));
1395 
1396     forever {
1397 	if ( s->knownlinear )
1398 return(s);
1399 	p = 0;
1400 	if ( s->splines[0].a!=0 ) {
1401 	    double d = 4*s->splines[0].b*s->splines[0].b-4*3*s->splines[0].a*s->splines[0].c;
1402 	    if ( d>0 ) {
1403 		d = sqrt(d);
1404 		t[p++] = CheckExtremaForSingleBitErrors(&s->splines[0],(-2*s->splines[0].b+d)/(2*3*s->splines[0].a));
1405 		t[p++] = CheckExtremaForSingleBitErrors(&s->splines[0],(-2*s->splines[0].b-d)/(2*3*s->splines[0].a));
1406 	    }
1407 	} else if ( s->splines[0].b!=0 )
1408 	    t[p++] = -s->splines[0].c/(2*s->splines[0].b);
1409 	if ( !always ) {
1410 	    /* Generally we are only interested in extrema on long splines, or */
1411 	    /* extrema which are extrema for the entire contour, not just this */
1412 	    /* spline */
1413 	    /* Also extrema which are very close to one of the end-points can */
1414 	    /*  be ignored. */
1415 	    /* No they can't. But we need to remove the original point in this*/
1416 	    /*  case */
1417 	    for ( i=0; i<p; ++i ) {
1418 		real x = ((s->splines[0].a*t[i]+s->splines[0].b)*t[i]+s->splines[0].c)*t[i]+s->splines[0].d;
1419 		real y = ((s->splines[1].a*t[i]+s->splines[1].b)*t[i]+s->splines[1].c)*t[i]+s->splines[1].d;
1420 		int close_from = ( x-s->from->me.x<offsetbound && x-s->from->me.x>-offsetbound) &&
1421 				( y-s->from->me.y<10*offsetbound && y-s->from->me.y>-10*offsetbound );
1422 		int close_to = ( x-s->to->me.x<offsetbound && x-s->to->me.x>-offsetbound) &&
1423 				( y-s->to->me.y<10*offsetbound && y-s->to->me.y>-10*offsetbound );
1424 		int remove_from = close_from  && GoodCurve(s->from,true);
1425 		int remove_to = close_to  && GoodCurve(s->to,false);
1426 		if (( x>b->minx && x<b->maxx  && len<lenbound ) ||
1427 			(close_from && !remove_from) || (close_to && !remove_to) ) {
1428 		    --p;
1429 		    for ( j=i; j<p; ++j )
1430 			t[j] = t[j+1];
1431 		    --i;
1432 		} else {
1433 		    rmfrom[i] = remove_from;
1434 		    rmto[i] = remove_to;
1435 		}
1436 	    }
1437 	}
1438 
1439 	p_s = p;
1440 	if ( s->splines[1].a!=0 ) {
1441 	    double d = 4*s->splines[1].b*s->splines[1].b-4*3*s->splines[1].a*s->splines[1].c;
1442 	    if ( d>0 ) {
1443 		d = sqrt(d);
1444 		t[p++] = CheckExtremaForSingleBitErrors(&s->splines[1],(-2*s->splines[1].b+d)/(2*3*s->splines[1].a));
1445 		t[p++] = CheckExtremaForSingleBitErrors(&s->splines[1],(-2*s->splines[1].b-d)/(2*3*s->splines[1].a));
1446 	    }
1447 	} else if ( s->splines[1].b!=0 )
1448 	    t[p++] = -s->splines[1].c/(2*s->splines[1].b);
1449 	if ( !always ) {
1450 	    for ( i=p_s; i<p; ++i ) {
1451 		real x = ((s->splines[0].a*t[i]+s->splines[0].b)*t[i]+s->splines[0].c)*t[i]+s->splines[0].d;
1452 		real y = ((s->splines[1].a*t[i]+s->splines[1].b)*t[i]+s->splines[1].c)*t[i]+s->splines[1].d;
1453 		int close_from =( y-s->from->me.y<offsetbound && y-s->from->me.y>-offsetbound ) &&
1454 			( x-s->from->me.x<offsetbound && x-s->from->me.x>-offsetbound);
1455 		int close_to = ( y-s->to->me.y<offsetbound && y-s->to->me.y>-offsetbound ) &&
1456 			( x-s->to->me.x<offsetbound && x-s->to->me.x>-offsetbound);
1457 		int remove_from = close_from  && GoodCurve(s->from,true);
1458 		int remove_to = close_to  && GoodCurve(s->to,false);
1459 		if (( y>b->miny && y<b->maxy && len<lenbound ) ||
1460 			(close_from && !remove_from) || (close_to && !remove_to) ) {
1461 		    --p;
1462 		    for ( j=i; j<p; ++j )
1463 			t[j] = t[j+1];
1464 		    --i;
1465 		} else {
1466 		    rmfrom[i] = remove_from;
1467 		    rmto[i] = remove_to;
1468 		}
1469 	    }
1470 	}
1471 
1472 	/* Throw out any t values which are not between 0 and 1 */
1473 	/*  (we do a little fudging near the endpoints so we don't get confused */
1474 	/*   by rounding errors) */
1475 	for ( i=0; i<p; ++i ) {
1476 	    if ( t[i]>0 && t[i]<.05 ) {
1477 		BasePoint test;
1478 		/* Expand strong gets very confused on zero-length splines so */
1479 		/*  don't let that happen */
1480 		test.x = ((s->splines[0].a*t[i]+s->splines[0].b)*t[i]+s->splines[0].c)*t[i]+s->splines[0].d;
1481 		test.y = ((s->splines[1].a*t[i]+s->splines[1].b)*t[i]+s->splines[1].c)*t[i]+s->splines[1].d;
1482 		if ( test.x== s->from->me.x && test.y==s->from->me.y )
1483 		    t[i] = 0;		/* Throw it out */
1484 	    }
1485 	    if ( t[i]<1 && t[i]>.95 ) {
1486 		BasePoint test;
1487 		test.x = ((s->splines[0].a*t[i]+s->splines[0].b)*t[i]+s->splines[0].c)*t[i]+s->splines[0].d;
1488 		test.y = ((s->splines[1].a*t[i]+s->splines[1].b)*t[i]+s->splines[1].c)*t[i]+s->splines[1].d;
1489 		if ( test.x== s->to->me.x && test.y==s->to->me.y )
1490 		    t[i] = 1.0;		/* Throw it out */
1491 	    }
1492 
1493 	    if ( t[i]<.0001 || t[i]>.9999 ) {
1494 		--p;
1495 		for ( j=i; j<p; ++j ) {
1496 		    t[j] = t[j+1];
1497 		    rmfrom[j] = rmfrom[j+1];
1498 		    rmto[j] = rmto[j+1];
1499 		}
1500 		--i;
1501 	    }
1502 	}
1503 
1504 	if ( p==0 )
1505 return(s);
1506 
1507 	/* Find the smallest of all the interesting points */
1508 	min = t[0]; mini = 0;
1509 	for ( i=1; i<p; ++i ) {
1510 	    if ( t[i]<min ) {
1511 		min=t[i];
1512 		mini = i;
1513 	    }
1514 	}
1515 	sp = SplineBisect(s,min);
1516 /* On the mac we get rounding errors in the bisect routine */
1517 	{ double dx, dy;
1518 	    if ( (dx = sp->me.x - sp->prevcp.x)<0 ) dx=-dx;
1519 	    if ( (dy = sp->me.y - sp->prevcp.y)<0 ) dy=-dy;
1520 	    if ( dx!=0 && dy!=0 ) {
1521 		if ( dx<dy )
1522 		    sp->prevcp.x = sp->me.x;
1523 		else
1524 		    sp->prevcp.y = sp->me.y;
1525 	    }
1526 	    if ( (dx = sp->me.x - sp->nextcp.x)<0 ) dx=-dx;
1527 	    if ( (dy = sp->me.y - sp->nextcp.y)<0 ) dy=-dy;
1528 	    if ( dx!=0 && dy!=0 ) {
1529 		if ( dx<dy )
1530 		    sp->nextcp.x = sp->me.x;
1531 		else
1532 		    sp->nextcp.y = sp->me.y;
1533 	    }
1534 	}
1535 
1536 	if ( rmfrom[mini] ) sp->prev->from->ticked = true;
1537 	if ( rmto[mini] ) sp->next->to->ticked = true;
1538 	s = sp->next;
1539 	if ( p==1 )
1540 return( s );
1541 	/* Don't try to use any other computed t values, it is easier to */
1542 	/*  recompute them than to try and figure out what they map to on the */
1543 	/*  new spline */
1544     }
1545 }
1546 
SplineSetAddExtrema(SplineChar * sc,SplineSet * ss,enum ae_type between_selected,int emsize)1547 void SplineSetAddExtrema(SplineChar *sc, SplineSet *ss,enum ae_type between_selected, int emsize) {
1548     Spline *s, *first;
1549     DBounds b;
1550     int always = true;
1551     real lenbound = 0;
1552     real offsetbound=0;
1553     SplinePoint *sp, *nextp;
1554 
1555     if ( between_selected==ae_only_good ) {
1556 	SplineSetQuickBounds(ss,&b);
1557 	lenbound = (emsize)/32.0;
1558 	always = false;
1559 	offsetbound = .5;
1560 	between_selected = ae_only_good_rm_later;
1561 	for ( sp = ss->first; ; ) {
1562 	    sp->ticked = false;
1563 	    if ( sp->next==NULL )
1564 	break;
1565 	    sp = sp->next->to;
1566 	    if ( sp==ss->first )
1567 	break;
1568 	}
1569     }
1570 
1571     first = NULL;
1572     for ( s = ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
1573 	if ( between_selected!=ae_between_selected ||
1574 		(s->from->selected && s->to->selected))
1575 	    s = SplineAddExtrema(s,always,lenbound,offsetbound,&b);
1576 	if ( first==NULL ) first = s;
1577     }
1578     if ( between_selected == ae_only_good_rm_later ) {
1579 	for ( sp = ss->first; ; ) {
1580 	    if ( sp->next==NULL )
1581 	break;
1582 	    nextp = sp->next->to;
1583 	    if ( sp->ticked ) {
1584 		if ( sp==ss->first )
1585 		    ss->first = ss->last = nextp;
1586 		SplinesRemoveBetween(sc,sp->prev->from,nextp,1);
1587 	    }
1588 	    sp = nextp;
1589 	    if ( sp==ss->first )
1590 	break;
1591 	}
1592     }
1593 }
1594 
1595 
GetNextUntitledName(void)1596 char *GetNextUntitledName(void) {
1597     static int untitled_cnt=1;
1598     char buffer[80];
1599 
1600     sprintf( buffer, "Untitled%d", untitled_cnt++ );
1601 return( copy(buffer));
1602 }
1603 
SplineFontEmpty(void)1604 SplineFont *SplineFontEmpty(void) {
1605     extern int default_fv_row_count, default_fv_col_count;
1606     time_t now;
1607     SplineFont *sf;
1608 
1609     sf = gcalloc(1,sizeof(SplineFont));
1610     sf->pfminfo.fstype = -1;
1611     sf->top_enc = -1;
1612     sf->macstyle = -1;
1613     sf->desired_row_cnt = default_fv_row_count; sf->desired_col_cnt = default_fv_col_count;
1614     sf->display_antialias = default_fv_antialias;
1615     sf->display_bbsized = default_fv_bbsized;
1616     sf->display_size = -default_fv_font_size;
1617     sf->display_layer = ly_fore;
1618     sf->pfminfo.winascent_add = sf->pfminfo.windescent_add = true;
1619     sf->pfminfo.hheadascent_add = sf->pfminfo.hheaddescent_add = true;
1620     sf->pfminfo.typoascent_add = sf->pfminfo.typodescent_add = true;
1621     if ( TTFFoundry!=NULL )
1622 	strncpy(sf->pfminfo.os2_vendor,TTFFoundry,4);
1623     else
1624 	memcpy(sf->pfminfo.os2_vendor,"PfEd",4);
1625     sf->for_new_glyphs = DefaultNameListForNewFonts();
1626     time(&now);
1627     sf->creationtime = sf->modificationtime = now;
1628 
1629     sf->layer_cnt = 2;
1630     sf->layers = gcalloc(2,sizeof(LayerInfo));
1631     sf->layers[0].name = copy(_("Back"));
1632     sf->layers[0].background = true;
1633     sf->layers[1].name = copy(_("Fore"));
1634     sf->layers[1].background = false;
1635     sf->grid.background = true;
1636 
1637 return( sf );
1638 }
1639 
1640 
SFChangeXUID(SplineFont * sf,int random)1641 static void SFChangeXUID(SplineFont *sf, int random) {
1642     char *pt, *new, *npt;
1643     int val;
1644 
1645     if ( sf->xuid==NULL )
1646 return;
1647     pt = strrchr(sf->xuid,' ');
1648     if ( pt==NULL )
1649 	pt = strchr(sf->xuid,'[');
1650     if ( pt==NULL )
1651 	pt = sf->xuid;
1652     else
1653 	++pt;
1654     if ( random )
1655 	val = rand()&0xffffff;
1656     else {
1657 	val = strtol(pt,NULL,10);
1658 	val = (val+1)&0xffffff;
1659     }
1660 
1661     new = galloc(pt-sf->xuid+12);
1662     strncpy(new,sf->xuid,pt-sf->xuid);
1663     npt = new + (pt-sf->xuid);
1664     if ( npt==new ) *npt++ = '[';
1665     sprintf(npt, "%d]", val );
1666     free(sf->xuid); sf->xuid = new;
1667     sf->changed = true;
1668     sf->changed_since_xuidchanged = false;
1669 }
1670 
SFIncrementXUID(SplineFont * sf)1671 void SFIncrementXUID(SplineFont *sf) {
1672     SFChangeXUID(sf,false);
1673 }
1674 
SFRandomChangeXUID(SplineFont * sf)1675 void SFRandomChangeXUID(SplineFont *sf) {
1676     SFChangeXUID(sf,true);
1677 }
1678 
SPWeightedAverageCps(SplinePoint * sp)1679 void SPWeightedAverageCps(SplinePoint *sp) {
1680     double pangle, nangle, angle, plen, nlen, c, s;
1681     if ( sp->noprevcp || sp->nonextcp )
1682 	/*SPAverageCps(sp)*/;		/* Expand Stroke wants this case to hold still */
1683     else if (( sp->pointtype==pt_curve || sp->pointtype==pt_hvcurve) &&
1684 	    sp->prev && sp->next ) {
1685 	pangle = atan2(sp->me.y-sp->prevcp.y,sp->me.x-sp->prevcp.x);
1686 	nangle = atan2(sp->nextcp.y-sp->me.y,sp->nextcp.x-sp->me.x);
1687 	if ( pangle<0 && nangle>0 && nangle-pangle>=3.1415926 )
1688 	    pangle += 2*3.1415926535897932;
1689 	else if ( pangle>0 && nangle<0 && pangle-nangle>=3.1415926 )
1690 	    nangle += 2*3.1415926535897932;
1691 	plen = sqrt((sp->me.y-sp->prevcp.y)*(sp->me.y-sp->prevcp.y) +
1692 		(sp->me.x-sp->prevcp.x)*(sp->me.x-sp->prevcp.x));
1693 	nlen = sqrt((sp->nextcp.y-sp->me.y)*(sp->nextcp.y-sp->me.y) +
1694 		(sp->nextcp.x-sp->me.x)*(sp->nextcp.x-sp->me.x));
1695 	if ( plen+nlen==0 )
1696 	    angle = (nangle+pangle)/2;
1697 	else
1698 	    angle = (plen*pangle + nlen*nangle)/(plen+nlen);
1699 	plen = -plen;
1700 	c = cos(angle); s=sin(angle);
1701 	sp->nextcp.x = c*nlen + sp->me.x;
1702 	sp->nextcp.y = s*nlen + sp->me.y;
1703 	sp->prevcp.x = c*plen + sp->me.x;
1704 	sp->prevcp.y = s*plen + sp->me.y;
1705 	SplineRefigure(sp->prev);
1706 	SplineRefigure(sp->next);
1707     } else
1708 	SPAverageCps(sp);
1709 }
1710 
SPAverageCps(SplinePoint * sp)1711 void SPAverageCps(SplinePoint *sp) {
1712     double pangle, nangle, angle, plen, nlen, c, s;
1713     if (( sp->pointtype==pt_curve || sp->pointtype==pt_hvcurve) &&
1714 	    sp->prev && sp->next ) {
1715 	if ( sp->noprevcp )
1716 	    pangle = atan2(sp->me.y-sp->prev->from->me.y,sp->me.x-sp->prev->from->me.x);
1717 	else
1718 	    pangle = atan2(sp->me.y-sp->prevcp.y,sp->me.x-sp->prevcp.x);
1719 	if ( sp->nonextcp )
1720 	    nangle = atan2(sp->next->to->me.y-sp->me.y,sp->next->to->me.x-sp->me.x);
1721 	else
1722 	    nangle = atan2(sp->nextcp.y-sp->me.y,sp->nextcp.x-sp->me.x);
1723 	if ( pangle<0 && nangle>0 && nangle-pangle>=3.1415926 )
1724 	    pangle += 2*3.1415926535897932;
1725 	else if ( pangle>0 && nangle<0 && pangle-nangle>=3.1415926 )
1726 	    nangle += 2*3.1415926535897932;
1727 	angle = (nangle+pangle)/2;
1728 	plen = -sqrt((sp->me.y-sp->prevcp.y)*(sp->me.y-sp->prevcp.y) +
1729 		(sp->me.x-sp->prevcp.x)*(sp->me.x-sp->prevcp.x));
1730 	nlen = sqrt((sp->nextcp.y-sp->me.y)*(sp->nextcp.y-sp->me.y) +
1731 		(sp->nextcp.x-sp->me.x)*(sp->nextcp.x-sp->me.x));
1732 	c = cos(angle); s=sin(angle);
1733 	sp->nextcp.x = c*nlen + sp->me.x;
1734 	sp->nextcp.y = s*nlen + sp->me.y;
1735 	sp->prevcp.x = c*plen + sp->me.x;
1736 	sp->prevcp.y = s*plen + sp->me.y;
1737 	SplineRefigure(sp->prev);
1738 	SplineRefigure(sp->next);
1739     } else if ( sp->pointtype==pt_tangent && sp->prev && sp->next ) {
1740 	if ( !sp->noprevcp ) {
1741 	    nangle = atan2(sp->next->to->me.y-sp->me.y,sp->next->to->me.x-sp->me.x);
1742 	    plen = -sqrt((sp->me.y-sp->prevcp.y)*(sp->me.y-sp->prevcp.y) +
1743 		    (sp->me.x-sp->prevcp.x)*(sp->me.x-sp->prevcp.x));
1744 	    c = cos(nangle); s=sin(nangle);
1745 	    sp->prevcp.x = c*plen + sp->me.x;
1746 	    sp->prevcp.y = s*plen + sp->me.y;
1747 	SplineRefigure(sp->prev);
1748 	}
1749 	if ( !sp->nonextcp ) {
1750 	    pangle = atan2(sp->me.y-sp->prev->from->me.y,sp->me.x-sp->prev->from->me.x);
1751 	    nlen = sqrt((sp->nextcp.y-sp->me.y)*(sp->nextcp.y-sp->me.y) +
1752 		    (sp->nextcp.x-sp->me.x)*(sp->nextcp.x-sp->me.x));
1753 	    c = cos(pangle); s=sin(pangle);
1754 	    sp->nextcp.x = c*nlen + sp->me.x;
1755 	    sp->nextcp.y = s*nlen + sp->me.y;
1756 	    SplineRefigure(sp->next);
1757 	}
1758     }
1759 }
1760 
1761 
SplineCharTangentNextCP(SplinePoint * sp)1762 void SplineCharTangentNextCP(SplinePoint *sp) {
1763     double len;
1764     BasePoint *bp, unit;
1765     extern int snaptoint;
1766 
1767     if ( sp->prev==NULL )
1768 return;
1769     bp = &sp->prev->from->me;
1770 
1771     unit.y = sp->me.y-bp->y; unit.x = sp->me.x-bp->x;
1772     len = sqrt( unit.x*unit.x + unit.y*unit.y );
1773     if ( len!=0 ) {
1774 	unit.x /= len;
1775 	unit.y /= len;
1776     }
1777     len = sqrt((sp->nextcp.y-sp->me.y)*(sp->nextcp.y-sp->me.y) + (sp->nextcp.x-sp->me.x)*(sp->nextcp.x-sp->me.x));
1778     sp->nextcp.x = sp->me.x + len*unit.x;
1779     sp->nextcp.y = sp->me.y + len*unit.y;
1780     if ( snaptoint ) {
1781 	sp->nextcp.x = rint(sp->nextcp.x);
1782 	sp->nextcp.y = rint(sp->nextcp.y);
1783     } else {
1784 	sp->nextcp.x = rint(sp->nextcp.x*1024)/1024;
1785 	sp->nextcp.y = rint(sp->nextcp.y*1024)/1024;
1786     }
1787     if ( sp->next!=NULL && sp->next->order2 )
1788 	sp->next->to->prevcp = sp->nextcp;
1789 }
1790 
SplineCharTangentPrevCP(SplinePoint * sp)1791 void SplineCharTangentPrevCP(SplinePoint *sp) {
1792     double len;
1793     BasePoint *bp, unit;
1794     extern int snaptoint;
1795 
1796     if ( sp->next==NULL )
1797 return;
1798     bp = &sp->next->to->me;
1799 
1800     unit.y = sp->me.y-bp->y; unit.x = sp->me.x-bp->x;
1801     len = sqrt( unit.x*unit.x + unit.y*unit.y );
1802     if ( len!=0 ) {
1803 	unit.x /= len;
1804 	unit.y /= len;
1805     }
1806     len = sqrt((sp->prevcp.y-sp->me.y)*(sp->prevcp.y-sp->me.y) + (sp->prevcp.x-sp->me.x)*(sp->prevcp.x-sp->me.x));
1807     sp->prevcp.x = sp->me.x + len*unit.x;
1808     sp->prevcp.y = sp->me.y + len*unit.y;
1809     if ( snaptoint ) {
1810 	sp->prevcp.x = rint(sp->prevcp.x);
1811 	sp->prevcp.y = rint(sp->prevcp.y);
1812     } else {
1813 	sp->prevcp.x = rint(sp->prevcp.x*1024)/1024;
1814 	sp->prevcp.y = rint(sp->prevcp.y*1024)/1024;
1815     }
1816     if ( sp->prev!=NULL && sp->prev->order2 )
1817 	sp->prev->from->nextcp = sp->prevcp;
1818 }
1819 
BP_HVForce(BasePoint * vector)1820 static void BP_HVForce(BasePoint *vector) {
1821     /* Force vector to be horizontal/vertical */
1822     double dx, dy, len;
1823 
1824     if ( (dx= vector->x)<0 ) dx = -dx;
1825     if ( (dy= vector->y)<0 ) dy = -dy;
1826     if ( dx==0 || dy==0 )
1827 return;
1828     len = sqrt(dx*dx + dy*dy);
1829     if ( dx>dy ) {
1830 	vector->x = vector->x<0 ? -len : len;
1831 	vector->y = 0;
1832     } else {
1833 	vector->y = vector->y<0 ? -len : len;
1834 	vector->x = 0;
1835     }
1836 }
1837 
1838 #define NICE_PROPORTION	.39
SplineCharDefaultNextCP(SplinePoint * base)1839 void SplineCharDefaultNextCP(SplinePoint *base) {
1840     SplinePoint *prev=NULL, *next;
1841     double len, plen, ulen;
1842     BasePoint unit;
1843     extern int snaptoint;
1844 
1845     if ( base->next==NULL )
1846 return;
1847     if ( base->next->order2 ) {
1848 	SplineRefigureFixup(base->next);
1849 return;
1850     }
1851     if ( !base->nextcpdef ) {
1852 	if ( base->pointtype==pt_tangent )
1853 	    SplineCharTangentNextCP(base);
1854 return;
1855     }
1856     next = base->next->to;
1857     if ( base->prev!=NULL )
1858 	prev = base->prev->from;
1859 
1860     len = NICE_PROPORTION * sqrt((base->me.x-next->me.x)*(base->me.x-next->me.x) +
1861 	    (base->me.y-next->me.y)*(base->me.y-next->me.y));
1862     unit.x = next->me.x - base->me.x;
1863     unit.y = next->me.y - base->me.y;
1864     ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
1865     if ( ulen!=0 )
1866 	unit.x /= ulen, unit.y /= ulen;
1867     base->nonextcp = false;
1868 
1869     if ( base->pointtype == pt_curve || base->pointtype == pt_hvcurve ) {
1870 	if ( prev!=NULL && (base->prevcpdef || base->noprevcp)) {
1871 	    unit.x = next->me.x - prev->me.x;
1872 	    unit.y = next->me.y - prev->me.y;
1873 	    ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
1874 	    if ( ulen!=0 )
1875 		unit.x /= ulen, unit.y /= ulen;
1876 	    if ( base->pointtype == pt_hvcurve )
1877 		BP_HVForce(&unit);
1878 	    plen = sqrt((base->prevcp.x-base->me.x)*(base->prevcp.x-base->me.x) +
1879 		    (base->prevcp.y-base->me.y)*(base->prevcp.y-base->me.y));
1880 	    base->prevcp.x = base->me.x - plen*unit.x;
1881 	    base->prevcp.y = base->me.y - plen*unit.y;
1882 	    if ( snaptoint ) {
1883 		base->prevcp.x = rint(base->prevcp.x);
1884 		base->prevcp.y = rint(base->prevcp.y);
1885 	    }
1886 	    SplineRefigureFixup(base->prev);
1887 	} else if ( prev!=NULL ) {
1888 	    /* The prev control point is fixed. So we've got to use the same */
1889 	    /*  angle it uses */
1890 	    unit.x = base->me.x-base->prevcp.x;
1891 	    unit.y = base->me.y-base->prevcp.y;
1892 	    ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
1893 	    if ( ulen!=0 )
1894 		unit.x /= ulen, unit.y /= ulen;
1895 	} else {
1896 	    base->prevcp = base->me;
1897 	    base->noprevcp = true;
1898 	    base->prevcpdef = true;
1899 	}
1900 	if ( base->pointtype == pt_hvcurve )
1901 	    BP_HVForce(&unit);
1902     } else if ( base->pointtype == pt_corner ) {
1903 	if ( next->pointtype != pt_curve && next->pointtype != pt_hvcurve ) {
1904 	    base->nonextcp = true;
1905 	}
1906     } else /* tangent */ {
1907 	if ( next->pointtype != pt_curve ) {
1908 	    base->nonextcp = true;
1909 	} else {
1910 	    if ( prev!=NULL ) {
1911 		if ( !base->noprevcp ) {
1912 		    plen = sqrt((base->prevcp.x-base->me.x)*(base->prevcp.x-base->me.x) +
1913 			    (base->prevcp.y-base->me.y)*(base->prevcp.y-base->me.y));
1914 		    base->prevcp.x = base->me.x - plen*unit.x;
1915 		    base->prevcp.y = base->me.y - plen*unit.y;
1916 		    SplineRefigureFixup(base->prev);
1917 		}
1918 		unit.x = base->me.x-prev->me.x;
1919 		unit.y = base->me.y-prev->me.y;
1920 		ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
1921 		if ( ulen!=0 )
1922 		    unit.x /= ulen, unit.y /= ulen;
1923 	    }
1924 	}
1925     }
1926     if ( base->nonextcp )
1927 	base->nextcp = base->me;
1928     else {
1929 	base->nextcp.x = base->me.x + len*unit.x;
1930 	base->nextcp.y = base->me.y + len*unit.y;
1931 	if ( snaptoint ) {
1932 	    base->nextcp.x = rint(base->nextcp.x);
1933 	    base->nextcp.y = rint(base->nextcp.y);
1934 	} else {
1935 	    base->nextcp.x = rint(base->nextcp.x*1024)/1024;
1936 	    base->nextcp.y = rint(base->nextcp.y*1024)/1024;
1937 	}
1938 	if ( base->next != NULL )
1939 	    SplineRefigureFixup(base->next);
1940     }
1941 }
1942 
SplineCharDefaultPrevCP(SplinePoint * base)1943 void SplineCharDefaultPrevCP(SplinePoint *base) {
1944     SplinePoint *next=NULL, *prev;
1945     double len, nlen, ulen;
1946     BasePoint unit;
1947     extern int snaptoint;
1948 
1949     if ( base->prev==NULL )
1950 return;
1951     if ( base->prev->order2 ) {
1952 	SplineRefigureFixup(base->prev);
1953 return;
1954     }
1955     if ( !base->prevcpdef ) {
1956 	if ( base->pointtype==pt_tangent )
1957 	    SplineCharTangentPrevCP(base);
1958 return;
1959     }
1960     prev = base->prev->from;
1961     if ( base->next!=NULL )
1962 	next = base->next->to;
1963 
1964     len = NICE_PROPORTION * sqrt((base->me.x-prev->me.x)*(base->me.x-prev->me.x) +
1965 	    (base->me.y-prev->me.y)*(base->me.y-prev->me.y));
1966     unit.x = prev->me.x - base->me.x;
1967     unit.y = prev->me.y - base->me.y;
1968     ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
1969     if ( ulen!=0 )
1970 	unit.x /= ulen, unit.y /= ulen;
1971     base->noprevcp = false;
1972 
1973     if ( base->pointtype == pt_curve || base->pointtype == pt_hvcurve ) {
1974 	if ( next!=NULL && (base->nextcpdef || base->nonextcp)) {
1975 	    unit.x = prev->me.x - next->me.x;
1976 	    unit.y = prev->me.y - next->me.y;
1977 	    ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
1978 	    if ( ulen!=0 )
1979 		unit.x /= ulen, unit.y /= ulen;
1980 	    if ( base->pointtype == pt_hvcurve )
1981 		BP_HVForce(&unit);
1982 	    nlen = sqrt((base->nextcp.x-base->me.x)*(base->nextcp.x-base->me.x) +
1983 		    (base->nextcp.y-base->me.y)*(base->nextcp.y-base->me.y));
1984 	    base->nextcp.x = base->me.x - nlen*unit.x;
1985 	    base->nextcp.y = base->me.y - nlen*unit.y;
1986 	    if ( snaptoint ) {
1987 		base->nextcp.x = rint(base->nextcp.x);
1988 		base->nextcp.y = rint(base->nextcp.y);
1989 	    }
1990 	    SplineRefigureFixup(base->next);
1991 	} else if ( next!=NULL ) {
1992 	    /* The next control point is fixed. So we got to use the same */
1993 	    /*  angle it uses */
1994 	    unit.x = base->me.x-base->nextcp.x;
1995 	    unit.y = base->me.y-base->nextcp.y;
1996 	    ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
1997 	    if ( ulen!=0 )
1998 		unit.x /= ulen, unit.y /= ulen;
1999 	} else {
2000 	    base->nextcp = base->me;
2001 	    base->nonextcp = true;
2002 	    base->nextcpdef = true;
2003 	}
2004 	if ( base->pointtype == pt_hvcurve )
2005 	    BP_HVForce(&unit);
2006     } else if ( base->pointtype == pt_corner ) {
2007 	if ( prev->pointtype != pt_curve && prev->pointtype != pt_hvcurve ) {
2008 	    base->noprevcp = true;
2009 	}
2010     } else /* tangent */ {
2011 	if ( prev->pointtype != pt_curve ) {
2012 	    base->noprevcp = true;
2013 	} else {
2014 	    if ( next!=NULL ) {
2015 		if ( !base->nonextcp ) {
2016 		    nlen = sqrt((base->nextcp.x-base->me.x)*(base->nextcp.x-base->me.x) +
2017 			    (base->nextcp.y-base->me.y)*(base->nextcp.y-base->me.y));
2018 		    base->nextcp.x = base->me.x - nlen*unit.x;
2019 		    base->nextcp.y = base->me.y - nlen*unit.y;
2020 		    SplineRefigureFixup(base->next);
2021 		}
2022 		unit.x = base->me.x-next->me.x;
2023 		unit.y = base->me.y-next->me.y;
2024 		ulen = sqrt(unit.x*unit.x + unit.y*unit.y);
2025 		if ( ulen!=0 )
2026 		    unit.x /= ulen, unit.y /= ulen;
2027 	    }
2028 	}
2029     }
2030     if ( base->noprevcp )
2031 	base->prevcp = base->me;
2032     else {
2033 	base->prevcp.x = base->me.x + len*unit.x;
2034 	base->prevcp.y = base->me.y + len*unit.y;
2035 	if ( snaptoint ) {
2036 	    base->prevcp.x = rint(base->prevcp.x);
2037 	    base->prevcp.y = rint(base->prevcp.y);
2038 	} else {
2039 	    base->prevcp.x = rint(base->prevcp.x*1024)/1024;
2040 	    base->prevcp.y = rint(base->prevcp.y*1024)/1024;
2041 	}
2042 	if ( base->prev!=NULL )
2043 	    SplineRefigureFixup(base->prev);
2044     }
2045 }
2046 
2047 
SplineSetReverse(SplineSet * spl)2048 SplineSet *SplineSetReverse(SplineSet *spl) {
2049     Spline *spline, *first, *next;
2050     BasePoint tp;
2051     SplinePoint *temp;
2052     int bool;
2053     /* reverse the splineset so that what was the start point becomes the end */
2054     /*  and vice versa. This entails reversing every individual spline, and */
2055     /*  each point */
2056 
2057     first = NULL;
2058     spline = spl->first->next;
2059     if ( spline==NULL )
2060 return( spl );			/* Only one point, reversal is meaningless */
2061 
2062     tp = spline->from->nextcp;
2063     spline->from->nextcp = spline->from->prevcp;
2064     spline->from->prevcp = tp;
2065     bool = spline->from->nonextcp;
2066     spline->from->nonextcp = spline->from->noprevcp;
2067     spline->from->noprevcp = bool;
2068     bool = spline->from->nextcpdef;
2069     spline->from->nextcpdef = spline->from->prevcpdef;
2070     spline->from->prevcpdef = bool;
2071 
2072     for ( ; spline!=NULL && spline!=first; spline=next ) {
2073 	next = spline->to->next;
2074 
2075 	if ( spline->to!=spl->first ) {		/* On a closed spline don't want to reverse the first point twice */
2076 	    tp = spline->to->nextcp;
2077 	    spline->to->nextcp = spline->to->prevcp;
2078 	    spline->to->prevcp = tp;
2079 	    bool = spline->to->nonextcp;
2080 	    spline->to->nonextcp = spline->to->noprevcp;
2081 	    spline->to->noprevcp = bool;
2082 	    bool = spline->to->nextcpdef;
2083 	    spline->to->nextcpdef = spline->to->prevcpdef;
2084 	    spline->to->prevcpdef = bool;
2085 	}
2086 
2087 	temp = spline->to;
2088 	spline->to = spline->from;
2089 	spline->from = temp;
2090 	spline->from->next = spline;
2091 	spline->to->prev = spline;
2092 	SplineRefigure(spline);
2093 	if ( first==NULL ) first = spline;
2094     }
2095 
2096     if ( spl->first!=spl->last ) {
2097 	temp = spl->first;
2098 	spl->first = spl->last;
2099 	spl->last = temp;
2100 	spl->first->prev = NULL;
2101 	spl->last->next = NULL;
2102     }
2103 
2104 return( spl );
2105 }
2106 
SplineSetsUntick(SplineSet * spl)2107 static void SplineSetsUntick(SplineSet *spl) {
2108     Spline *spline, *first;
2109 
2110     while ( spl!=NULL ) {
2111 	first = NULL;
2112 	spl->first->isintersection = false;
2113 	for ( spline=spl->first->next; spline!=first && spline!=NULL; spline = spline->to->next ) {
2114 	    spline->isticked = false;
2115 	    spline->isneeded = false;
2116 	    spline->isunneeded = false;
2117 	    spline->ishorvert = false;
2118 	    spline->to->isintersection = false;
2119 	    if ( first==NULL ) first = spline;
2120 	}
2121 	spl = spl->next;
2122     }
2123 }
2124 
SplineSetTick(SplineSet * spl)2125 static void SplineSetTick(SplineSet *spl) {
2126     Spline *spline, *first;
2127 
2128     first = NULL;
2129     for ( spline=spl->first->next; spline!=first && spline!=NULL; spline = spline->to->next ) {
2130 	spline->isticked = true;
2131 	if ( first==NULL ) first = spline;
2132     }
2133 }
2134 
SplineSetOfSpline(SplineSet * spl,Spline * search)2135 static SplineSet *SplineSetOfSpline(SplineSet *spl,Spline *search) {
2136     Spline *spline, *first;
2137 
2138     while ( spl!=NULL ) {
2139 	first = NULL;
2140 	for ( spline=spl->first->next; spline!=first && spline!=NULL; spline = spline->to->next ) {
2141 	    if ( spline==search )
2142 return( spl );
2143 	    if ( first==NULL ) first = spline;
2144 	}
2145 	spl = spl->next;
2146     }
2147 return( NULL );
2148 }
2149 
SplineInSplineSet(Spline * spline,SplineSet * spl)2150 static int SplineInSplineSet(Spline *spline, SplineSet *spl) {
2151     Spline *first, *s;
2152 
2153     first = NULL;
2154     for ( s = spl->first->next; s!=NULL && s!=first; s = s->to->next ) {
2155 	if ( s==spline )
2156 return( true );
2157 	if ( first==NULL ) first = s;
2158     }
2159 return( false );
2160 }
2161 
2162 #include "edgelist.h"
2163 
EdgeListReverse(EdgeList * es,SplineSet * spl)2164 static void EdgeListReverse(EdgeList *es, SplineSet *spl) {
2165     int i;
2166 
2167     if ( es->edges!=NULL ) {
2168 	for ( i=0; i<es->cnt; ++i ) {
2169 	    Edge *e;
2170 	    for ( e = es->edges[i]; e!=NULL; e = e->esnext ) {
2171 		if ( SplineInSplineSet(e->spline,spl)) {
2172 		    e->up = !e->up;
2173 		    e->t_mmin = 1-e->t_mmin;
2174 		    e->t_mmax = 1-e->t_mmax;
2175 		    e->t_cur = 1-e->t_cur;
2176 		}
2177 	    }
2178 	}
2179     }
2180 }
2181 
SSCheck(SplineSet * base,Edge * active,int up,EdgeList * es,int * changed)2182 static int SSCheck(SplineSet *base,Edge *active, int up, EdgeList *es,int *changed) {
2183     SplineSet *spl;
2184     if ( active->spline->isticked )
2185 return( 0 );
2186     spl = SplineSetOfSpline(base,active->spline);
2187     if ( active->up!=up ) {
2188 	SplineSetReverse(spl);
2189 	*changed = true;
2190 	EdgeListReverse(es,spl);
2191     }
2192     SplineSetTick(spl);
2193 return( 1 );
2194 }
2195 
2196 
2197 /* The idea behind SplineSetsCorrect is simple. However there are many splinesets */
2198 /*  where it is impossible, so bear in mind that this only works for nice */
2199 /*  splines. Figure 8's, interesecting splines all cause problems */
2200 /* The outermost spline should be clockwise (up), the next splineset we find */
2201 /*  should be down, if it isn't reverse it (if it's already been dealt with */
2202 /*  then ignore it) */
SplineSetsCorrect(SplineSet * base,int * changed)2203 SplineSet *SplineSetsCorrect(SplineSet *base,int *changed) {
2204     SplineSet *spl;
2205     int sscnt, check_cnt;
2206     EdgeList es;
2207     DBounds b;
2208     Edge *active=NULL, *apt, *pr, *e;
2209     int i, winding;
2210 
2211     *changed = false;
2212 
2213     SplineSetsUntick(base);
2214     for (sscnt=0,spl=base; spl!=NULL; spl=spl->next, ++sscnt );
2215 
2216     SplineSetFindBounds(base,&b);
2217     memset(&es,'\0',sizeof(es));
2218     es.scale = 1.0;
2219     es.mmin = floor(b.miny*es.scale);
2220     es.mmax = ceil(b.maxy*es.scale);
2221     es.omin = b.minx*es.scale;
2222     es.omax = b.maxx*es.scale;
2223     es.layer = ly_fore;		/* Not meaningful */
2224 
2225 /* Give up if we are given unreasonable values (ie. if rounding errors might screw us up) */
2226     if ( es.mmin<1e5 && es.mmax>-1e5 && es.omin<1e5 && es.omax>-1e5 ) {
2227 	es.cnt = (int) (es.mmax-es.mmin) + 1;
2228 	es.edges = gcalloc(es.cnt,sizeof(Edge *));
2229 	es.interesting = gcalloc(es.cnt,sizeof(char));
2230 	es.sc = NULL;
2231 	es.major = 1; es.other = 0;
2232 	FindEdgesSplineSet(base,&es,false);
2233 
2234 	check_cnt = 0;
2235 	for ( i=0; i<es.cnt && check_cnt<sscnt; ++i ) {
2236 	    active = ActiveEdgesRefigure(&es,active,i);
2237 	    if ( es.edges[i]!=NULL )
2238 	continue;			/* Just too hard to get the edges sorted when we are at a start vertex */
2239 	    if ( /*es.edges[i]==NULL &&*/ !es.interesting[i] &&
2240 		    !(i>0 && es.interesting[i-1]) && !(i>0 && es.edges[i-1]!=NULL) &&
2241 		    !(i<es.cnt-1 && es.edges[i+1]!=NULL) &&
2242 		    !(i<es.cnt-1 && es.interesting[i+1]))	/* interesting things happen when we add (or remove) entries */
2243 	continue;			/* and where we have extrema */
2244 	    for ( apt=active; apt!=NULL; apt = e) {
2245 		check_cnt += SSCheck(base,apt,true,&es,changed);
2246 		winding = apt->up?1:-1;
2247 		for ( pr=apt, e=apt->aenext; e!=NULL && winding!=0; pr=e, e=e->aenext ) {
2248 		    if ( !e->spline->isticked )
2249 			check_cnt += SSCheck(base,e,winding<0,&es,changed);
2250 		    if ( pr->up!=e->up )
2251 			winding += (e->up?1:-1);
2252 		    else if ( (pr->before==e || pr->after==e ) &&
2253 			    (( pr->mmax==i && e->mmin==i ) ||
2254 			     ( pr->mmin==i && e->mmax==i )) )
2255 			/* This just continues the line and doesn't change count */;
2256 		    else
2257 			winding += (e->up?1:-1);
2258 		}
2259 		/* color a horizontal line that comes out of the last vertex */
2260 		if ( e!=NULL && (e->before==pr || e->after==pr) &&
2261 			    (( pr->mmax==i && e->mmin==i ) ||
2262 			     ( pr->mmin==i && e->mmax==i )) ) {
2263 		    pr = e;
2264 		    e = e->aenext;
2265 		}
2266 	    }
2267 	}
2268 	FreeEdges(&es);
2269     }
2270 return( base );
2271 }
2272 
2273 
SplinePointListIsClockwise(const SplineSet * spl)2274 int SplinePointListIsClockwise(const SplineSet *spl) {
2275     EIList el;
2276     EI *active=NULL, *apt, *e;
2277     int i, change,waschange;
2278     SplineChar dummy;
2279     SplineSet *next;
2280     int ret = -1, maybe=-1;
2281     Layer layers[2];
2282 
2283     if ( spl->first!=spl->last || spl->first->next == NULL )
2284 return( -1 );		/* Open paths, (open paths with only one point are a special case) */
2285 
2286     memset(&el,'\0',sizeof(el));
2287     memset(&dummy,'\0',sizeof(dummy));
2288     memset(layers,0,sizeof(layers));
2289     el.layer = ly_fore;
2290     dummy.layers = layers;
2291     dummy.layer_cnt = 2;
2292     dummy.layers[ly_fore].splines = (SplineSet *) spl;
2293     next = spl->next; ((SplineSet *) spl)->next = NULL;
2294     ELFindEdges(&dummy,&el);
2295     if ( el.coordmax[1]-el.coordmin[1] > 1.e6 ) {
2296 	LogError( _("Warning: Unreasonably big splines. They will be ignored.\n") );
2297 return( -1 );
2298     }
2299     el.major = 1;
2300     ELOrder(&el,el.major);
2301 
2302     waschange = false;
2303     for ( i=0; i<el.cnt && ret==-1; ++i ) {
2304 	active = EIActiveEdgesRefigure(&el,active,i,1,&change);
2305 	if ( el.ordered[i]!=NULL || el.ends[i] || waschange || change ) {
2306 	    waschange = change;
2307 	    if ( active!=NULL )
2308 		maybe = active->up;
2309     continue;			/* Just too hard to get the edges sorted when we are at a start vertex */
2310 	}
2311 	waschange = change;
2312 	for ( apt=active; apt!=NULL && ret==-1; apt = e) {
2313 	    if ( EISkipExtremum(apt,i+el.low,1)) {
2314 		e = apt->aenext->aenext;
2315 	continue;
2316 	    }
2317 	    ret = apt->up;
2318 	break;
2319 	}
2320     }
2321     free(el.ordered);
2322     free(el.ends);
2323     ElFreeEI(&el);
2324     ((SplineSet *) spl)->next = next;
2325     if ( ret==-1 )
2326 	ret = maybe;
2327 return( ret );
2328 }
2329