static void CVMergeSPLS(CharView *cv,SplineSet *ss, SplinePoint *base,SplinePoint *sp) { int order2 = cv->b.layerheads[cv->b.drawmode]->order2; cv->joinvalid = true; cv->joinpos = *sp; cv->joinpos.selected = false; if ( sp->prev!=NULL ) SplineSetReverse(cv->p.spl); if ( sp->prev!=NULL ) IError("Base point not at start of splineset in CVMouseDownPoint"); /* remove the old spl entry from the chain */ if ( cv->p.spl==cv->b.layerheads[cv->b.drawmode]->splines ) cv->b.layerheads[cv->b.drawmode]->splines = cv->p.spl->next; else { SplineSet *temp; for ( temp = cv->b.layerheads[cv->b.drawmode]->splines; temp->next!=cv->p.spl; temp = temp->next ); temp->next = cv->p.spl->next; } if ( order2 && (!RealNear(base->nextcp.x,sp->prevcp.x) || !RealNear(base->nextcp.y,sp->prevcp.y)) ) { base->nonextcp = sp->noprevcp = true; base->nextcp = base->me; sp->prevcp = sp->me; } SplineMake(base,sp,order2); SplineCharDefaultNextCP(base); SplineCharDefaultPrevCP(sp); if ( sp->pointtype==pt_tangent ) { SplineCharTangentNextCP(sp); if ( sp->next ) SplineRefigure(sp->next ); } ss->last = cv->p.spl->last; if ( ss->spiros && cv->p.spl->spiros ) { if ( ss->spiro_cnt+cv->p.spl->spiro_cnt > ss->spiro_max ) ss->spiros = realloc(ss->spiros, (ss->spiro_max = ss->spiro_cnt+cv->p.spl->spiro_cnt)*sizeof(spiro_cp)); memcpy(ss->spiros+ss->spiro_cnt-1, cv->p.spl->spiros+1, (cv->p.spl->spiro_cnt-1)*sizeof(spiro_cp)); ss->spiro_cnt += cv->p.spl->spiro_cnt-2; } else SplineSetSpirosClear(ss); cv->p.spl->last = cv->p.spl->first = NULL; cv->p.spl->spiros = 0; SplinePointListFree(cv->p.spl); cv->p.spl = NULL; }
/* Finishes an old FontAnvil 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); }
static int AssignPtNumbers(MMSet *mm,int gid) { /* None of the instances has fixed point numbers. Make them match */ int cnt=0; SplineSet **ss; SplinePoint **sp; int i; int allavg, alllines, stillmore, ret=true; ss = malloc((mm->instance_count+1)*sizeof(SplineSet *)); sp = malloc((mm->instance_count+1)*sizeof(SplinePoint *)); for ( i=0; i<mm->instance_count; ++i ) ss[i] = mm->instances[i]->glyphs[gid]->layers[ly_fore].splines; ss[i] = mm->normal->glyphs[gid]->layers[ly_fore].splines; if ( ss[0]==NULL ) { stillmore = false; for ( i=0; i<=mm->instance_count; ++i ) if ( ss[i]!=NULL ) stillmore = true; if ( stillmore ) return( false ); return( true ); } else { stillmore = true; for ( i=0; i<=mm->instance_count; ++i ) if ( ss[i]==NULL ) stillmore = false; if ( !stillmore ) return( false ); } for (;;) { for ( i=0; i<=mm->instance_count; ++i ) sp[i] = ss[i]->first; for (;;) { allavg = alllines = true; for ( i=0; i<=mm->instance_count; ++i ) { if ( !RealNear(sp[i]->me.x,(sp[i]->nextcp.x+sp[i]->prevcp.x)/2) || !RealNear(sp[i]->me.y,(sp[i]->nextcp.y+sp[i]->prevcp.y)/2) ) allavg = false; if ( !sp[i]->nonextcp ) alllines = false; } if ( sp[0] == ss[0]->first ) allavg = false; for ( i=0; i<=mm->instance_count; ++i ) { if ( allavg ) sp[i]->ttfindex = 0xffff; else sp[i]->ttfindex = cnt; } if ( !allavg ) ++cnt; for ( i=0; i<=mm->instance_count; ++i ) { if ( alllines ) sp[i]->nextcpindex = 0xffff; else sp[i]->nextcpindex = cnt; } if ( !alllines ) ++cnt; if ( sp[0]->next==NULL ) { stillmore = false; for ( i=1; i<=mm->instance_count; ++i ) if ( sp[i]->next!=NULL ) stillmore = true; if ( stillmore ) ret = false; break; } for ( i=1; i<=mm->instance_count; ++i ) if ( sp[i]->next==NULL ) stillmore = false; if ( !stillmore ) { ret = false; break; } sp[0] = sp[0]->next->to; for ( i=1; i<=mm->instance_count; ++i ) sp[i] = sp[i]->next->to; if ( sp[0]==ss[0]->first ) { stillmore = false; for ( i=1; i<=mm->instance_count; ++i ) if ( sp[i]!=ss[i]->first ) stillmore = true; if ( stillmore ) ret = false; break; } for ( i=1; i<=mm->instance_count; ++i ) { if ( sp[i]==ss[i]->first ) stillmore = false; } if ( !stillmore ) { ret = false; break; } } if ( !ret ) break; stillmore = true; for ( i=0; i<=mm->instance_count; ++i ) ss[i] = ss[i]->next; if ( ss[0]==NULL ) { stillmore=false; for ( i=1; i<=mm->instance_count; ++i ) if ( ss[i]!=NULL ) stillmore = true; if ( stillmore ) ret = true; break; } for ( i=1; i<=mm->instance_count; ++i ) if ( ss[i]==NULL ) stillmore = false; if ( !stillmore ) { ret = true; break; } } return( ret ); }
static int MatchPoints(SplineFont *sffixed, SplineFont *sfother, int gid) { SplineChar *fixed, *other; SplineSet *ss1, *ss2; SplinePoint *sp1, *sp2; fixed = sffixed->glyphs[gid]; other = sfother->glyphs[gid]; if ( PtNumbersAreSet(other)) { /* Point numbers must match exactly, both are fixed */ for ( ss1=fixed->layers[ly_fore].splines, ss2=other->layers[ly_fore].splines; ss1!=NULL && ss2!=NULL ; ss1 = ss1->next, ss2=ss2->next ) { for ( sp1=ss1->first, sp2=ss2->first; ; ) { if ( sp1->ttfindex!=sp2->ttfindex || sp1->nextcpindex!=sp2->nextcpindex ) return( false ); if ( sp1->next==NULL || sp2->next==NULL ) { if ( sp1->next!=NULL || sp2->next!=NULL ) return( false ); break; } sp1 = sp1->next->to; sp2=sp2->next->to; if ( sp1==ss1->first || sp2==ss2->first ) { if ( sp1!=ss1->first || sp2!=ss2->first ) return( false ); break; } } } return( ss1==NULL && ss2==NULL ); } else { for ( ss1=fixed->layers[ly_fore].splines, ss2=other->layers[ly_fore].splines; ss1!=NULL && ss2!=NULL ; ss1 = ss1->next, ss2=ss2->next ) { for ( sp1=ss1->first, sp2=ss2->first; ; ) { if ( sp1->ttfindex!=0xffff ) sp2->ttfindex = sp1->ttfindex; else if ( !RealNear(sp2->me.x,(sp2->nextcp.x+sp2->prevcp.x)/2) || !RealNear(sp2->me.y,(sp2->nextcp.y+sp2->prevcp.y)/2) ) return( false ); else sp2->ttfindex = 0xffff; if ( sp1->nextcpindex!=0xffff ) sp2->nextcpindex = sp1->nextcpindex; else if ( !sp2->nonextcp ) return( false ); else sp2->nextcpindex = 0xffff; if ( sp1->next==NULL || sp2->next==NULL ) { if ( sp1->next!=NULL || sp2->next!=NULL ) return( false ); break; } sp1 = sp1->next->to; sp2=sp2->next->to; if ( sp1==ss1->first || sp2==ss2->first ) { if ( sp1!=ss1->first || sp2!=ss2->first ) return( false ); break; } } } return( ss1==NULL && ss2==NULL ); } }
static void AddSpline(EdgeList *es, Spline *sp ) { real t1=2, t2=2, t; real b2_fourac; real fm, tm; Spline1D *msp = &sp->splines[es->major], *osp = &sp->splines[es->other]; /* Find the points of extrema on the curve discribing y behavior */ if ( !RealNear(msp->a,0) ) { /* cubic, possibly 2 extrema (possibly none) */ b2_fourac = 4*msp->b*msp->b - 12*msp->a*msp->c; if ( b2_fourac>=0 ) { b2_fourac = sqrt(b2_fourac); t1 = CheckExtremaForSingleBitErrors(msp,(-2*msp->b - b2_fourac) / (6*msp->a)); t2 = CheckExtremaForSingleBitErrors(msp,(-2*msp->b + b2_fourac) / (6*msp->a)); if ( t1>t2 ) { real temp = t1; t1 = t2; t2 = temp; } else if ( t1==t2 ) t2 = 2.0; /* check for curves which have such a small slope they might */ /* as well be horizontal */ fm = es->major==1?sp->from->me.y:sp->from->me.x; tm = es->major==1?sp->to->me.y:sp->to->me.x; if ( fm==tm ) { real m1, m2, d1, d2; m1 = m2 = fm; if ( t1>0 && t1<1 ) m1 = ((msp->a*t1+msp->b)*t1+msp->c)*t1 + msp->d; if ( t2>0 && t2<1 ) m2 = ((msp->a*t2+msp->b)*t2+msp->c)*t2 + msp->d; d1 = (m1-fm)*es->scale; d2 = (m2-fm)*es->scale; if ( d1>-.5 && d1<.5 && d2>-.5 && d2<.5 ) { sp->ishorvert = true; if ( es->genmajoredges ) AddMajorEdge(es,sp); return; /* Pretend it's horizontal, ignore it */ } } } } else if ( !RealNear(msp->b,0) ) { /* Quadratic, at most one extremum */ t1 = -msp->c/(2.0*msp->b); } else if ( !RealNear(msp->c,0) ) { /* linear, no points of extrema */ } else { sp->ishorvert = true; if ( es->genmajoredges ) AddMajorEdge(es,sp); return; /* Horizontal line, ignore it */ } if ( RealNear(t1,0)) t1=0; if ( RealNear(t1,1)) t1=1; if ( RealNear(t2,0)) t2=0; if ( RealNear(t2,1)) t2=1; if ( RealNear(t1,t2)) t2=2; t=0; if ( t1>0 && t1<1 ) { AddEdge(es,sp,0,t1); t = t1; } if ( t2>0 && t2<1 ) { AddEdge(es,sp,t,t2); t = t2; } AddEdge(es,sp,t,1.0); if ( es->interesting ) { /* Also store up points of extrema in X as interesting (we got the endpoints, just internals now)*/ extended ot1, ot2; int mpos; SplineFindExtrema(osp,&ot1,&ot2); if ( ot1>0 && ot1<1 ) { mpos = (int) ceil( ( ((msp->a*ot1+msp->b)*ot1+msp->c)*ot1+msp->d )*es->scale-es->mmin ); es->interesting[mpos] = 1; } if ( ot2>0 && ot2<1 ) { mpos = (int) ceil( ( ((msp->a*ot2+msp->b)*ot2+msp->c)*ot2+msp->d )*es->scale-es->mmin ); es->interesting[mpos] = 1; } } }
static void AddEdge(EdgeList *es, Spline *sp, real tmin, real tmax ) { Edge *e, *pr; real m1, m2; int mpos; Hints *hint; Spline1D *msp = &sp->splines[es->major], *osp = &sp->splines[es->other]; e = gcalloc(1,sizeof(Edge)); e->spline = sp; m1 = ( ((msp->a*tmin+msp->b)*tmin+msp->c)*tmin + msp->d ) * es->scale; m2 = ( ((msp->a*tmax+msp->b)*tmax+msp->c)*tmax + msp->d ) * es->scale; if ( m1>m2 ) { e->mmin = m2; e->t_mmin = tmax; e->mmax = m1; e->t_mmax = tmin; e->up = false; } else { e->mmax = m2; e->t_mmax = tmax; e->mmin = m1; e->t_mmin = tmin; e->up = true; } if ( RealNear(e->mmin,es->mmin)) e->mmin = es->mmin; e->o_mmin = ( ((osp->a*e->t_mmin+osp->b)*e->t_mmin+osp->c)*e->t_mmin + osp->d ) * es->scale; e->o_mmax = ( ((osp->a*e->t_mmax+osp->b)*e->t_mmax+osp->c)*e->t_mmax + osp->d ) * es->scale; e->mmin -= es->mmin; e->mmax -= es->mmin; e->t_cur = e->t_mmin; e->o_cur = e->o_mmin; e->m_cur = e->mmin; e->last_opos = e->last_mpos = -2; e->tmin = tmin; e->tmax = tmax; if ( e->mmin<0 || e->mmin>=e->mmax ) { /*IError("Probably not serious, but we've got a zero length spline in AddEdge in %s",es->sc==NULL?<nameless>:es->sc->name);*/ free(e); return; } if ( es->sc!=NULL ) for ( hint=es->hhints; hint!=NULL; hint=hint->next ) { if ( hint->adjustb ) { if ( e->m_cur>hint->b1 && e->m_cur<hint->b2 ) { e->m_cur = e->mmin = hint->ab; e->min_adjusted = true; } else if ( e->mmax>hint->b1 && e->mmax<hint->b2 ) { e->mmax = hint->ab; e->max_adjusted = true; } } else if ( hint->adjuste ) { if ( e->m_cur>hint->e1 && e->m_cur<hint->e2 ) { e->m_cur = e->mmin = hint->ae; e->min_adjusted = true; } else if ( e->mmax>hint->e1 && e->mmax<hint->e2 ) { e->mmax = hint->ae; e->max_adjusted = true; } } } mpos = (int) ceil(e->m_cur); if ( mpos>e->mmax || mpos>=es->cnt ) { free(e); return; } if ( e->m_cur!=ceil(e->m_cur) ) { /* bring the new edge up to its first scan line */ e->t_cur = TOfNextMajor(e,es,ceil(e->m_cur)); e->o_cur = ( ((osp->a*e->t_cur+osp->b)*e->t_cur+osp->c)*e->t_cur + osp->d ) * es->scale; } e->before = es->last; if ( es->last!=NULL ) es->last->after = e; if ( es->last==NULL ) es->splinesetfirst = e; es->last = e; if ( es->edges[mpos]==NULL || e->o_cur<es->edges[mpos]->o_cur || (e->o_cur==es->edges[mpos]->o_cur && SlopeLess(e,es->edges[mpos],es->other))) { e->esnext = es->edges[mpos]; es->edges[mpos] = e; } else { for ( pr=es->edges[mpos]; pr->esnext!=NULL && pr->esnext->o_cur<e->o_cur ; pr = pr->esnext ); /* When two splines share a vertex which is a local minimum, then */ /* o_cur will be equal for both (to the vertex's o value) and so */ /* the above code randomly picked one to go first. That screws up */ /* the overlap code, which wants them properly ordered from the */ /* start. so look at the end point, nope the end point isn't always */ /* meaningful, look at the slope... */ if ( pr->esnext!=NULL && pr->esnext->o_cur==e->o_cur && SlopeLess(e,pr->esnext,es->other)) { pr = pr->esnext; } e->esnext = pr->esnext; pr->esnext = e; } if ( es->interesting ) { /* Mark the other end of the spline as interesting */ es->interesting[(int) ceil(e->mmax)]=1; } }
static int Trans_OK(GGadget *g, GEvent *e) { real transform[6], trans[6], t[6]; bigreal angle, angle2; int i, index, err; int alllayers = false, round_2_int = false, dokerns = false, dokp=false; int dogrid = false, dowidth = false; BasePoint base; int origin, bvpos=0; BVTFunc bvts[TCnt+1]; static int warned = false; int isapply = GGadgetGetCid(g) == CID_Apply; if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) { TransData *td = GDrawGetUserData(GGadgetGetWindow(g)); transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[4] = transform[5] = 0; base.x = base.y = 0; origin = GGadgetGetFirstListSelectedItem( GWidgetGetControl(td->gw,CID_Origin)); if ( GWidgetGetControl(td->gw,CID_AllLayers)!=NULL ) alllayers = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_AllLayers)); if ( GWidgetGetControl(td->gw,CID_DoGrid)!=NULL ) dogrid = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoGrid)); if ( GWidgetGetControl(td->gw,CID_DoWidth)!=NULL ) dowidth = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoWidth)); else dowidth = true; if ( GWidgetGetControl(td->gw,CID_DoSimplePos)!=NULL ) dokp = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoSimplePos)); if ( GWidgetGetControl(td->gw,CID_DoKerns)!=NULL ) dokerns = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_DoKerns)); round_2_int = GGadgetIsChecked(GWidgetGetControl(td->gw,CID_Round2Int)); if ( isapply ) alllayers = dogrid = dokp = dokerns = false; if ( td->getorigin!=NULL ) { (td->getorigin)(td->userdata,&base,origin ); transform[4] = -base.x; transform[5] = -base.y; } for ( i=0; i<TCnt; ++i ) { index = GGadgetGetFirstListSelectedItem( GWidgetGetControl(td->gw,CID_Type+i*TBlock_CIDOffset)); trans[0] = trans[3] = 1.0; trans[1] = trans[2] = trans[4] = trans[5] = 0; err = 0; switch ( index ) { case 0: /* Do Nothing */ break; case 1: /* Move */ trans[4] = GetReal8(td->gw,CID_XMove+i*TBlock_CIDOffset,_("X Movement"),&err); trans[5] = GetReal8(td->gw,CID_YMove+i*TBlock_CIDOffset,_("Y Movement"),&err); bvts[bvpos].x = trans[4]; bvts[bvpos].y = trans[5]; bvts[bvpos++].func = bvt_transmove; break; case 2: /* Rotate */ angle = GetReal8(td->gw,CID_Angle+i*TBlock_CIDOffset,_("Rotation Angle"),&err); if ( GGadgetIsChecked( GWidgetGetControl(td->gw,CID_Clockwise+i*TBlock_CIDOffset)) ) angle = -angle; if ( fmod(angle,90)!=0 ) bvts[0].func = bvt_none; /* Bad trans=> No trans */ else { angle = fmod(angle,360); if ( angle<0 ) angle+=360; if ( angle==90 ) bvts[bvpos++].func = bvt_rotate90ccw; else if ( angle==180 ) bvts[bvpos++].func = bvt_rotate180; else if ( angle==270 ) bvts[bvpos++].func = bvt_rotate90cw; } angle *= 3.1415926535897932/180; trans[0] = trans[3] = cos(angle); trans[2] = -(trans[1] = sin(angle)); break; case 3: /* Scale Uniformly */ trans[0] = trans[3] = GetReal8(td->gw,CID_Scale+i*TBlock_CIDOffset,_("Scale Factor"),&err)/100.0; bvts[0].func = bvt_none; /* Bad trans=> No trans */ break; case 4: /* Scale */ trans[0] = GetReal8(td->gw,CID_XScale+i*TBlock_CIDOffset,_("X Scale Factor"),&err)/100.0; trans[3] = GetReal8(td->gw,CID_YScale+i*TBlock_CIDOffset,_("Y Scale Factor"),&err)/100.0; bvts[0].func = bvt_none; /* Bad trans=> No trans */ break; case 5: /* Flip */ if ( GGadgetIsChecked( GWidgetGetControl(td->gw,CID_Horizontal+i*TBlock_CIDOffset)) ) { trans[0] = -1; bvts[bvpos++].func = bvt_fliph; } else { trans[3] = -1; bvts[bvpos++].func = bvt_flipv; } break; case 6: /* Skew */ angle = GetReal8(td->gw,CID_SkewAng+i*TBlock_CIDOffset,_("Skew Angle"),&err); if ( GGadgetIsChecked( GWidgetGetControl(td->gw,CID_CounterClockwise+i*TBlock_CIDOffset)) ) angle = -angle; angle *= 3.1415926535897932/180; trans[2] = tan(angle); skewselect(&bvts[bvpos],trans[2]); ++bvpos; break; case 7: /* 3D rotate */ angle = GetReal8(td->gw,CID_XAxis+i*TBlock_CIDOffset,_("Rotation about X Axis"),&err) * 3.1415926535897932/180; angle2 = GetReal8(td->gw,CID_YAxis+i*TBlock_CIDOffset,_("Rotation about Y Axis"),&err) * 3.1415926535897932/180; trans[0] = cos(angle2); trans[3] = cos(angle ); bvts[0].func = bvt_none; /* Bad trans=> No trans */ break; default: IError("Unexpected selection in Transform"); err = 1; break; } if ( err ) return(true); #if 0 printf( "(%g,%g,%g,%g,%g,%g)*(%g,%g,%g,%g,%g,%g) = ", trans[0], trans[1], trans[2], trans[3], trans[4], trans[5], transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]); #endif t[0] = transform[0]*trans[0] + transform[1]*trans[2]; t[1] = transform[0]*trans[1] + transform[1]*trans[3]; t[2] = transform[2]*trans[0] + transform[3]*trans[2]; t[3] = transform[2]*trans[1] + transform[3]*trans[3]; t[4] = transform[4]*trans[0] + transform[5]*trans[2] + trans[4]; t[5] = transform[4]*trans[1] + transform[5]*trans[3] + trans[5]; memcpy(transform,t,sizeof(t)); #if 0 printf( "(%g,%g,%g,%g,%g,%g)\n", transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]); #endif } bvts[bvpos++].func = bvt_none; /* Done */ for ( i=0; i<6; ++i ) if ( RealNear(transform[i],0)) transform[i] = 0; transform[4] += base.x; transform[5] += base.y; if (( transform[1]!=0 || transform[2]!=0 ) && !warned ) { ff_post_notice(_("Warning"),_("After rotating or skewing a glyph you should probably apply Element->Add Extrema")); warned = true; } (td->transfunc)(td->userdata,transform,origin,bvts, (alllayers?fvt_alllayers:0)| (dogrid?fvt_dogrid:0)| (dowidth?0:fvt_dontmovewidth)| (round_2_int?fvt_round_to_int:0)| (dokp?fvt_scalepstpos:0)| (dokerns?fvt_scalekernclasses:0)| (isapply?fvt_justapply:0)); td->done = !isapply; td->applied = isapply; } return( true ); }
static int SPMatchesF(SplinePoint *sp, SearchData *s, SplineSet *path, SplinePoint *sc_path_first, int substring ) { SplinePoint *sc_sp, *nsc_sp, *p_sp, *np_sp; int flip, flipmax; bigreal rot, scale; int saw_sc_first = false, first_of_path; BasePoint p_unit, pend_unit, sc_unit; bigreal len, temp; s->matched_sp = sp; s->matched_rot = 0; s->matched_scale = 1.0; s->matched_flip = flip_none; s->matched_co = 1; s->matched_si=0; first_of_path = true; p_sp = path->first; if ( s->endpoints ) { SplinePoint *p_prevsp = p_sp; SplinePoint *psc_sp; p_sp = p_sp->next->to; p_unit.x = p_sp->me.x - p_prevsp->me.x; p_unit.y = p_sp->me.y - p_prevsp->me.y; len = sqrt(p_unit.x*p_unit.x + p_unit.y*p_unit.y); if ( len==0 ) return( false ); p_unit.x /= len; p_unit.y /= len; if ( sp->prev==NULL ) return( false ); psc_sp = sp->prev->from; if ( (sp->me.x-psc_sp->me.x)*(sp->me.x-psc_sp->me.x) + (sp->me.y-psc_sp->me.y)*(sp->me.y-psc_sp->me.y) < len*len ) return( false ); } if ( s->endpoints ) { SplinePoint *p_nextsp = path->last; SplinePoint *p_end = p_nextsp->prev->from; if ( sp->next==NULL ) return( false ); for ( p_end = p_sp, p_nextsp = p_end->next->to, sc_sp = sp, nsc_sp=sp->next->to ;; ) { if ( p_nextsp->next==NULL ) break; if ( nsc_sp->next==NULL ) return( false ); p_end = p_nextsp; sc_sp = nsc_sp; p_nextsp = p_nextsp->next->to; nsc_sp = nsc_sp->next->to; } pend_unit.x = p_nextsp->me.x - p_end->me.x; pend_unit.y = p_nextsp->me.y - p_end->me.y; len = sqrt(pend_unit.x*pend_unit.x + pend_unit.y*pend_unit.y); if ( len==0 ) return( false ); pend_unit.x /= len; pend_unit.y /= len; if ( (sp->me.x-nsc_sp->me.x)*(sp->me.x-nsc_sp->me.x) + (sp->me.y-nsc_sp->me.y)*(sp->me.y-nsc_sp->me.y) < len*len ) return( false ); } /* ******************* Match with no transformations applied **************** */ first_of_path = true; for (sc_sp=sp; ; ) { if ( sc_sp->ticked ) /* Don't search within stuff we have just replaced */ return( false ); if ( p_sp->next==NULL ) { if ( substring || sc_sp->next==NULL ) { s->last_sp = saw_sc_first ? NULL : sp; return( true ); } break; } np_sp = p_sp->next->to; if ( sc_sp->next==NULL ) break; nsc_sp = sc_sp->next->to; if ( first_of_path && s->endpoints ) { SplinePoint *sc_prevsp; if ( sc_sp->prev==NULL ) return( false ); sc_prevsp = sc_sp->prev->from; if ( !p_sp->noprevcp ) { if ( sc_sp->noprevcp ) return( false ); if ( !CoordMatches(sc_sp->prevcp.x-sc_sp->me.x,p_sp->prevcp.x-p_sp->me.x,s) || !CoordMatches(sc_sp->prevcp.y-sc_sp->me.y,p_sp->prevcp.y-p_sp->me.y,s) ) break; /* prev control points do not match, give up */ } else { if ( !sc_sp->noprevcp ) return( false ); sc_unit.x = sc_sp->me.x - sc_prevsp->me.x; sc_unit.y = sc_sp->me.y - sc_prevsp->me.y; len = sqrt(sc_unit.x*sc_unit.x + sc_unit.y*sc_unit.y ); if ( len==0 ) return( false ); sc_unit.x /= len; sc_unit.y /= len; if ( !RealNear(sc_unit.x,p_unit.x) || !RealNear(sc_unit.y,p_unit.y)) break; } first_of_path = false; } if ( np_sp->next==NULL && s->endpoints ) { SplinePoint *sc_nextsp; if ( sc_sp->next==NULL ) return( false ); sc_nextsp = sc_sp->next->to; if ( !p_sp->nonextcp ) { if ( !CoordMatches(sc_sp->nextcp.x-sc_sp->me.x,p_sp->nextcp.x-p_sp->me.x,s) || !CoordMatches(sc_sp->nextcp.y-sc_sp->me.y,p_sp->nextcp.y-p_sp->me.y,s) ) break; /* prev control points do not match, give up */ } else { if ( !sc_sp->nonextcp ) return( false ); sc_unit.x = sc_nextsp->me.x - sc_sp->me.x; sc_unit.y = sc_nextsp->me.y - sc_sp->me.y; len = sqrt(sc_unit.x*sc_unit.x + sc_unit.y*sc_unit.y ); if ( len==0 ) return( false ); sc_unit.x /= len; sc_unit.y /= len; if ( RealNear(sc_unit.x,pend_unit.x) && RealNear(sc_unit.y,pend_unit.y)) { s->last_sp = saw_sc_first ? NULL : sp; return( true ); } else break; } } if ( !CoordMatches(sc_sp->nextcp.x-sc_sp->me.x,p_sp->nextcp.x-p_sp->me.x,s) || !CoordMatches(sc_sp->nextcp.y-sc_sp->me.y,p_sp->nextcp.y-p_sp->me.y,s) || !CoordMatches(nsc_sp->me.x-sc_sp->me.x,np_sp->me.x-p_sp->me.x,s) || !CoordMatches(nsc_sp->me.y-sc_sp->me.y,np_sp->me.y-p_sp->me.y,s) || !CoordMatches(nsc_sp->prevcp.x-nsc_sp->me.x,np_sp->prevcp.x-np_sp->me.x,s) || !CoordMatches(nsc_sp->prevcp.y-nsc_sp->me.y,np_sp->prevcp.y-np_sp->me.y,s) ) break; if ( np_sp==path->first ) { if ( nsc_sp==sp ) { s->last_sp = saw_sc_first ? NULL : sp; return( true ); } break; } sc_sp = nsc_sp; if ( sc_sp == sc_path_first ) saw_sc_first = true; p_sp = np_sp; } /* ************** Match with just flip transformations applied ************** */ if ( s->tryflips ) for ( flip=flip_x ; flip<=flip_xy; ++flip ) { int xsign = (flip&1) ? -1 : 1, ysign = (flip&2) ? -1 : 1; saw_sc_first = false; p_sp = s->endpoints ? path->first->next->to : path->first; first_of_path = true; for (sc_sp=sp; ; ) { if ( p_sp->next==NULL ) { if ( substring || sc_sp->next==NULL ) { s->matched_flip = flip; s->last_sp = saw_sc_first ? NULL : sp; return( true ); } else break; } np_sp = p_sp->next->to; if ( sc_sp->next==NULL ) break; nsc_sp = sc_sp->next->to; if ( first_of_path && s->endpoints ) { SplinePoint *sc_prevsp; /* if ( sc_sp->prev==NULL )*/ /* Already checked this above */ sc_prevsp = sc_sp->prev->from; if ( !p_sp->noprevcp ) { if ( !CoordMatches(sc_sp->prevcp.x-sc_sp->me.x,xsign*(p_sp->prevcp.x-p_sp->me.x),s) || !CoordMatches(sc_sp->prevcp.y-sc_sp->me.y,ysign*(p_sp->prevcp.y-p_sp->me.y),s) ) break; /* prev control points do not match, give up */ } else { sc_unit.x = sc_sp->me.x - sc_prevsp->me.x; sc_unit.y = sc_sp->me.y - sc_prevsp->me.y; len = sqrt(sc_unit.x*sc_unit.x + sc_unit.y*sc_unit.y ); sc_unit.x /= len; sc_unit.y /= len; if ( !RealNear(sc_unit.x,xsign * p_unit.x) || !RealNear(sc_unit.y,ysign*p_unit.y)) break; } first_of_path = false; } if ( np_sp->next==NULL && s->endpoints ) { SplinePoint *sc_nextsp; if ( sc_sp->next==NULL ) return( false ); sc_nextsp = sc_sp->next->to; if ( !p_sp->nonextcp ) { if ( !CoordMatches(sc_sp->nextcp.x-sc_sp->me.x,xsign*(p_sp->nextcp.x-p_sp->me.x),s) || !CoordMatches(sc_sp->nextcp.y-sc_sp->me.y,ysign*(p_sp->nextcp.y-p_sp->me.y),s) ) break; /* prev control points do not match, give up */ } else { if ( !sc_sp->nonextcp ) return( false ); sc_unit.x = sc_nextsp->me.x - sc_sp->me.x; sc_unit.y = sc_nextsp->me.y - sc_sp->me.y; len = sqrt(sc_unit.x*sc_unit.x + sc_unit.y*sc_unit.y ); if ( len==0 ) return( false ); sc_unit.x /= len; sc_unit.y /= len; if ( RealNear(sc_unit.x,xsign*pend_unit.x) && RealNear(sc_unit.y,ysign*pend_unit.y)) { s->matched_flip = flip; s->last_sp = saw_sc_first ? NULL : sp; return( true ); } else break; } } if ( !CoordMatches(sc_sp->nextcp.x-sc_sp->me.x,xsign*(p_sp->nextcp.x-p_sp->me.x),s) || !CoordMatches(sc_sp->nextcp.y-sc_sp->me.y,ysign*(p_sp->nextcp.y-p_sp->me.y),s) || !CoordMatches(nsc_sp->me.x-sc_sp->me.x,xsign*(np_sp->me.x-p_sp->me.x),s) || !CoordMatches(nsc_sp->me.y-sc_sp->me.y,ysign*(np_sp->me.y-p_sp->me.y),s) || !CoordMatches(nsc_sp->prevcp.x-nsc_sp->me.x,xsign*(np_sp->prevcp.x-np_sp->me.x),s) || !CoordMatches(nsc_sp->prevcp.y-nsc_sp->me.y,ysign*(np_sp->prevcp.y-np_sp->me.y),s) ) break; if ( np_sp==path->first ) { if ( nsc_sp==sp ) { s->matched_flip = flip; s->last_sp = saw_sc_first ? NULL : sp; return( true ); } else break; } sc_sp = nsc_sp; if ( sc_sp == sc_path_first ) saw_sc_first = true; p_sp = np_sp; } } /* ******* Match with rotate, scale and flip transformations applied ******** */ if ( s->tryrotate || s->tryscale ) { if ( s->tryflips ) flipmax = flip_xy; else flipmax = flip_none; for ( flip=flip_none ; flip<=flipmax; ++flip ) { p_sp = s->endpoints ? path->first->next->to : path->first; np_sp = p_sp->next->to; /* if p_sp->next were NULL, we'd have returned by now */ sc_sp = sp; if ( sc_sp->next==NULL ) return( false ); nsc_sp = sc_sp->next->to; if ( p_sp->me.x==np_sp->me.x && p_sp->me.y==np_sp->me.y ) return( false ); if ( sc_sp->me.x==nsc_sp->me.x && sc_sp->me.y==nsc_sp->me.y ) return( false ); if ( s->tryrotate && s->endpoints && np_sp->next == NULL ) { int xsign = (flip&1)?-1:1, ysign=(flip&2)?-1:1; if ( !p_sp->noprevcp ) { rot = atan2(xsign*(sc_sp->me.y-sc_sp->prevcp.y),ysign*(sc_sp->me.x-sc_sp->prevcp.x)) - atan2( p_sp->me.y- p_sp->prevcp.y, p_sp->me.x- p_sp->prevcp.x); } else { rot = atan2(xsign*(sc_unit.y),ysign*(sc_unit.x)) - atan2( p_unit.y, p_unit.x); } scale = 1; } else if ( s->endpoints && np_sp->next == NULL ) { return( false ); /* Not enough info to make a guess */ } else if ( !s->tryrotate ) { if ( p_sp->me.x==np_sp->me.x ) scale = (np_sp->me.y-p_sp->me.y) / (nsc_sp->me.y-sc_sp->me.y); else if ( p_sp->me.y==np_sp->me.y ) scale = (np_sp->me.x-p_sp->me.x) / (nsc_sp->me.x-sc_sp->me.x); else { real yscale = (np_sp->me.y-p_sp->me.y) / (nsc_sp->me.y-sc_sp->me.y); scale = (np_sp->me.x-p_sp->me.x) / (nsc_sp->me.x-sc_sp->me.x); if ( scale<.99*yscale || scale>1.01*yscale ) return( false ); } rot = 0; } else { int xsign = (flip&1)?-1:1, ysign=(flip&2)?-1:1; rot = atan2(xsign*(nsc_sp->me.y-sc_sp->me.y),ysign*(nsc_sp->me.x-sc_sp->me.x)) - atan2(np_sp->me.y-p_sp->me.y,np_sp->me.x-p_sp->me.x); if ( !s->tryscale ) scale = 1; else scale = sqrt( ((np_sp->me.y-p_sp->me.y)*(np_sp->me.y-p_sp->me.y) + (np_sp->me.x-p_sp->me.x)*(np_sp->me.x-p_sp->me.x))/ ((nsc_sp->me.y-sc_sp->me.y)*(nsc_sp->me.y-sc_sp->me.y) + (nsc_sp->me.x-sc_sp->me.x)*(nsc_sp->me.x-sc_sp->me.x)) ); } if ( scale>-.00001 && scale<.00001 ) return( false ); s->matched_rot = rot; if ( rot==0 ) s->matched_co=1,s->matched_si=0; else if ( rot>3.14159 && rot<3.141595 ) s->matched_co=-1,s->matched_si=0; else if ( rot>1.570793 && rot<1.570799 ) s->matched_co=0,s->matched_si=1; else if ( (rot>4.712386 && rot<4.712392 ) || (rot<-1.570793 && rot>-1.570799 ) ) s->matched_co=0,s->matched_si=-1; else s->matched_co = cos(rot), s->matched_si = sin(rot); saw_sc_first = false; first_of_path = true; for (sc_sp=sp ; ; ) { if ( p_sp->next==NULL ) { if ( substring || sc_sp->next==NULL ) { s->matched_flip = flip; s->matched_rot = rot; s->matched_scale = scale; s->last_sp = saw_sc_first ? NULL : sp; return( true ); } else return( false ); } np_sp = p_sp->next->to; if ( sc_sp->next==NULL ) return( false ); nsc_sp = sc_sp->next->to; if ( first_of_path && s->endpoints ) { SplinePoint *sc_prevsp; /* if ( sc_sp->prev==NULL )*/ /* Already checked this above */ sc_prevsp = sc_sp->prev->from; if ( !p_sp->noprevcp ) { if ( !BPMatches(&sc_sp->prevcp,&sc_sp->me,&p_sp->prevcp,&p_sp->me,flip,rot,scale,s) ) break; } else { sc_unit.x = sc_sp->me.x - sc_prevsp->me.x; sc_unit.y = sc_sp->me.y - sc_prevsp->me.y; len = sqrt(sc_unit.x*sc_unit.x + sc_unit.y*sc_unit.y ); sc_unit.x /= len; sc_unit.y /= len; temp = sc_unit.x * s->matched_co + sc_unit.y * s->matched_si; sc_unit.y = -sc_unit.x * s->matched_si + sc_unit.y * s->matched_co; sc_unit.x = temp; if ( !RealNear(sc_unit.x,p_unit.x) || !RealNear(sc_unit.y,p_unit.y)) break; } first_of_path = false; } if ( np_sp->next==NULL && s->endpoints ) { SplinePoint *sc_nextsp; if ( sc_sp->next==NULL ) return( false ); sc_nextsp = sc_sp->next->to; if ( !p_sp->nonextcp ) { if ( !BPMatches(&sc_sp->nextcp,&sc_sp->me,&p_sp->nextcp,&p_sp->me,flip,rot,scale,s) ) break; } else { if ( !sc_sp->nonextcp ) return( false ); sc_unit.x = sc_nextsp->me.x - sc_sp->me.x; sc_unit.y = sc_nextsp->me.y - sc_sp->me.y; len = sqrt(sc_unit.x*sc_unit.x + sc_unit.y*sc_unit.y ); if ( len==0 ) return( false ); sc_unit.x /= len; sc_unit.y /= len; temp = sc_unit.x * s->matched_co + sc_unit.y * s->matched_si; sc_unit.y = -sc_unit.x * s->matched_si + sc_unit.y * s->matched_co; sc_unit.x = temp; if ( RealNear(sc_unit.x,pend_unit.x) && RealNear(sc_unit.y,pend_unit.y)) { s->matched_flip = flip; s->matched_rot = rot; s->matched_scale = scale; s->last_sp = saw_sc_first ? NULL : sp; return( true ); } else break; } } if ( !BPMatches(&sc_sp->nextcp,&sc_sp->me,&p_sp->nextcp,&p_sp->me,flip,rot,scale,s) || !BPMatches(&nsc_sp->me,&sc_sp->me,&np_sp->me,&p_sp->me,flip,rot,scale,s) || !BPMatches(&nsc_sp->prevcp,&nsc_sp->me,&np_sp->prevcp,&np_sp->me,flip,rot,scale,s) ) return( false ); if ( np_sp==path->first ) { if ( nsc_sp==sp ) { s->matched_flip = flip; s->matched_rot = rot; s->matched_scale = scale; s->last_sp = saw_sc_first ? NULL : sp; return( true ); } else return( false ); } sc_sp = nsc_sp; if ( sc_sp == sc_path_first ) saw_sc_first = true; p_sp = np_sp; } } } return( false ); }