Permalink
Fetching contributors…
Cannot retrieve contributors at this time
189 lines (165 sloc) 5.57 KB
/*
Copyright: 2007 Raph Levien
License: GPL-2+
bezctx_ps.c - ppedit - A pattern plate editor for Spiro splines.
Copyright: 2007 George Williams
bezctx_ff.c - Provide a gateway into FontForge with added modification.
Contributions: Yuri Chornoivan, Jonathan Hanna, Joe Da Silva, Reuben Thomas,
Frank Trampe
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include <basics.h>
#include <stdio.h>
#include "splineutil.h"
#ifndef _NO_LIBSPIRO
#include "bezctx_ff.h"
#include "fontforgevw.h" /* For LogError, else splinefont.h */
#ifdef HAVE_IEEEFP_H
# include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
#endif
#include <math.h>
typedef struct {
bezctx base; /* This is a superclass of bezctx, and this is the entry for the base */
int is_open;
int gotnans; /* Sometimes spiro fails to converge and we get NaNs. */
/* Complain the first time this happens, but not thereafter */
SplineSet *ss; /* The fontforge contour which we build up as we go along */
} bezctx_ff;
static void
nancheck(bezctx_ff *bc) {
if ( !bc->gotnans ) { /* Called when we get passed a NaN. Complain the first time that happens */
LogError(_("Spiros did not converge") );
bc->gotnans = true;
}
}
/* This routine starts a new contour */
/* So we allocate a new SplineSet, and then add the first point to it */
static void bezctx_ff_moveto(bezctx *z, double x, double y, int is_open) {
bezctx_ff *bc = (bezctx_ff *)z;
if ( !isfinite(x) || !isfinite(y)) { /* Protection against NaNs */
nancheck(bc);
x = y = 0;
}
if (!bc->is_open) {
SplineSet *ss;
if ( (ss=(SplineSet *)calloc(1,sizeof(SplineSet)))==NULL )
return;
ss->next = bc->ss;
bc->ss = ss;
}
bc->ss->first = bc->ss->last = SplinePointCreate(x,y);
bc->ss->start_offset = 0;
bc->is_open = is_open;
}
/* This routine creates a linear spline from the previous point specified to this one */
static void bezctx_ff_lineto(bezctx *z, double x, double y) {
bezctx_ff *bc = (bezctx_ff *)z;
SplinePoint *sp;
if ( !isfinite(x) || !isfinite(y)) {
nancheck(bc);
x = y = 0;
}
sp = SplinePointCreate(x,y);
if ( sp!=NULL && SplineMake3(bc->ss->last,sp)!=NULL )
bc->ss->last = sp;
}
/* This could create a quadratic spline, except FontForge only is prepared */
/* to deal with cubics, so convert the quadratic into the equivalent cubic */
static void
bezctx_ff_quadto(bezctx *z, double xm, double ym, double x3, double y3) {
bezctx_ff *bc = (bezctx_ff *)z;
double x0, y0;
double x1, y1;
double x2, y2;
SplinePoint *sp;
if ( !isfinite(xm) || !isfinite(ym) || !isfinite(x3) || !isfinite(y3)) {
nancheck(bc);
xm = ym = x3 = y3 = 0;
}
if ( (sp=SplinePointCreate(x3,y3))!=NULL ) {
x0 = bc->ss->last->me.x;
y0 = bc->ss->last->me.y;
x1 = xm + (1./3) * (x0 - xm);
y1 = ym + (1./3) * (y0 - ym);
x2 = xm + (1./3) * (x3 - xm);
y2 = ym + (1./3) * (y3 - ym);
bc->ss->last->nextcp.x = x1;
bc->ss->last->nextcp.y = y1;
bc->ss->last->nonextcp = false;
sp->prevcp.x = x2;
sp->prevcp.y = y2;
sp->noprevcp = false;
if ( SplineMake3(bc->ss->last,sp)!=NULL )
bc->ss->last = sp;
}
}
/* And this creates a cubic */
static void
bezctx_ff_curveto(bezctx *z, double x1, double y1, double x2, double y2,
double x3, double y3) {
bezctx_ff *bc = (bezctx_ff *)z;
SplinePoint *sp;
if ( !isfinite(x1) || !isfinite(y1) || !isfinite(x2) || !isfinite(y2) || !isfinite(x3) || !isfinite(y3)) {
nancheck(bc);
x1 = y1 = x2 = y2 = x3 = y3 = 0;
}
if ( (sp=SplinePointCreate(x3,y3))!=NULL ) {
bc->ss->last->nextcp.x = x1;
bc->ss->last->nextcp.y = y1;
bc->ss->last->nonextcp = false;
sp->prevcp.x = x2;
sp->prevcp.y = y2;
sp->noprevcp = false;
if ( SplineMake3(bc->ss->last,sp)!=NULL )
bc->ss->last = sp;
}
}
/* Allocates and initializes a new FontForge bezier context */
bezctx *new_bezctx_ff(void) {
bezctx_ff *result;
if ( (result=(bezctx_ff *)calloc(1,sizeof(bezctx_ff)))==NULL )
return NULL;
result->base.moveto = bezctx_ff_moveto;
result->base.lineto = bezctx_ff_lineto;
result->base.quadto = bezctx_ff_quadto;
result->base.curveto = bezctx_ff_curveto;
result->base.mark_knot = NULL;
result->is_open = 0;
result->gotnans = 0;
result->ss = NULL;
return &result->base;
}
/* Finishes an old FontForge bezier context, and returns the contour which was created */
struct splinepointlist *bezctx_ff_close(bezctx *z) {
bezctx_ff *bc = (bezctx_ff *)z;
SplineSet *ss = bc->ss;
if (!bc->is_open && ss!=NULL ) {
if ( ss->first!=ss->last &&
RealNear(ss->first->me.x,ss->last->me.x) &&
RealNear(ss->first->me.y,ss->last->me.y)) {
ss->first->prevcp = ss->last->prevcp;
ss->first->noprevcp = ss->last->noprevcp;
ss->first->prev = ss->last->prev;
ss->first->prev->to = ss->first;
SplinePointFree(ss->last);
ss->last = ss->first;
} else {
if ( SplineMake3(ss->last,ss->first)!=NULL )
ss->last = ss->first;
}
}
free(bc);
return( ss );
}
#endif