[arch-commits] Commit in fontforge/trunk (spline-fix.patch)
Gaetan Bisson
bisson at archlinux.org
Wed Sep 29 22:43:13 UTC 2010
Date: Wednesday, September 29, 2010 @ 18:43:12
Author: bisson
Revision: 92444
missing patch...
Added:
fontforge/trunk/spline-fix.patch
------------------+
spline-fix.patch | 954 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 954 insertions(+)
Added: spline-fix.patch
===================================================================
--- spline-fix.patch (rev 0)
+++ spline-fix.patch 2010-09-29 22:43:12 UTC (rev 92444)
@@ -0,0 +1,954 @@
+diff -aur fontforge-20100501/fontforge/splinestroke.c fontforge-SVN-20100929/fontforge/splinestroke.c
+--- fontforge-20100501/fontforge/splinestroke.c 2010-04-29 05:53:21.000000000 +0200
++++ fontforge-SVN-20100929/fontforge/splinestroke.c 2010-09-14 22:08:14.000000000 +0200
+@@ -51,10 +51,25 @@
+ uint8 rt;
+ } StrokePoint;
+
++/* Square line caps and miter line joins cover more area than the circular pen*/
++/* So we need a list of the polygons which represent these guys so we can do */
++/* an additional hit test on them. */
++/* I'm not sure that these will always be presented to us in a clockwise fashion*/
++/* We can test that by taking a point which is the average of the vertices */
++/* and seeing if the hit-test says it is inside (It will be inside because */
++/* these polies are convex). If the hit test fails then the poly must be */
++/* drawn counter clockwise */
++struct extrapoly {
++ BasePoint poly[4];
++ int ptcnt; /* 3 (for miters) or 4 (for square caps) */
++};
++
+ typedef struct strokecontext {
+ enum pentype { pt_circle, pt_square, pt_poly } pentype;
+ int cur, max;
+ StrokePoint *all;
++ struct extrapoly *ep;
++ int ecur, emax;
+ TPoint *tpt;
+ int tmax;
+ double resolution; /* take samples roughly this many em-units */ /* radius/16.0? */
+@@ -62,6 +77,10 @@
+ double radius2; /* Squared */
+ enum linejoin join; /* Only for circles */
+ enum linecap cap; /* Only for circles */
++ double miterlimit; /* Only for circles if join==lj_miter */
++ /* PostScript uses 1/sin( theta/2 ) as their miterlimit */
++ /* I use -cos(theta). (where theta is the angle between the slopes*/
++ /* same idea, different implementation */
+ int n; /* For polygon pens */
+ BasePoint *corners; /* Expressed as an offset from the center of the poly */ /* (Where center could mean center of bounding box, or average or all verteces) */
+ BasePoint *slopes; /* slope[0] is unitvector corners[1]-corners[0] */
+@@ -70,7 +89,7 @@
+ unsigned int open: 1; /* Original is an open contour */
+ unsigned int remove_inner: 1;
+ unsigned int remove_outer: 1;
+- /* unsigned int rotate_relative_to_direction: 1; /* Rotate the polygon pen so it maintains the same orientation with respect to the contour's slope */
++ /* unsigned int rotate_relative_to_direction: 1; */ /* Rotate the polygon pen so it maintains the same orientation with respect to the contour's slope */
+ /* Um, the above is essentially equivalent to a circular pen. No point in duplicating it */
+ unsigned int leave_users_center: 1; /* Don't move the pen so its center is at the origin */
+ unsigned int scaled_or_rotated: 1;
+@@ -79,6 +98,8 @@
+ real inverse[6];
+ } StrokeContext;
+
++static char *glyphname=NULL;
++
+ /* Basically the idea is we find the spline, and then at each point, project */
+ /* out normal to the current slope and find a point that is radius units away*/
+ /* Now that's all well and good but we've also got to handle linecaps and joins */
+@@ -91,6 +112,18 @@
+ /* and where there is a significant hidden area, and at certain places within*/
+ /* caps and joins */
+
++/* Butt line caps and bevel line joins cause problems because they are going */
++/* be inside (hidden) by a circle centered on the line end or joint. So we */
++/* can't do the hit test on these edges using any point on the contour which */
++/* is within radius of the joint. */
++/* Hmmm. That works for the edge itself, but if some other part of the contour*/
++/* approaches closely (within radius) to the non-existant area it will be */
++/* incorrectly hidden. BUG!!!!! */
++/* Square line caps and miter line joins have the opposite problem: They should*/
++/* hide more points than a circular pen will cover. So we can build up a list*/
++/* of the polygons which represent these extrusions (rectangle for the cap, */
++/* and triangle for the miter) and do a polygon hit test with those. */
++
+ /* OK, that's a circular pen. Now by scaling we can turn a circle into an */
+ /* elipse, and by rotating we can orient the main axis how we like */
+ /* (we actually scale the splines by a transform that turns the ellipse into */
+@@ -146,7 +179,7 @@
+ /* the pen (and testing that it wasn't concave). */
+ /* For a concave poly, the concavities are only relevant at the joins and caps*/
+ /* (otherwise the concavity will be filled as the pen moves) so we could */
+-/* simply use the smallest convex poly that contains the convex one, and just */
++/* simply use the smallest convex poly that contains the concave one, and just */
+ /* worry about the concavity at the caps and joins (and maybe in doing the hit*/
+ /* test) But I don't think there is much point in dealing with that, and there*/
+ /* are the same issues on describing the shape as before */
+@@ -169,6 +202,143 @@
+ len += 1.5*(len-distance);
+ return( len );
+ }
++
++enum hittest { ht_Outside, ht_Inside, ht_OnEdge };
++
++static enum hittest PolygonHitTest(BasePoint *poly,BasePoint *polyslopes, int n,BasePoint *test, double *distance) {
++ /* If the poly is drawn clockwise, then a point is inside the poly if it */
++ /* is on the right side of each edge */
++ /* A point lies on an edge if the dot product of: */
++ /* 1. the vector normal to the edge */
++ /* 2. the vector from either vertex to the point in question */
++ /* is 0 (and it is otherwise inside) */
++ /* Now, if we choose the normal vector which points right, then */
++ /* the dot product must be positive. */
++ /* Note we could modify this code to work with counter-clockwise*/
++ /* polies. Either all the dots must be positive, or all must be*/
++ /* negative */
++ /* Sigh. Rounding errors. dot may be off by a very small amount */
++ /* (the polyslopes need to be unit vectors for this test to work) */
++ int i, zero_cnt=0, outside=false;
++ double dx,dy, dot, bestd= 0;
++
++ for ( i=0; i<n; ++i ) {
++
++ dx = test->x - poly[i].x;
++ dy = test->y - poly[i].y;
++ dot = dx*polyslopes[i].y - dy*polyslopes[i].x;
++ if ( dot>=-0.001 && dot<=.001 )
++ ++zero_cnt;
++ else if ( dot<0 ) { /* It's on the left, so it can't be inside */
++ if ( distance==NULL )
++return( ht_Outside );
++ outside= true;
++ if ( bestd<-dot )
++ bestd = -dot;
++ }
++ }
++
++ if ( outside ) {
++ *distance = bestd;
++return( ht_Outside );
++ }
++
++ if ( distance!=NULL )
++ *distance = 0;
++ /* zero_cnt==1 => on edge, zero_cnt==2 => on a vertex (on edge), zero_cnt>2 is impossible on a nice poly */
++ if ( zero_cnt>0 ) {
++return( ht_OnEdge );
++ }
++
++return( ht_Inside );
++}
++
++/* Something is a valid polygonal pen if: */
++/* 1. It contains something (not a line, or a single point, something with area) */
++/* 2. It contains ONE contour */
++/* (Multiple contours can be dealt with as long as each contour follows */
++/* requirements 3-n. If we have multiple contours: Find the offset from */
++/* the center of each contour to the center of all the contours. Trace */
++/* each contour individually and then translate by this offset) */
++/* 3. All edges must be lines (no control points) */
++/* 4. No more than 255 corners (could extend this number, but why?) */
++/* 5. It must be drawn clockwise (not really an error, if found just invert, but important for later checks). */
++/* 6. It must be convex */
++/* 7. No extranious points on the edges */
++
++enum PolyType PolygonIsConvex(BasePoint *poly,int n, int *badpointindex) {
++ /* For each vertex: */
++ /* Remove that vertex from the polygon, and then test if the vertex is */
++ /* inside the resultant poly. If it is inside, then the polygon is not */
++ /* convex */
++ /* If all verteces are outside then we have a convex poly */
++ /* If one vertex is on an edge, then we have a poly with an unneeded vertex */
++ double nx,ny;
++ int i,j,ni;
++
++ if ( badpointindex!=NULL )
++ *badpointindex = -1;
++ if ( n<3 )
++return( Poly_TooFewPoints );
++ /* All the points might lie on one line. That wouldn't be a polygon */
++ nx = -(poly[1].y-poly[0].y);
++ ny = (poly[1].x-poly[0].x);
++ for ( i=2; i<n; ++i ) {
++ if ( (poly[i].x-poly[0].x)*ny - (poly[i].y-poly[0].y)*nx != 0 )
++ break;
++ }
++ if ( i==n )
++return( Poly_Line ); /* Colinear */
++ if ( n==3 ) {
++ /* Triangles are always convex */
++return( Poly_Convex );
++ }
++
++ for ( j=0; j<n; ++j ) {
++ /* Test to see if poly[j] is inside the polygon poly[0..j-1,j+1..n] */
++ /* Basically the hit test code above modified to ignore poly[j] */
++ int outside = 0, zero_cnt=0, sign=0;
++ double sx, sy, dx,dy, dot;
++
++ for ( i=0; ; ++i ) {
++ if ( i==j )
++ continue;
++ ni = i+1;
++ if ( ni==n ) ni=0;
++ if ( ni==j ) {
++ ++ni;
++ if ( ni==n )
++ ni=0; /* Can't be j, because it already was */
++ }
++
++ sx = poly[ni].x - poly[i].x;
++ sy = poly[ni].y - poly[i].y;
++ dx = poly[j ].x - poly[i].x;
++ dy = poly[j ].y - poly[i].y;
++ /* Only care about signs, so I don't need unit vectors */
++ dot = dx*sy - dy*sx;
++ if ( dot==0 )
++ ++zero_cnt;
++ else if ( sign==0 )
++ sign= dot;
++ else if ( (dot<0 && sign>0) || (dot>0 && sign<0)) {
++ outside = true;
++ break;
++ }
++ if ( ni==0 )
++ break;
++ }
++ if ( !outside ) {
++ if ( badpointindex!=NULL )
++ *badpointindex = j;
++ if ( zero_cnt>0 )
++return( Poly_PointOnEdge );
++ else
++return( Poly_Concave );
++ }
++ }
++return( Poly_Convex );
++}
+ /******************************************************************************/
+ /* ******************************* Circle Pen ******************************* */
+ /******************************************************************************/
+@@ -240,6 +410,27 @@
+ halfleft.y = base2.y + c->radius*done.slope.x;
+ halfright.x = base2.x + c->radius*done.slope.y;
+ halfright.y = base2.y - c->radius*done.slope.x;
++ {
++ struct extrapoly *ep;
++ if ( c->ecur>=c->emax )
++ c->ep = grealloc(c->ep,(c->emax+=40)*sizeof(struct extrapoly));
++ ep = &c->ep[c->ecur++];
++ ep->poly[0] = done.left;
++ ep->poly[1].x = done.left.x + c->radius*slope.x;
++ ep->poly[1].y = done.left.y + c->radius*slope.y;
++ ep->poly[2].x = done.right.x + c->radius*slope.x;
++ ep->poly[2].y = done.right.y + c->radius*slope.y;
++ ep->poly[3] = done.right;
++ if ( !isend ) {
++ BasePoint temp;
++ ep->poly[0] = done.right;
++ temp = ep->poly[1];
++ ep->poly[1] = ep->poly[2];
++ ep->poly[2] = temp;
++ ep->poly[3] = done.left;
++ }
++ ep->ptcnt = 4;
++ }
+ for ( i=start; ; i+=incr ) {
+ p = &c->all[c->cur++];
+ p->sp = done.sp;
+@@ -306,7 +497,8 @@
+ StrokePoint *p, *pp;
+ int pindex;
+ int cnt, cnt1, i, was_neg;
+- /* atbreak means that we are dealing with a close contour, and we have */
++ int force_bevel;
++ /* atbreak means that we are dealing with a closed contour, and we have*/
+ /* reached the "end" of the contour (which is only the end because we */
+ /* had to start somewhere), so the next point on the contour is the */
+ /* start (index 0), as opposed to (index+1) */
+@@ -331,6 +523,8 @@
+ dot = (nslope.x*pslope.x + nslope.y*pslope.y);
+ if ( dot>=.999 )
+ return; /* Essentially colinear */ /* Won't be perfect because control points lie on integers */
++ /* miterlimit of 6, 18 degrees */
++ force_bevel = ( c->join==lj_miter && dot<c->miterlimit );
+
+ cnt = ceil(c->radius/c->resolution);
+ if ( cnt<6 ) cnt = 6;
+@@ -353,7 +547,7 @@
+ else
+ bends_left = false; /* So it bends right */
+
+- if ( c->join==lj_bevel ) {
++ if ( c->join==lj_bevel || force_bevel ) {
+ /* This is easy, a line between the two end points */
+ if ( bends_left ) {
+ /* If it bends left, then the joint is on the right */
+@@ -402,6 +596,20 @@
+ if ( !IntersectLinesSlopes(&inter,&base,&c->all[pindex].slope,
+ &final,&done.slope))
+ inter = base;
++ {
++ struct extrapoly *ep;
++ if ( c->ecur>=c->emax )
++ c->ep = grealloc(c->ep,(c->emax+=40)*sizeof(struct extrapoly));
++ ep = &c->ep[c->ecur++];
++ ep->poly[0] = base;
++ ep->poly[1] = inter;
++ ep->poly[2] = final;
++ if ( bends_left ) {
++ ep->poly[0] = final;
++ ep->poly[2] = base;
++ }
++ ep->ptcnt = 3;
++ }
+ curslope.x = inter.x - base.x;
+ curslope.y = inter.y - base.y;
+ len = sqrt(curslope.x*curslope.x + curslope.y*curslope.y);
+@@ -510,8 +718,12 @@
+ else
+ p->left = temp;
+ if ( rot.x<=0 && !was_neg ) {
+- was_neg = true;
++ was_neg = c->cur-1;
+ p->needs_point_left = p->needs_point_right = true;
++ if ( diff_angle.y>.1 ) {
++ incr_angle.y = diff_angle.y/20;
++ incr_angle.x = sqrt(1-incr_angle.y*incr_angle.y);
++ }
+ }
+ temp.x = rot.x*incr_angle.x - rot.y*incr_angle.y;
+ temp.y = rot.x*incr_angle.y + rot.y*incr_angle.x;
+@@ -525,6 +737,8 @@
+ rot = temp;
+ }
+ }
++ if ( was_neg!=0 && c->cur-was_neg<5 )
++ c->all[was_neg].needs_point_left = c->all[was_neg].needs_point_right = false;
+ }
+ if ( !atbreak )
+ c->all[c->cur++] = done;
+@@ -645,6 +859,32 @@
+ }
+ }
+ }
++
++ /* now see if any miter join polygons (or square cap polys) cover anything */
++ for ( j=0; j<c->ecur; ++j ) {
++ BasePoint slopes[4];
++ double len;
++ struct extrapoly *ep = &c->ep[j];
++ for ( i=0; i<ep->ptcnt; ++i ) {
++ int ni = i+1;
++ if ( ni==ep->ptcnt ) ni=0;
++ slopes[i].x = ep->poly[ni].x - ep->poly[i].x;
++ slopes[i].y = ep->poly[ni].y - ep->poly[i].y;
++ len = sqrt(slopes[i].x*slopes[i].x + slopes[i].y*slopes[i].y);
++ if ( len==0 )
++return;
++ slopes[i].x /= len; slopes[i].y /= len;
++ }
++ for ( i=c->cur-1; i>=0 ; --i ) {
++ StrokePoint *p = &c->all[i];
++ if ( !p->left_hidden )
++ if ( PolygonHitTest(ep->poly,slopes,ep->ptcnt,&p->left,NULL)==ht_Inside )
++ p->left_hidden = true;
++ if ( !p->right_hidden )
++ if ( PolygonHitTest(ep->poly,slopes,ep->ptcnt,&p->right,NULL)==ht_Inside )
++ p->right_hidden = true;
++ }
++ }
+ }
+
+ static void FindStrokePointsCircle(SplineSet *ss, StrokeContext *c) {
+@@ -704,7 +944,7 @@
+ /* just in case... add an on curve point every time the sample's slopes */
+ /* move through 90 degrees. (We only do this for circles because for */
+ /* squares and polygons this will happen automatically whenever we change */
+- /* polygon/squar vertices, which is close enough to the same idea as no */
++ /* polygon/square vertices, which is close enough to the same idea as no */
+ /* matter) */
+ { int j,k, skip=10/c->resolution;
+ for ( i=c->cur-1; i>=0; ) {
+@@ -1189,143 +1429,6 @@
+ /* ****************************** Polygon Pen ******************************* */
+ /******************************************************************************/
+
+-/* Something is a valid polygonal pen if: */
+-/* 1. It contains something (not a line, or a single point, something with area) */
+-/* 2. It contains ONE contour */
+-/* (Multiple contours can be dealt with as long as each contour follows */
+-/* requirements 3-n. If we have multiple contours: Find the offset from */
+-/* the center of each contour to the center of all the contours. Trace */
+-/* each contour individually and then translate by this offset) */
+-/* 3. All edges must be lines (no control points) */
+-/* 4. No more than 255 corners (could extend this number, but why?) */
+-/* 5. It must be drawn clockwise (not really an error, if found just invert, but important for later checks). */
+-/* 6. It must be convex */
+-/* 7. No extranious points on the edges */
+-
+-enum hittest { ht_Outside, ht_Inside, ht_OnEdge };
+-
+-static enum hittest PolygonHitTest(BasePoint *poly,BasePoint *polyslopes, int n,BasePoint *test, double *distance) {
+- /* If the poly is drawn clockwise, then a point is inside the poly if it */
+- /* is on the right side of each edge */
+- /* A point lies on an edge if the dot product of: */
+- /* 1. the vector normal to the edge */
+- /* 2. the vector from either vertex to the point in question */
+- /* is 0 (and it is otherwise inside) */
+- /* Now, if we choose the normal vector which points right, then */
+- /* the dot product must be positive. */
+- /* Note we could modify this code to work with counter-clockwise*/
+- /* polies. Either all the dots must be positive, or all must be*/
+- /* negative */
+- /* Sigh. Rounding errors. dot may be off by a very small amount */
+- /* (the polyslopes need to be unit vectors for this test to work) */
+- int i, zero_cnt=0, outside=false;
+- double dx,dy, dot, bestd= 0;
+-
+- for ( i=0; i<n; ++i ) {
+-
+- dx = test->x - poly[i].x;
+- dy = test->y - poly[i].y;
+- dot = dx*polyslopes[i].y - dy*polyslopes[i].x;
+- if ( dot>=-0.001 && dot<=.001 )
+- ++zero_cnt;
+- else if ( dot<0 ) { /* It's on the left, so it can't be inside */
+- if ( distance==NULL )
+-return( ht_Outside );
+- outside= true;
+- if ( bestd<-dot )
+- bestd = -dot;
+- }
+- }
+-
+- if ( outside ) {
+- *distance = bestd;
+-return( ht_Outside );
+- }
+-
+- if ( distance!=NULL )
+- *distance = 0;
+- /* zero_cnt==1 => on edge, zero_cnt==2 => on a vertex (on edge), zero_cnt>2 is impossible on a nice poly */
+- if ( zero_cnt>0 ) {
+-return( ht_OnEdge );
+- }
+-
+-return( ht_Inside );
+-}
+-
+-enum PolyType PolygonIsConvex(BasePoint *poly,int n, int *badpointindex) {
+- /* For each vertex: */
+- /* Remove that vertex from the polygon, and then test if the vertex is */
+- /* inside the resultant poly. If it is inside, then the polygon is not */
+- /* convex */
+- /* If all verteces are outside then we have a convex poly */
+- /* If one vertex is on an edge, then we have a poly with an unneeded vertex */
+- double nx,ny;
+- int i,j,ni;
+-
+- if ( badpointindex!=NULL )
+- *badpointindex = -1;
+- if ( n<3 )
+-return( Poly_TooFewPoints );
+- /* All the points might lie on one line. That wouldn't be a polygon */
+- nx = -(poly[1].y-poly[0].y);
+- ny = (poly[1].x-poly[0].x);
+- for ( i=2; i<n; ++i ) {
+- if ( (poly[i].x-poly[0].x)*nx + (poly[i].y-poly[0].y)*ny != 0 )
+- break;
+- }
+- if ( i==n )
+-return( Poly_Line ); /* Colinear */
+- if ( n==3 ) {
+- /* Triangles are always convex */
+-return( Poly_Convex );
+- }
+-
+- for ( j=0; j<n; ++j ) {
+- /* Test to see if poly[j] is inside the polygon poly[0..j-1,j+1..n] */
+- /* Basically the hit test code above modified to ignore poly[j] */
+- int outside = 0, zero_cnt=0, sign=0;
+- double sx, sy, dx,dy, dot;
+-
+- for ( i=0; ; ++i ) {
+- if ( i==j )
+- continue;
+- ni = i+1;
+- if ( ni==n ) ni=0;
+- if ( ni==j ) {
+- ++ni;
+- if ( ni==n )
+- ni=0; /* Can't be j, because it already was */
+- }
+-
+- sx = poly[ni].x - poly[i].x;
+- sy = poly[ni].y - poly[i].y;
+- dx = poly[j ].x - poly[i].x;
+- dy = poly[j ].y - poly[i].y;
+- /* Only care about signs, so I don't need unit vectors */
+- dot = dx*sy - dy*sx;
+- if ( dot==0 )
+- ++zero_cnt;
+- else if ( sign==0 )
+- sign= dot;
+- else if ( (dot<0 && sign>0) || (dot>0 && sign<0)) {
+- outside = true;
+- break;
+- }
+- if ( ni==0 )
+- break;
+- }
+- if ( !outside ) {
+- if ( badpointindex!=NULL )
+- *badpointindex = j;
+- if ( zero_cnt>0 )
+-return( Poly_PointOnEdge );
+- else
+-return( Poly_Concave );
+- }
+- }
+-return( Poly_Convex );
+-}
+-
+ static int WhichPolyCorner(StrokeContext *c, BasePoint *slope, int *right_trace) {
+ /* The corner we are interested in is the corner whose normal distance */
+ /* from the slope is the greatest. */
+@@ -2424,18 +2527,23 @@
+ if ( startslope.x!=0 || startslope.y!=0 )
+ ret->noprevcp = false;
+ if ( !*newcontour ) {
+- ret->nextcp.x += posslope.x;
+- ret->nextcp.y += posslope.y;
+- if ( posslope.x!=0 || posslope.y!=0 )
+- ret->nonextcp = false;
+ /* the same point will often appear at the end of one spline and the */
+ /* start of the next */
+ /* Or a joint may add a lot of points to the other side which show up */
+ /* hidden on this side */
++ int opos = pos;
+ while ( pos+1<c->cur &&
+ ((ret->me.x==c->all[pos+1].right.x && ret->me.y==c->all[pos+1].right.y ) ||
+ c->all[pos+1].right_hidden))
+ ++pos;
++ if ( opos!=pos ) {
++ RightSlopeAtPos(c,pos,false,&posslope);
++ ret->pointtype = pt_corner;
++ }
++ ret->nextcp.x += posslope.x;
++ ret->nextcp.y += posslope.y;
++ if ( posslope.x!=0 || posslope.y!=0 )
++ ret->nonextcp = false;
+ len2 = (ret->me.x-c->all[pos].right.x)*(ret->me.x-c->all[pos].right.x) + (ret->me.y-c->all[pos].right.y)*(ret->me.y-c->all[pos].right.y);
+ if ( len2>=res_bound )
+ *newcontour = true;
+@@ -2704,7 +2812,7 @@
+
+ SplinePointFree(other);
+ }
+-
++
+ static SplineSet *JoinFragments(SplineSet *fragments,SplineSet **contours,
+ double resolution) {
+ double res2 = resolution*resolution;
+@@ -3212,6 +3320,133 @@
+
+ #define MAX_TPOINTS 40
+
++static int InterpolateTPoints(StrokeContext *c,int start_pos,int end_pos,
++ int isleft) {
++ /* We have a short segment of the contour here. So short that there are */
++ /* very few points StrokePoints on it. If we've only got 1 StrokePoint */
++ /* we tend to get singular matrices. 2 StrokePoints just gives a bad */
++ /* approximation (or might), etc. */
++ /* But we have the original spline. We can add as many points between */
++ /* start and end as we like */
++ double start_t, end_t, t, diff_t;
++ double start_x, end_x, x, diff_x, start_y, end_y, y, diff_y, r2;
++ BasePoint slope, me;
++ Spline *s;
++ int lt,rt;
++ int i,j;
++ double len;
++
++ if ( start_pos==0 )
++return( end_pos-start_pos );
++
++ if ( 20 >= c->tmax )
++ c->tpt = grealloc(c->tpt,(c->tmax = 20+MAX_TPOINTS)*sizeof(TPoint));
++
++ if ( c->all[start_pos].line ) {
++ me = c->all[start_pos-1].me;
++ if ( isleft ) {
++ slope.x = (c->all[end_pos].left.x - me.x)/6;
++ slope.y = (c->all[end_pos].left.y - me.y)/6;
++ } else {
++ slope.x = (c->all[end_pos].right.x - me.x)/6;
++ slope.y = (c->all[end_pos].right.y - me.y)/6;
++ }
++ for ( i=0; i<5; ++i ) {
++ c->tpt[i].x = me.x + slope.x*(i+1);
++ c->tpt[i].x = me.y + slope.y*(i+1);
++ c->tpt[i].t = (i+1)/6.0;
++ }
++return( 5 );
++ } else if ( c->all[start_pos].circle ) {
++ me = c->all[start_pos].me; /* Center */
++ if ( isleft ) {
++ start_x = c->all[start_pos-1].left.x - me.x;
++ end_x = c->all[end_pos].left.x - me.x;
++ start_y = c->all[start_pos-1].left.y - me.y;
++ end_y = c->all[end_pos].left.y - me.y;
++ } else {
++ start_x = c->all[start_pos-1].right.x - me.x;
++ end_x = c->all[end_pos].right.x - me.x;
++ start_y = c->all[start_pos-1].right.y - me.y;
++ end_y = c->all[end_pos].right.y - me.y;
++ }
++ if ( (diff_x = end_x-start_x)<0 ) diff_x = -diff_x;
++ if ( (diff_y = end_y-start_y)<0 ) diff_y = -diff_y;
++ /* By choosing the bigger difference, I insure the other coord will */
++ /* not cross over from negative to positive. Actually this is only */
++ /* true for small segments of the circle. But that's what we've got*/
++ r2 = c->radius*c->radius;
++ if ( diff_y>diff_x ) {
++ diff_y = (end_y-start_y)/11.0;
++ for ( y=start_y+diff_y, i=0; i<10; ++i, y+=diff_y ) {
++ x = sqrt( r2-y*y );
++ if ( start_x<0 ) x=-x;
++ c->tpt[i].x = me.x + x;
++ c->tpt[i].y = me.y + y;
++ c->tpt[i].t = (i+1)/11.0;
++ }
++ } else {
++ diff_x = (end_x-start_x)/11.0;
++ for ( x=start_x+diff_x, i=0; i<10; ++i, x+=diff_x ) {
++ y = sqrt( r2-x*x );
++ if ( start_y<0 ) y=-y;
++ c->tpt[i].x = me.x + x;
++ c->tpt[i].y = me.y + y;
++ c->tpt[i].t = (i+1)/11.0;
++ }
++ }
++return( 10 );
++ }
++
++ if ( c->all[start_pos-1].t == c->all[end_pos].t ||
++ c->all[start_pos-1].sp!=c->all[end_pos].sp ||
++ ( isleft && c->all[start_pos-1].lt!=c->all[end_pos].lt) ||
++ (!isleft && c->all[start_pos-1].rt!=c->all[end_pos].rt))
++return( end_pos-start_pos ); /* Well, nothing we can do here */
++
++ start_t = c->all[start_pos-1].t; end_t = c->all[end_pos].t;
++ diff_t = (end_t-start_t)/11;
++ s = c->all[start_pos].sp;
++ lt = c->all[start_pos].lt; rt = c->all[start_pos].rt;
++ for ( t=start_t+diff_t, j=i=0; i<10; ++i, t+=diff_t ) {
++ me.x = ((s->splines[0].a*t+s->splines[0].b)*t+s->splines[0].c)*t+s->splines[0].d;
++ me.y = ((s->splines[1].a*t+s->splines[1].b)*t+s->splines[1].c)*t+s->splines[1].d;
++ slope.x = (3*s->splines[0].a*t+2*s->splines[0].b)*t+s->splines[0].c;
++ slope.y = (3*s->splines[1].a*t+2*s->splines[1].b)*t+s->splines[1].c;
++ len = slope.x*slope.x + slope.y*slope.y;
++ if ( len==0 && c->pentype==pt_circle )
++ continue;
++ len = sqrt(len);
++ slope.x /= len; slope.y /= len;
++ if ( isleft ) {
++ if ( c->pentype==pt_circle ) {
++ c->tpt[j].x = me.x - c->radius*slope.y;
++ c->tpt[j].y = me.y + c->radius*slope.x;
++ } else if ( c->pentype==pt_square ) {
++ c->tpt[j].x = me.x + c->radius*SquareCorners[lt].x;
++ c->tpt[j].y = me.y + c->radius*SquareCorners[lt].y;
++ } else {
++ c->tpt[j].x = me.x + c->corners[lt].x;
++ c->tpt[j].y = me.y + c->corners[lt].y;
++ }
++ c->tpt[j++].t = (i+1)/11.0;
++ } else {
++ if ( c->pentype==pt_circle ) {
++ c->tpt[j].x = me.x + c->radius*slope.y;
++ c->tpt[j].y = me.y - c->radius*slope.x;
++ } else if ( c->pentype==pt_square ) {
++ c->tpt[j].x = me.x + c->radius*SquareCorners[rt].x;
++ c->tpt[j].y = me.y + c->radius*SquareCorners[rt].y;
++ } else {
++ c->tpt[j].x = me.x + c->corners[rt].x;
++ c->tpt[j].y = me.y + c->corners[rt].y;
++ }
++ c->tpt[j++].t = (i+1)/11.0;
++ }
++ }
++return( j );
++}
++
+ static SplineSet *ApproximateStrokeContours(StrokeContext *c) {
+ int end_pos, i, start_pos=0, pos, ipos;
+ SplinePoint *first=NULL, *last=NULL, *cur;
+@@ -3281,7 +3516,7 @@
+ StrokePoint *spt = c->all+ipos;
+ tpt->x = spt->left.x;
+ tpt->y = spt->left.y;
+- tpt->t = (ipos-start_pos)/ (double) (end_pos-start_pos+1);
++ tpt->t = (ipos-start_pos+1)/ (double) (end_pos-start_pos+1);
+ ipos += jump;
+ if ( ++skip_cnt>skip && extras>0 ) {
+ ++ipos;
+@@ -3291,9 +3526,11 @@
+ if ( ipos>end_pos )
+ ipos = end_pos;
+ }
+- if ( end_pos!=start_pos )
++ if ( end_pos<start_pos+3 )
++ tot = InterpolateTPoints(c,start_pos,end_pos,true);
++ if ( end_pos!=start_pos ) {
+ ApproximateSplineFromPointsSlopes(last,cur,c->tpt,tot,false);
+- else
++ } else
+ SplineMake3(last,cur);
+ last = cur;
+ if ( pos<end_pos ) {
+@@ -3357,7 +3594,7 @@
+ StrokePoint *spt = c->all+ipos;
+ tpt->x = spt->right.x;
+ tpt->y = spt->right.y;
+- tpt->t = (ipos-start_pos)/ (double) (end_pos-start_pos+1);
++ tpt->t = (ipos-start_pos+1)/ (double) (end_pos-start_pos+1);
+ ipos += jump;
+ if ( ++skip_cnt>skip && extras>0 ) {
+ ++ipos;
+@@ -3367,9 +3604,11 @@
+ if ( ipos>end_pos )
+ ipos = end_pos;
+ }
+- if ( end_pos!=start_pos )
++ if ( end_pos<start_pos+3 )
++ tot = InterpolateTPoints(c,start_pos,end_pos,false);
++ if ( end_pos!=start_pos ) {
+ ApproximateSplineFromPointsSlopes(last,cur,c->tpt,tot,false);
+- else
++ } else
+ SplineMake3(last,cur);
+ last = cur;
+ if ( last->next!=NULL ) last=last->next->to;
+@@ -3417,7 +3656,7 @@
+ lfragments = EdgeEffects(lfragments,c);
+ lfragments=JoinFragments(lfragments,&contours,c->resolution);
+ if ( lfragments!=NULL ) {
+- IError("Some fragments did not join");
++ IError(glyphname==NULL?_("Some fragments did not join"):_("Some fragments did not join in %s"),glyphname);
+ for ( ret=lfragments; ret->next!=NULL; ret=ret->next );
+ ret->next = contours;
+ contours = lfragments;
+@@ -3444,6 +3683,7 @@
+ if ( c->cur!=0 )
+ memset(c->all,0,c->cur*sizeof(StrokePoint));
+ c->cur = 0;
++ c->ecur = 0;
+ c->open = base->first->prev==NULL;
+ switch ( c->pentype ) {
+ case pt_circle:
+@@ -3508,6 +3748,7 @@
+ pt_poly;
+ c.join = si->join;
+ c.cap = si->cap;
++ c.miterlimit = /* -cos(theta) */ -.98 /* theta=~11 degrees, PS miterlimit=10 */;
+ c.radius = si->radius;
+ c.radius2 = si->radius*si->radius;
+ c.remove_inner = si->removeinternal;
+@@ -3652,6 +3893,7 @@
+ if ( (gid=fv->map->map[i])!=-1 && (sc = fv->sf->glyphs[gid])!=NULL &&
+ !sc->ticked && fv->selected[i] ) {
+ sc->ticked = true;
++ glyphname = sc->name;
+ if ( sc->parent->multilayer ) {
+ SCPreserveState(sc,false);
+ for ( layer = ly_fore; layer<sc->layer_cnt; ++layer ) {
+@@ -3671,5 +3913,6 @@
+ break;
+ }
+ }
++ glyphname = NULL;
+ ff_progress_end_indicator();
+ }
+diff -aur fontforge-20100501/fontforge/splineutil2.c fontforge-SVN-20100929/fontforge/splineutil2.c
+--- fontforge-20100501/fontforge/splineutil2.c 2010-04-29 05:53:22.000000000 +0200
++++ fontforge-SVN-20100929/fontforge/splineutil2.c 2010-09-14 22:08:14.000000000 +0200
+@@ -505,7 +505,7 @@
+ }
+
+ /* Find a spline which best approximates the list of intermediate points we */
+-/* are given. No attempt is made to fix the slopes */
++/* are given. No attempt is made to use fixed slope angles */
+ /* given a set of points (x,y,t) */
+ /* find the bezier spline which best fits those points */
+
+@@ -599,6 +599,56 @@
+ }
+ }
+
++#if 0
++ /* if we look at (p(t)-pi) = (a*t^3+b*t^2+c*t+d)-pi */
++ /* d = p0, a = (p1-p0-b-c) */
++ /* We find another set of equations we can minimize. */
++ /* As might be expected it has exactly the same singularities */
++ /* Just a linear transform, after all. But I worked through it hoping... */
++ if ( order2 ) {
++ } else {
++ /* Try a different approach */
++ double xconst[2], yconst[2], b_term[2], c_term[2] /* Same for x and y */;
++ double determinant;
++ BasePoint off;
++ xconst[0] = xconst[1] = yconst[0] = yconst[1] =
++ b_term[0] = b_term[1] = c_term[0] = c_term[1] = 0;
++ off.x = to->me.x - from->me.x; off.y = to->me.y-from->me.y;
++ for ( i=0; i<cnt; ++i ) {
++ double t = mid[i].t, t2 = t*t, t3=t*t2;
++ double bfactor = t2-t3, cfactor=t-t3, bc = bfactor*cfactor;
++
++ b_term[0] += bfactor*bfactor;
++ b_term[1] += bc;
++ /*c_term[0] += bc;*/ /* Same as b_term[1]; */
++ c_term[1] += cfactor*cfactor;
++ xconst[0] += (off.x*t3+from->me.x-mid[i].x)*bfactor;
++ xconst[1] += (off.x*t3+from->me.x-mid[i].x)*cfactor;
++ yconst[0] += (off.y*t3+from->me.y-mid[i].y)*bfactor;
++ yconst[1] += (off.y*t3+from->me.y-mid[i].y)*cfactor;
++ }
++ c_term[0] = b_term[1];
++ determinant = b_term[1]*c_term[0] - b_term[0]*c_term[1];
++ if ( determinant!=0 ) {
++ double bx, by, cx, cy;
++ cx = -(xconst[0]*b_term[1] - xconst[1]*b_term[0])/determinant;
++ cy = -(yconst[0]*b_term[1] - yconst[1]*b_term[0])/determinant;
++ if ( b_term[0]!=0 ) {
++ bx = -(xconst[0]+c_term[0]*cx)/b_term[0];
++ by = -(yconst[0]+c_term[0]*cy)/b_term[0];
++ } else {
++ bx = -(xconst[1]+c_term[1]*cx)/b_term[1];
++ by = -(yconst[1]+c_term[1]*cy)/b_term[1];
++ }
++ from->nextcp.x = from->me.x + cx/3;
++ from->nextcp.y = from->me.y + cy/3;
++ to->prevcp.x = from->nextcp.x + (bx+cx)/3;
++ to->prevcp.y = from->nextcp.y + (by+cy)/3;
++return( SplineMake3(from,to));
++ }
++ }
++#endif
++
+ if ( (spline = IsLinearApprox(from,to,mid,cnt,order2))!=NULL )
+ return( spline );
+
+@@ -799,21 +849,21 @@
+ /* p(t) = pf + [ 3*rf*Δf ]*t + 3*[pt-pf+rt*Δt-2*rf*Δf] *t^2 + */
+ /* [2*pf-2*pt+3*rf*Δf-3*rt*Δt]*t^3 */
+
+-/* So I want
++/* So I want */
+ /* d Σ (p(t(i))-p(i))^2/ d rf == 0 */
+ /* d Σ (p(t(i))-p(i))^2/ d rt == 0 */
+ /* now... */
+ /* d Σ (p(t(i))-p(i))^2/ d rf == 0 */
+ /* => Σ 3*t*Δf*(1-2*t+t^2)*
+-/* [pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3] +
+-/* 3*[t - 2*t^2 + t^3]*Δf*rf +
+-/* 3*[t^2-t^3]*Δt*rt */
++ * [pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3] +
++ * 3*[t - 2*t^2 + t^3]*Δf*rf +
++ * 3*[t^2-t^3]*Δt*rt */
+ /* and... */
+ /* d Σ (p(t(i))-p(i))^2/ d rt == 0 */
+ /* => Σ 3*t^2*Δt*(1-t)*
+-* [pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3] +
+-/* 3*[t - 2*t^2 + t^3]*Δf*rf +
+-/* 3*[t^2-t^3]*Δt*rt */
++ * [pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3] +
++ * 3*[t - 2*t^2 + t^3]*Δf*rf +
++ * 3*[t^2-t^3]*Δt*rt */
+
+ /* Now for a long time I looked at that and saw four equations and two unknowns*/
+ /* That was I was trying to solve for x and y separately, and that doesn't work. */
+@@ -852,6 +902,7 @@
+ double offn_, offp_, finaldiff;
+ double pt_pf_x, pt_pf_y, determinant;
+ double consts[2], rt_terms[2], rf_terms[2];
++ double rfbad=0, rtbad=0;
+
+ /* If all the selected points are at the same spot, and one of the */
+ /* end-points is also at that spot, then just copy the control point */
+@@ -1027,6 +1078,8 @@
+ rt_terms[1] += factor_to*( -tounit.x*rt_term_x + -tounit.y*rt_term_y);
+ }
+
++ /* I've only seen singular matrices (determinant==0) when cnt==1 */
++ /* but even with cnt==1 the determinant is usually non-0 (16 times out of 17)*/
+ determinant = (rt_terms[0]*rf_terms[1]-rt_terms[1]*rf_terms[0]);
+ if ( determinant!=0 ) {
+ double rt, rf;
+@@ -1035,6 +1088,16 @@
+ rf = -(consts[0]+rt*rt_terms[0])/rf_terms[0];
+ else /* if ( rf_terms[1]!=0 ) This can't happen, otherwise the determinant would be 0 */
+ rf = -(consts[1]+rt*rt_terms[1])/rf_terms[1];
++ /* If we get bad values (ones that point diametrically opposed to what*/
++ /* we need), then fix that factor at 0, and see what we get for the */
++ /* other */
++ if ( rf>=0 && rt>0 && rf_terms[0]!=0 &&
++ (rf = -consts[0]/rf_terms[0])>0 ) {
++ rt = 0;
++ } else if ( rf<0 && rt<=0 && rt_terms[1]!=0 &&
++ (rt = -consts[1]/rt_terms[1])<0 ) {
++ rf = 0;
++ }
+ if ( rt<=0 && rf>=0 ) {
+ from->nextcp.x = from->me.x + rf*fromunit.x;
+ from->nextcp.y = from->me.y + rf*fromunit.y;
+@@ -1044,7 +1107,12 @@
+ to->noprevcp = rt==0;
+ return( SplineMake3(from,to));
+ }
+- }
++
++ rfbad = rf; rtbad = -rt;
++ } else
++ rfbad = rtbad = -2;
++
++
+
+ trylen = (to->me.x-from->me.x)*fromunit.x + (to->me.y-from->me.y)*fromunit.y;
+ if ( trylen>flen ) flen = trylen;
+@@ -2101,6 +2169,7 @@
+ return( top/(dxdt*dxdt) );
+ }
+
++
+ /* Does the second derivative change sign around this point? If so we should */
+ /* retain it for truetype */
+ static int SPisD2Change( SplinePoint *sp ) {
+@@ -3415,8 +3484,10 @@
+ s->to->prevcp = s->to->me;
+ } else {
+ s->from->nonextcp = true;
+- s->from->nextcp = s->to->me;
++ s->from->nextcp = s->from->me;
+ }
++ end->pointtype = pt_corner;
++ SplineRefigure(s);
+ return( true ); /* We changed the slope */
+ }
+ unitslope.x /= len; unitslope.y /= len;
+@@ -3435,12 +3506,14 @@
+ s->from->nextcp.x = s->from->me.x + mydot*unitslope.x;
+ s->from->nextcp.y = s->from->me.y + mydot*unitslope.y;
+ }
++ SplineRefigure(s);
+ return( true ); /* We changed the slope */
+ }
+
+ if ( (xdiff = cp->x - end->me.x)<0 ) xdiff = -xdiff;
+ if ( (ydiff = cp->y - end->me.y)<0 ) ydiff = -ydiff;
+
++ to = *cp;
+ if ( xdiff<ydiff/10.0 && xdiff>0 ) {
+ to.x = end->me.x;
+ end->pointtype = pt_corner;
More information about the arch-commits
mailing list