static void CVMouseMoveSpiroPoint(CharView *cv, PressedOn *p) { spiro_cp *active = cv->active_cp, *merge = p->spiro; SplineSet *activess = cv->active_spl; int active_index; if ( active==NULL ) return; if ( cv->info.x==active->x && cv->info.y==active->y ) return; if ( !cv->recentchange ) CVPreserveState(&cv->b); active->x = cv->info.x; active->y = cv->info.y; CVSetCharChanged(cv,true); active_index = active-activess->spiros; if ( active!=merge && merge!=NULL && p->spl!=NULL && SPIRO_SPL_OPEN(activess) && SPIRO_SPL_OPEN(p->spl) && (active_index==0 || active_index==activess->spiro_cnt-2) && ((merge-p->spl->spiros)==0 || (merge-p->spl->spiros)==p->spl->spiro_cnt-2) ) { SplinePoint *activesp = active_index==0 ? activess->first : activess->last; SplinePoint *mergesp = (merge-p->spl->spiros)==0 ? p->spl->first : p->spl->last; CVMergeSplineSets(cv,activesp,activess,mergesp,p->spl); } SSRegenerateFromSpiros(activess); SCUpdateAll(cv->b.sc); }
/** * Exactly like _SpiroCP2SplineSet except that if the Spiro path fails * to converge, it will not return NULL. The resulting Bezier curve will be * the same as that generated by SSRegenerateFromSpiros (the return value of * _SpiroCP2SplineSet, or otherwise a set of straight lines between the * Spiro points when it fails to converge). * * @param [in] spiros The spiro list. This result is stored in the returned * value (`ss->spiros`) and should not be freed. * @return The spline point list. */ SplineSet *SpiroCP2SplineSet(spiro_cp *spiros) { SplineSet *ss = calloc(1, sizeof(SplineSet)); int n; for (n = 0; spiros[n].ty != SPIRO_END; n++) /* Pass */; ss->spiros = spiros; ss->spiro_cnt = ss->spiro_max = n+1; SSRegenerateFromSpiros(ss); return ss; }
static void CVMouseDownSpiroPoint(CharView *cv, GEvent *event) { SplineSet *sel, *ss; SplineChar *sc = cv->b.sc; spiro_cp *base, *cp; int base_index, cp_index, i; char ty = (cv->active_tool==cvt_curve?SPIRO_G4: cv->active_tool==cvt_hvcurve?SPIRO_G2: cv->active_tool==cvt_corner?SPIRO_CORNER: cv->active_tool==cvt_tangent?SPIRO_LEFT: /*cv->active_tool==cvt_pen?*/SPIRO_RIGHT); cv->active_spl = NULL; cv->active_sp = NULL; sel = CVAnySelPointList(cv); if ( sel!=NULL ) { if ( SPIRO_SELECTED(&sel->spiros[0]) ) base_index = 0; else base_index = sel->spiro_cnt-2; base = &sel->spiros[base_index]; if ( base==cv->p.spiro ) return; /* We clicked on the active point, that's a no-op */ } CVPreserveState(&cv->b); CVClearSel(cv); if ( sel!=NULL ) { if ( (cp = cv->p.spiro)!=NULL ) cp_index = cp-cv->p.spl->spiros; cv->lastselcp = base; ss = sel; if ( base_index!=sel->spiro_cnt-2 ) { SplineSetReverse(sel); base = &sel->spiros[sel->spiro_cnt-2]; if ( cv->p.spl==sel ) { cp_index = sel->spiro_cnt-2-cp_index; cp = &sel->spiros[cp_index]; } } if ( cp==NULL || (cp_index!=0 && cp_index!=cv->p.spl->spiro_cnt-2) || cp==base || !SPIRO_SPL_OPEN(cv->p.spl)) { /* Add a new point */ if ( sel->spiro_cnt>=sel->spiro_max ) sel->spiros = realloc(sel->spiros,(sel->spiro_max += 10)*sizeof(spiro_cp)); cp = &sel->spiros[sel->spiro_cnt-1]; cp[1] = cp[0]; /* Move the final 'z' */ cp->x = cv->p.cx; cp->y = cv->p.cy; cp->ty = ty; SPIRO_DESELECT(cp-1); ++sel->spiro_cnt; } else if ( cv->p.spl==sel ) { /* Close the current spline set */ sel->spiros[0].ty = ty; cv->joinvalid = true; cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp); } else { /* Merge two spline sets */ SplinePoint *sp = cp_index==0 ? cv->p.spl->first : cv->p.spl->last; SplinePoint *basesp = base_index==0 ? sel->first : sel->last; cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp); CVMergeSPLS(cv,ss,basesp,sp); } } else if ( cv->p.spline!=NULL ) { /* Add an intermediate point on an already existing spline */ ss = cv->p.spl; if ( ss->spiro_cnt>=ss->spiro_max ) ss->spiros = realloc(ss->spiros,(ss->spiro_max += 10)*sizeof(spiro_cp)); for ( i=ss->spiro_cnt-1; i>cv->p.spiro_index; --i ) ss->spiros[i+1] = ss->spiros[i]; ++ss->spiro_cnt; cp = &ss->spiros[cv->p.spiro_index+1]; cp->x = cv->p.cx; cp->y = cv->p.cy; cp->ty = ty; ss = cv->p.spl; cv->joinvalid = true; cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp); } else { /* A new point on a new (open) contour */ ss = chunkalloc(sizeof(SplineSet)); ss->next = cv->b.layerheads[cv->b.drawmode]->splines; cv->b.layerheads[cv->b.drawmode]->splines = ss; ss->spiros = malloc((ss->spiro_max=10)*sizeof(spiro_cp)); cp = &ss->spiros[0]; cp->x = cv->p.cx; cp->y = cv->p.cy; cp->ty = SPIRO_OPEN_CONTOUR; cp[1].x = cp[1].y = 0; cp[1].ty = 'z'; ss->spiro_cnt = 2; } SPIRO_SELECT(cp); SSRegenerateFromSpiros(ss); cv->active_spl = ss; cv->active_cp = cp; CVSetCharChanged(cv,true); CVInfoDraw(cv,cv->gw); SCUpdateAll(sc); }
void CVMouseUpKnife(CharView *cv, GEvent *event) { #if !defined(KNIFE_CONTINUOUS) /* draw a line from (cv->p.cx,cv->p.cy) to (cv->info.x,cv->info.y) */ /* and cut anything intersected by it */ SplineSet *spl, *spl2; Spline *s, *nexts; Spline dummy; SplinePoint dummyfrom, dummyto, *mid, *mid2; BasePoint inters[9]; extended t1s[10], t2s[10]; int foundsomething = true, ever = false; int i; int spiro_index = 0; memset(&dummy,0,sizeof(dummy)); memset(&dummyfrom,0,sizeof(dummyfrom)); memset(&dummyto,0,sizeof(dummyto)); dummyfrom.me.x = cv->p.cx; dummyfrom.me.y = cv->p.cy; dummyto.me.x = cv->info.x; dummyto.me.y = cv->info.y; dummyfrom.nextcp = dummyfrom.prevcp = dummyfrom.me; dummyto.nextcp = dummyto.prevcp = dummyto.me; dummyfrom.nonextcp = dummyfrom.noprevcp = dummyto.nonextcp = dummyto.noprevcp = true; dummy.splines[0].d = cv->p.cx; dummy.splines[0].c = cv->info.x-cv->p.cx; dummy.splines[1].d = cv->p.cy; dummy.splines[1].c = cv->info.y-cv->p.cy; dummy.from = &dummyfrom; dummy.to = &dummyto; dummy.islinear = dummy.knownlinear = true; dummyfrom.next = dummyto.prev = &dummy; for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) spl->ticked = false; while ( foundsomething ) { foundsomething = false; for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL && !foundsomething; spl = spl->next ) { for ( s = spl->first->next; s!=NULL ; ) { nexts = NULL; if ( s->to!=spl->first ) nexts = s->to->next; if ( SplinesIntersect(s,&dummy,inters,t1s,t2s)>0 ) { if ( event->u.mouse.state&ksm_meta ) { for ( i=0; i<4 && t1s[i]!=-1 && (t1s[i]<.0001 || t1s[i]>1-.0001); ++i ); if ( i<4 && t1s[i]!=-1 ) { /* With meta down we just remove the spline rather than */ /* cutting it */ foundsomething = true; nexts = NULL; if ( !ever ) CVPreserveState(&cv->b); ever = true; if ( spl->first==spl->last ) { spl->first = s->to; spl->last = s->from; } else { spl2 = chunkalloc(sizeof(SplineSet)); spl2->next = spl->next; spl->next = spl2; spl2->first = s->to; spl2->last = spl->last; spl->last = s->from; } s->to->prev = s->from->next = NULL; SplineFree(s); SplineSetSpirosClear(spl); } } else { for ( i=0; i<4 && t1s[i]!=-1 && (( t1s[i]<.001 && s->from->prev==NULL ) || ( t1s[i]>1-.001 && s->to->next == NULL )); ++i ); if ( i<4 && t1s[i]!=-1 ) { foundsomething = true; nexts = NULL; if ( !ever ) CVPreserveState(&cv->b); ever = true; spiro_index = -1; if ( cv->b.sc->inspiro && hasspiro()) { if ( spl->spiro_cnt!=0 ) spiro_index = SplineT2SpiroIndex(s,t1s[i],spl); } else SplineSetSpirosClear(spl); if ( t1s[i]<.001 ) { mid = s->from; } else if ( t1s[i]>1-.001 ) { mid = s->to; } else mid = SplineBisect(s,t1s[i]); /* if the intersection is close to an end point */ /* cut at the end point, else break in the middle */ /* Cut here, and then */ /* start all over again (we may need to alter the */ /* splineset structure so drastically that we just */ /* can't continue these loops) */ mid->pointtype = pt_corner; mid2 = chunkalloc(sizeof(SplinePoint)); *mid2 = *mid; mid2->hintmask = NULL; mid->next = NULL; mid2->prev = NULL; mid2->next->from = mid2; spl->ticked = true; if ( spl->first==spl->last ) { spl->first = mid2; spl->last = mid; if ( spiro_index!=-1 ) ReorderSpirosAndAddAndCut(spl,spiro_index); } else { spl2 = chunkalloc(sizeof(SplineSet)); spl2->next = spl->next; spl->next = spl2; spl2->first = mid2; spl2->last = spl->last; spl->last = mid; if ( spiro_index!=-1 ) SplitSpirosAndAddAndCut(spl,spl2,spiro_index); spl2->ticked = true; } } } } s = nexts; } } } if ( ever ) { for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) { if ( spl->ticked && spl->spiros!=NULL && cv->b.sc->inspiro && hasspiro()) SSRegenerateFromSpiros(spl); spl->ticked = false; } CVCharChangedUpdate(&cv->b); } #endif }