static void IkarusAddContour(SplineChar *sc,int npts,BasePoint *bps, uint8 *ptype, int nesting) { SplinePointList *spl; SplinePoint *last, *next; int i, cw; spl = chunkalloc(sizeof(SplinePointList)); spl->next = sc->layers[ly_fore].splines; sc->layers[ly_fore].splines = spl; spl->first = spl->last = last = SplinePointCreate(bps[0].x,bps[0].y); last->pointtype = ptype[npts-1]; last->nextcpdef = last->prevcpdef = true; for ( i=1; i<npts-1; ++i ) { next = SplinePointCreate(bps[i].x,bps[i].y); next->nextcpdef = next->prevcpdef = true; next->pointtype = ptype[i]; SplineMake3(last,next); last = next; } SplineMake3(last,spl->last); last = spl->first; for ( i=1; i<npts; ++i ) { SplineCharDefaultPrevCP(last); SplineCharDefaultNextCP(last); last=last->next->to; } cw = SplinePointListIsClockwise(spl)==1; if ( ((nesting&1) && cw) || (!(nesting&1) && !cw) ) SplineSetReverse(spl); }
void SSRegenerateFromSpiros(SplineSet *spl) { SplineSet *temp; if ( spl->spiro_cnt<=1 ) return; if ( !has_spiro) return; SplineSetBeziersClear(spl); temp = SpiroCP2SplineSet(spl->spiros); if ( temp!=NULL ) { spl->first = temp->first; spl->last = temp->last; chunkfree(temp,sizeof(SplineSet)); } else { /* didn't converge... or something */ int i; SplinePoint *sp, *last; last = spl->first = SplinePointCreate(spl->spiros[0].x, spl->spiros[0].y); for ( i=1; i<spl->spiro_cnt; ++i ) { sp = SplinePointCreate(spl->spiros[i].x, spl->spiros[i].y); SplineMake3(last,sp); last = sp; } if ( SPIRO_SPL_OPEN(spl)) spl->last = last; else { SplineMake3(last,spl->first); spl->last = spl->first; } } spl->beziers_need_optimizer = true; }
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 ( !finite(xm) || !finite(ym) || !finite(x3) || !finite(y3)) { nancheck(bc); xm = ym = x3 = y3 = 0; } sp = SplinePointCreate(x3,y3); 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; SplineMake3(bc->ss->last,sp); bc->ss->last = sp; }
SplineSet *SpiroCP2SplineSet(spiro_cp *spiros) { int n; int any = 0; spiro_cp *nspiros; SplineSet *ss; int lastty = 0; if ( spiros==NULL ) return( NULL ); for ( n=0; spiros[n].ty!=SPIRO_END; ++n ) if ( SPIRO_SELECTED(&spiros[n]) ) ++any; if ( n==0 ) return( NULL ); if ( n==1 ) { ss = chunkalloc(sizeof(SplineSet)); ss->first = ss->last = SplinePointCreate(spiros[0].x,spiros[0].y); } else { bezctx *bc = new_bezctx_ff(); if ( (spiros[0].ty&0x7f)=='{' ) { lastty = spiros[n-1].ty; spiros[n-1].ty = '}'; } if ( !any ) { #if _LIBSPIRO_FUN if ( TaggedSpiroCPsToBezier0(spiros,bc)==0 ) { return( NULL ); } #else TaggedSpiroCPsToBezier(spiros,bc); #endif } else { nspiros = galloc((n+1)*sizeof(spiro_cp)); memcpy(nspiros,spiros,(n+1)*sizeof(spiro_cp)); for ( n=0; nspiros[n].ty!=SPIRO_END; ++n ) nspiros[n].ty &= ~0x80; #if _LIBSPIRO_FUN if ( TaggedSpiroCPsToBezier0(nspiros,bc)==0 ) { free(nspiros); return( NULL ); } #else TaggedSpiroCPsToBezier(nspiros,bc); #endif free(nspiros); } ss = bezctx_ff_close(bc); if ( (spiros[0].ty&0x7f)=='{' ) spiros[n-1].ty = lastty; } ss->spiros = spiros; ss->spiro_cnt = ss->spiro_max = n+1; SPLCatagorizePoints(ss); return( ss ); }
/* 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; }
void SSRegenerateFromSpiros(SplineSet * spl) { /* Regenerate an updated SplineSet from SpiroCPs after edits are done. */ if (spl->spiro_cnt <= 1 || !has_spiro) return; SplineSet *temp=SpiroCP2SplineSet(spl->spiros); if (temp != NULL) { /* Regenerated new SplineSet. Discard old copy. Keep new copy. */ SplineSetBeziersClear(spl); spl->first=temp->first; spl->last=temp->last; chunkfree(temp, sizeof(SplineSet)); } else { /* Didn't converge... or something ...therefore let's fake-it. */ int i; SplinePoint *sp, *first, *last; if ((last=first = SplinePointCreate(spl->spiros[0].x, spl->spiros[0].y))==NULL) return; for (i=1; i < spl->spiro_cnt; ++i) { if ((sp=SplinePointCreate(spl->spiros[i].x, spl->spiros[i].y))) { SplineMake3(last, sp); last=sp; } else break; /* ...have problem, but keep what we got so far */ } /* dump the prior SplineSet and now show this line-art instead */ SplineSetBeziersClear(spl); spl->first=first; if (SPIRO_SPL_OPEN(spl)) spl->last=last; else { SplineMake3(last, spl->first); spl->last=spl->first; } } spl->beziers_need_optimizer=true; }
static void bezctx_ff_moveto(bezctx *z, double x, double y, int is_open) { bezctx_ff *bc = (bezctx_ff *)z; if ( !finite(x) || !finite(y)) { nancheck(bc); x = y = 0; } if (!bc->is_open) { SplineSet *ss = chunkalloc(sizeof(SplineSet)); ss->next = bc->ss; bc->ss = ss; } bc->ss->first = bc->ss->last = SplinePointCreate(x,y); bc->is_open = is_open; }
/* 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->is_open=is_open; }
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 ( !finite(x1) || !finite(y1) || !finite(x2) || !finite(y2) || !finite(x3) || !finite(y3)) { nancheck(bc); x1 = y1 = x2 = y2 = x3 = y3 = 0; } sp = SplinePointCreate(x3,y3); 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; SplineMake3(bc->ss->last,sp); bc->ss->last = sp; }
SplineSet *SpiroCP2SplineSet(spiro_cp *spiros) { /* Create a SplineSet from the given spiros_code_points.*/ int n; int any = 0; SplineSet *ss; int lastty = 0; if ( spiros==NULL ) return( NULL ); for ( n=0; spiros[n].ty!=SPIRO_END; ++n ) if ( SPIRO_SELECTED(&spiros[n]) ) ++any; if ( n==0 ) return( NULL ); if ( n==1 ) { /* Spiro only haS 1 code point sofar (no conversion needed yet) */ if ( (ss=chunkalloc(sizeof(SplineSet)))==NULL || \ (ss->first=ss->last=SplinePointCreate(spiros[0].x,spiros[0].y))==NULL ) { chunkfree(ss,sizeof(SplineSet)); return( NULL ); } } else { /* Spiro needs to be converted to bezier curves using libspiro. */ bezctx *bc; if ( (bc=new_bezctx_ff())==NULL ) return( NULL ); if ( (spiros[0].ty&0x7f)=='{' ) { lastty = spiros[n-1].ty; spiros[n-1].ty = '}'; } if ( !any ) { #if _LIBSPIRO_FUN if ( TaggedSpiroCPsToBezier0(spiros,bc)==0 ) { if ( lastty ) spiros[n-1].ty = lastty; free(bc); return( NULL ); } #else TaggedSpiroCPsToBezier(spiros,bc); #endif } else { int i; spiro_cp *nspiros; if ( (nspiros=malloc((n+1)*sizeof(spiro_cp)))==NULL ) { if ( lastty ) spiros[n-1].ty = lastty; free(bc); return( NULL ); } memcpy(nspiros,spiros,(n+1)*sizeof(spiro_cp)); for ( i=0; nspiros[i].ty!=SPIRO_END; ++i ) nspiros[i].ty &= ~0x80; #if _LIBSPIRO_FUN if ( TaggedSpiroCPsToBezier0(nspiros,bc)==0 ) { if ( lastty ) spiros[n-1].ty = lastty; free(nspiros); free(bc); return( NULL ); } #else TaggedSpiroCPsToBezier(nspiros,bc); #endif free(nspiros); } if ( lastty ) spiros[n-1].ty = lastty; if ( (ss=bezctx_ff_close(bc))==NULL ) return( NULL ); } ss->spiros = spiros; ss->spiro_cnt = ss->spiro_max = n+1; SPLCatagorizePoints(ss); return( ss ); }
/* When the user tries to add a point (by doing a mouse down with a point tool selected) there are several cases to be looked at: If there is a single point selected and it is at the begining/end of an open spline set if we clicked on another point which is the begining/end of an open splineset draw a spline connecting the two spline sets and merge them (or if it's the same spline set, then close it) else create a new point where we clicked draw a spline between the selected point and the new one deselect the old point select the new one endif else if they clicked on a spline split the spline into two bits at the point where they clicked else create a new point where they clicked put it on a new splineset select it endif and, if the old point is a tangent, we may need to adjust its control pt With the introduction of spiro mode (Raph Levien's clothoid splines) we've got to worry about all the above cases for spiro points too. */ void CVMouseDownPoint(CharView *cv, GEvent *event) { SplineSet *sel, *ss; SplinePoint *sp, *base = NULL; SplineChar *sc = cv->b.sc; enum pointtype ptype = (cv->active_tool==cvt_curve?pt_curve: cv->active_tool==cvt_hvcurve?pt_hvcurve: cv->active_tool==cvt_corner?pt_corner: cv->active_tool==cvt_tangent?pt_tangent: /*cv->active_tool==cvt_pen?*/pt_corner); int order2 = cv->b.layerheads[cv->b.drawmode]->order2; int order2_style = (order2 && !(event->u.mouse.state&ksm_meta)) || (!order2 && (event->u.mouse.state&ksm_meta)); cv->active_spl = NULL; cv->active_sp = NULL; if ( cv->b.sc->inspiro && hasspiro()) { CVMouseDownSpiroPoint(cv, event); return; } sel = CVAnySelPointList(cv); if ( sel!=NULL ) { if ( sel->first->selected ) base = sel->first; else base = sel->last; if ( base==cv->p.sp ) return; /* We clicked on the active point, that's a no-op */ } CVPreserveState(&cv->b); CVClearSel(cv); if ( sel!=NULL ) { sp = cv->p.sp; cv->lastselpt = base; ss = sel; if ( base->next!=NULL ) SplineSetReverse(sel); if ( base->next!=NULL ) IError("Base point not at end of splineset in CVMouseDownPoint"); if ( sp==NULL || (sp->next!=NULL && sp->prev!=NULL) || sp==base ) { /* Add a new point */ SplineSetSpirosClear(sel); sp = SplinePointCreate( cv->p.cx, cv->p.cy ); sp->noprevcp = sp->nonextcp = 1; sp->nextcpdef = sp->prevcpdef = 1; sp->pointtype = ptype; sp->selected = true; if ( !base->nonextcp && order2_style && cv->active_tool==cvt_pen ) { sp->prevcp = base->nextcp; sp->noprevcp = false; sp->me.x = ( sp->prevcp.x + sp->nextcp.x )/2; sp->me.y = ( sp->prevcp.y + sp->nextcp.y )/2; sp->nonextcp = false; sp->pointtype = pt_curve; } else if ( order2 && !base->nonextcp ) { sp->prevcp = base->nextcp; sp->noprevcp = false; if ( cv->active_tool==cvt_pen ) { sp->nextcp.x = sp->me.x - (sp->prevcp.x-sp->me.x); sp->nextcp.y = sp->me.y - (sp->prevcp.y-sp->me.y); sp->nonextcp = false; sp->pointtype = pt_curve; } } if ( base->nonextcp ) base->nextcpdef = true; SplineMake(base,sp,order2); if ( cv->active_tool!=cvt_pen ) { SplineCharDefaultNextCP(base); SplineCharDefaultPrevCP(sp); } ss->last = sp; } else if ( cv->p.spl==sel ) { /* Close the current spline set */ SplineSetSpirosClear(sel); cv->joinvalid = true; cv->joinpos = *sp; cv->joinpos.selected = false; if ( order2 ) { if ( base->nonextcp || sp->noprevcp ) { base->nonextcp = sp->noprevcp = true; base->nextcp = base->me; sp->prevcp = sp->me; } else { base->nextcp.x = sp->prevcp.x = (base->nextcp.x+sp->prevcp.x)/2; base->nextcp.y = sp->prevcp.y = (base->nextcp.y+sp->prevcp.y)/2; } base->nextcpdef = sp->prevcpdef = true; } SplineMake(base,sp,order2); if ( cv->active_tool!=cvt_pen ) SplineCharDefaultNextCP(base); SplineCharDefaultPrevCP(sp); ss->last = sp; if ( sp->pointtype==pt_tangent ) { SplineCharTangentNextCP(sp); if ( sp->next ) SplineRefigure(sp->next ); } } else { /* Merge two spline sets */ SplineSetSpirosClear(sel); CVMergeSPLS(cv,sel, base,sp); } sp->selected = true; if ( base->pointtype==pt_tangent ) { SplineCharTangentPrevCP(base); if ( base->prev!=NULL ) SplineRefigure(base->prev); } } else if ( cv->p.spline!=NULL ) { sp = SplineBisect(cv->p.spline,cv->p.t); cv->joinvalid = true; cv->joinpos = *sp; cv->joinpos.selected = false; if ( cv->active_tool==cvt_pen ) ptype = pt_curve; sp->pointtype = ptype; if ( ptype==pt_hvcurve ) { SPHVCurveForce(sp); } sp->selected = true; ss = cv->p.spl; } else { ss = chunkalloc(sizeof(SplineSet)); sp = SplinePointCreate( cv->p.cx, cv->p.cy ); ss->first = ss->last = sp; ss->next = cv->b.layerheads[cv->b.drawmode]->splines; cv->b.layerheads[cv->b.drawmode]->splines = ss; sp->nonextcp = sp->noprevcp = 1; sp->nextcpdef = sp->prevcpdef = 1; sp->pointtype = ptype; sp->selected = true; } cv->active_spl = ss; cv->active_sp = sp; CVSetCharChanged(cv,true); CVInfoDraw(cv,cv->gw); SCUpdateAll(sc); if ( cv->active_tool == cvt_pen ) cv->p.constrain = sp->me; }