/* count */
len= 0;
a= nu->pntsu-1;
- if(nu->flagu & 1) a++;
+ if(nu->flagu & CU_CYCLIC) a++;
prevbezt= nu->bezt;
bezt= prevbezt+1;
while(a--) {
- if(a==0 && (nu->flagu & 1)) bezt= nu->bezt;
+ if(a==0 && (nu->flagu & CU_CYCLIC)) bezt= nu->bezt;
if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) len++;
else len+= resolu;
- if(a==0 && (nu->flagu & 1)==0) len++;
+ if(a==0 && (nu->flagu & CU_CYCLIC)==0) len++;
prevbezt= bezt;
bezt++;
}
}
+/* calculates a bevel width (radius) for a particular subdivided curve part,
+ * based on the radius value of the surrounding CVs */
+static float calc_manual_taper(Curve *cu, Nurb *nu, int cursubdiv)
+{
+ BezTriple *bezt, *beztfirst, *beztlast, *beztnext, *beztprev;
+ BPoint *bp, *bpfirst, *bplast;
+ int resolu;
+ float prevrad=0.0, nextrad=0.0, rad=0.0, ratio=0.0;
+ int vectseg=0, subdivs=0;
+
+ if((nu==NULL) || (nu->pntsu<=1)) return 1.0;
+ bezt= nu->bezt;
+ bp = nu->bp;
+
+ if(G.rendering && cu->resolu_ren!=0) resolu= cu->resolu_ren;
+ else resolu= nu->resolu;
+
+ if(((nu->type & 7)==CU_BEZIER) && (bezt != NULL)) {
+ beztfirst = nu->bezt;
+ beztlast = nu->bezt + (nu->pntsu - 1);
+
+ /* loop through the CVs to end up with a pointer to the CV before the subdiv in question, and a ratio
+ * of how far that subdiv is between this CV and the next */
+ while(bezt<=beztlast) {
+ beztnext = bezt+1;
+ beztprev = bezt-1;
+ vectseg=0;
+
+ if (subdivs==cursubdiv) {
+ ratio= 0.0;
+ break;
+ }
+
+ /* check to see if we're looking at a vector segment (no subdivisions) */
+ if (nu->flagu & CU_CYCLIC) {
+ if (bezt == beztfirst) {
+ if ((beztlast->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1;
+ } else {
+ if ((beztprev->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1;
+ }
+ } else if ((bezt->h2==HD_VECT) && (beztnext->h1==HD_VECT)) vectseg = 1;
+
+
+ if (vectseg==0) {
+ /* if it's NOT a vector segment, check to see if the subdiv falls within the segment */
+ subdivs += resolu;
+
+ if (cursubdiv < subdivs) {
+ ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu);
+ break;
+ }
+ } else {
+ /* must be a vector segment.. loop again! */
+ subdivs += 1;
+ }
+
+ bezt++;
+ }
+
+ /* Now we have a nice bezt pointer to the CV that we want. But cyclic messes it up, so must correct for that..
+ * (cyclic goes last-> first -> first+1 -> first+2 -> ...) */
+ if (nu->flagu & CU_CYCLIC) {
+ if (bezt == beztfirst) bezt = beztlast;
+ else bezt--;
+ }
+
+ /* find the radii at the bounding CVs and interpolate between them based on ratio */
+ rad = prevrad = bezt->radius;
+
+ if ((bezt == beztlast) && (nu->flagu & CU_CYCLIC)) { /* loop around */
+ bezt= beztfirst;
+ } else if (bezt != beztlast) {
+ bezt++;
+ }
+ nextrad = bezt->radius;
+
+ }
+ else if( ( ((nu->type & 7)==CU_NURBS) || ((nu->type & 7)==CU_POLY)) && (bp != NULL)) {
+ /* follows similar algo as for bezt above */
+ bpfirst = nu->bp;
+ bplast = nu->bp + (nu->pntsu - 1);
+
+ if ((nu->type & 7)==CU_POLY) resolu=1;
+
+ while(bp<=bplast) {
+ if (subdivs==cursubdiv) {
+ ratio= 0.0;
+ break;
+ }
+
+ subdivs += resolu;
+
+ if (cursubdiv < subdivs) {
+ ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu);
+ break;
+ }
+
+ bp++;
+ }
+
+ if ( ((nu->type & 7)==CU_NURBS) && (nu->flagu & CU_CYCLIC)) {
+ if (bp == bplast) bp = bpfirst;
+ else bp++;
+ }
+
+ rad = prevrad = bp->radius;
+
+ if ((bp == bplast) && (nu->flagu & CU_CYCLIC)) { /* loop around */
+ bp= bpfirst;
+ } else if (bp != bplast) {
+ bp++;
+ }
+ nextrad = bp->radius;
+
+ }
+
+
+ if (nextrad != prevrad) {
+ /* smooth interpolation */
+ rad = prevrad + (nextrad-prevrad)*(3.0f*ratio*ratio - 2.0f*ratio*ratio*ratio);
+ }
+
+ if (rad > 0.0)
+ return rad;
+ else
+ return 1.0;
+}
/* taper rules:
- only 1 curve
makeBevelList(ob);
- /* If curve has no bevel will return nothing */
+ /* If curve has no bevel will return nothing */
makebevelcurve(ob, &dlbev);
/* no bevel or extrude, and no width correction? */
/* for each point of poly make a bevel piece */
bevp= (BevPoint *)(bl+1);
for(a=0; a<bl->nr; a++,bevp++) {
- float fac = calc_taper(cu->taperobj, a, bl->nr);
+ float fac;
+ if (cu->taperobj==NULL) {
+ fac = calc_manual_taper(cu, nu, a);
+ } else {
+ fac = calc_taper(cu->taperobj, a, bl->nr);
+ }
if (bevp->f1) {
dl->bevelSplitFlag[a>>5] |= 1<<(a&0x1F);
#define TFM_MIRROR 14
#define TFM_BONESIZE 15
#define TFM_BONE_ENVELOPE 16
+#define TFM_CURVE_SHRINKFATTEN 17
/* TRANSFORM CONTEXTS */
#define CTX_NONE 0
void initTilt(TransInfo *t);
int Tilt(TransInfo *t, short mval[2]);
+void initCurveShrinkFatten(TransInfo *t);
+int CurveShrinkFatten(TransInfo *t, short mval[2]);
+
void initTrackball(TransInfo *t);
int Trackball(TransInfo *t, short mval[2]);
*/
typedef struct BezTriple {
float vec[3][3];
- float alfa, weight, pad;
+ float alfa, weight, radius; /* alfa: tilt in 3D View, weight: used for softbody goal weight, radius: for bevel tapering */
short h1, h2;
char f1, f2, f3, hide;
} BezTriple;
/* note; alfa location in struct is abused by Key system */
typedef struct BPoint {
float vec[4];
- float alfa, weight;
+ float alfa, weight; /* alfa: tilt in 3D View, weight: used for softbody goal weight */
short f1, hide;
+ float radius, pad; /* user-set radius per point for bevelling etc */
} BPoint;
typedef struct Nurb {
- struct Nurb *next, *prev;
+ struct Nurb *next, *prev; /* multiple nurbs per curve object are allowed */
short type;
- short mat_nr; /* index into material list */
+ short mat_nr; /* index into material list */
short hide, flag;
- short pntsu, pntsv;
- short resolu, resolv;
+ short pntsu, pntsv; /* number of points in the U or V directions */
+ short resolu, resolv; /* tesselation resolution in the U or V directions */
short orderu, orderv;
short flagu, flagv;
uiDefButF(block, NUM, B_MAKEDISP, "Width:", 760,90,150,19, &cu->width, 0.0, 2.0, 1, 0, "Make interpolated result thinner or fatter");
uiDefButF(block, NUM, B_MAKEDISP, "Extrude:", 760,70,150,19, &cu->ext1, 0.0, 5.0, 10, 0, "Curve extrusion size when not using a bevel object");
uiDefButF(block, NUM, B_MAKEDISP, "Bevel Depth:", 760,50,150,19, &cu->ext2, 0.0, 2.0, 1, 0, "Bevel depth when not using a bevel object");
- uiDefButS(block, NUM, B_MAKEDISP, "BevResol:", 760,30,150,19, &cu->bevresol, 0.0, 10.0, 0, 0, "Bevel resolution when depth is non-zero and not using a bevel object");
+ uiDefButS(block, NUM, B_MAKEDISP, "BevResol:", 760,30,150,19, &cu->bevresol, 0.0, 32.0, 0, 0, "Bevel resolution when depth is non-zero and not using a bevel object");
uiDefIDPoinBut(block, test_obcurpoin_but, ID_OB, B_CHANGEDEP, "BevOb:", 760,10,150,19, &cu->bevobj, "Curve object name that defines the bevel shape");
uiDefIDPoinBut(block, test_obcurpoin_but, ID_OB, B_CHANGEDEP, "TaperOb:", 760,-10,150,19, &cu->taperobj, "Curve object name that defines the taper (width)");
nu= editNurb.first;
while(nu) {
- if((nu->type & 7)==1) {
+ if((nu->type & 7)==CU_BEZIER) {
bezt= nu->bezt;
a= nu->pntsu;
while(a--) {
uiDefButF(block, NUM, REDRAWVIEW3D, "X Offset:", 0, 6, 140, 19, &vd->bgpic->xof, -250.0*vd->grid,250.0*vd->grid, 10, 2, "Set the horizontal offset of the background image");
uiDefButF(block, NUM, REDRAWVIEW3D, "Y Offset:", 150, 6, 140, 19, &vd->bgpic->yof, -250.0*vd->grid,250.0*vd->grid, 10, 2, "Set the vertical offset of the background image");
-
-
- // uiDefButF(block, NUM, REDRAWVIEW3D, "Size:", 160,160,150,20, &vd->bgpic->size, 0.1, 250.0, 100, 0, "Set the size for the width of the BackGroundPic");
-
-
-
-// uiDefButF(block, NUMSLI, B_BLENDBGPIC, "Blend:", 120,100,190,20,&vd->bgpic->blend, 0.0,1.0, 0, 0, "Set the BackGroundPic transparency");
-
-// uiDefButF(block, NUM, B_DIFF, "Center X: ", 10,70,140,20,&vd->bgpic->xof, -20.0,20.0, 10, 2, "Set the BackGroundPic X Offset");
-// uiDefButF(block, NUM, B_DIFF, "Center Y: ", 160,70,140,20,&vd->bgpic->yof, -20.0,20.0, 10, 2, "Set the BackGroundPic Y Offset");
-
}
}
if(a==0 && (nu->flagu & 1)) {VECCOPY(beztnew->vec[0], vec+6);}
else {VECCOPY(bezt->vec[0], vec+6);}
+ beztn->radius = (prevbezt->radius + bezt->radius)/2.0f;
+ beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
+
beztn++;
}
VECCOPY(bezt->vec[1], bp->vec);
bezt->f1=bezt->f2=bezt->f3= bp->f1;
bezt->h1= bezt->h2= HD_VECT;
+ bezt->weight= bp->weight;
+ bezt->radius= bp->radius;
bp++;
bezt++;
}
bp->vec[3]= 1.0;
bp->f1= bezt->f2;
nr-= 2;
+ bp->radius= bezt->radius;
+ bp->weight= bezt->weight;
bp++;
}
else {
if(c==0) bp->f1= bezt->f1;
else if(c==1) bp->f1= bezt->f2;
else bp->f1= bezt->f3;
+ bp->radius= bezt->radius;
+ bp->weight= bezt->weight;
bp++;
}
}
bp++;
VECCOPY(bezt->vec[2], bp->vec);
bezt->f3= bp->f1;
+ bezt->radius= bp->radius;
+ bezt->weight= bp->weight;
bp++;
bezt++;
}
bp= nu->bp;
while(a--) {
if( bp->f1 & 1 ) {
- if(nu->flagu & 1) nu->flagu--;
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
else nu->flagu++;
break;
}
bezt= nu->bezt;
while(a--) {
if( BEZSELECTED(bezt) ) {
- if(nu->flagu & 1) nu->flagu--;
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
else nu->flagu++;
break;
}
bp= nu->bp;
while(a--) {
if( bp->f1 & 1 ) {
- if(nu->flagu & 1) nu->flagu--;
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
else {
nu->flagu++;
nu->flagu &= ~2; /* endpoint flag, fixme */
if( bp->f1 & 1) {
if(cyclmode==1 && nu->pntsu>1) {
- if(nu->flagu & 1) nu->flagu--;
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
else {
nu->flagu++;
fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN");
bezt= nu->bezt;
bezt->h1= bezt->h2= HD_ALIGN;
bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->radius = 1.0;
for(a=0;a<3;a++) {
VECCOPY(bezt->vec[a], cent);
bezt++;
bezt->h1= bezt->h2= HD_ALIGN;
bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->radius = bezt->weight = 1.0;
for(a=0;a<3;a++) {
VECCOPY(bezt->vec[a], cent);
VECCOPY(bp->vec, cent);
bp->vec[3]= 1.0;
bp->f1= 1;
+ bp->radius = bp->weight = 1.0;
}
bp= nu->bp;
}
break;
- case 6: /* 5 point pad */
+ case 6: /* 5 point path */
nu->pntsu= 5;
nu->pntsv= 1;
nu->orderu= 5;
VECCOPY(bp->vec, cent);
bp->vec[3]= 1.0;
bp->f1= 1;
+ bp->radius = bp->weight = 1.0;
}
bp= nu->bp;
bezt->f1= bezt->f2= bezt->f3= 1;
bezt->vec[1][0]+= -G.vd->grid;
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
-
+ bezt->radius = bezt->weight = 1.0;
+
bezt++;
for(a=0;a<3;a++) {
VECCOPY(bezt->vec[a], cent);
bezt->f1= bezt->f2= bezt->f3= 1;
bezt->vec[1][1]+= G.vd->grid;
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
+ bezt->radius = bezt->weight = 1.0;
bezt++;
for(a=0;a<3;a++) {
bezt->f1= bezt->f2= bezt->f3= 1;
bezt->vec[1][0]+= G.vd->grid;
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
+ bezt->radius = bezt->weight = 1.0;
bezt++;
for(a=0;a<3;a++) {
bezt->f1= bezt->f2= bezt->f3= 1;
bezt->vec[1][1]+= -G.vd->grid;
for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
+ bezt->radius = bezt->weight = 1.0;
calchandlesNurb(nu);
}
if(a & 1) bp->vec[3]= 0.25*sqrt(2.0);
else bp->vec[3]= 1.0;
Mat3MulVecfl(imat,bp->vec);
+ bp->radius = bp->weight = 1.0;
+
bp++;
}
}
else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
- nr= pupmenu("Specials%t|Subdivide%x1|Switch Direction%x2|Set Goal Weight %x3");
+ nr= pupmenu("Specials%t|Subdivide%x1|Switch Direction%x2|Set Goal Weight %x3|Set Radius %x4");
switch(nr) {
case 1:
}
}
break;
+ case 4:
+ {
+ static float radius= 1.0f;
+ extern ListBase editNurb;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if(fbutton(&radius, 0.0001f, 10.0f, 10, 10, "Set Radius")) {
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(nu->bezt) {
+ for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
+ if(bezt->f2 & SELECT)
+ bezt->radius= radius;
+ }
+ }
+ else if(nu->bp) {
+ for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
+ if(bp->f1 & SELECT)
+ bp->radius= radius;
+ }
+ }
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+
+ }
+ break;
}
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
if(G.obedit->type==OB_ARMATURE) {
initTransform(TFM_BONESIZE, CTX_NONE);
}
- else
+ else if (G.obedit->type==OB_CURVE) {
+ initTransform(TFM_CURVE_SHRINKFATTEN, CTX_NONE);
+ } else {
initTransform(TFM_SHRINKFATTEN, CTX_NONE);
+ }
Transform();
}
else if(G.qual==LR_CTRLKEY) {
case TFM_TILT:
initTilt(&Trans);
break;
+ case TFM_CURVE_SHRINKFATTEN:
+ initCurveShrinkFatten(&Trans);
+ break;
case TFM_TRACKBALL:
initTrackball(&Trans);
break;
return 1;
}
+
+/* ******************** Curve Shrink/Fatten *************** */
+
+int CurveShrinkFatten(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ float ratio;
+ int i;
+ char str[50];
+
+ if(t->flag & T_SHIFT_MOD) {
+ /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+ float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+ float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+
+ dx= (float)(t->center2d[0] - mval[0]);
+ dy= (float)(t->center2d[1] - mval[1]);
+ ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+
+ }
+ else {
+ float dx= (float)(t->center2d[0] - mval[0]);
+ float dy= (float)(t->center2d[1] - mval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+ }
+
+ snapGrid(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+ sprintf(str, "Shrink/Fatten: %s", c);
+ }
+ else {
+ sprintf(str, "Shrink/Fatten: %3f", ratio);
+ }
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if(td->val) {
+ //*td->val= ratio;
+ *td->val= td->ival*ratio;
+ if (*td->val <= 0.0f) *td->val = 0.0001f;
+ }
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+void initCurveShrinkFatten(TransInfo *t)
+{
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+ t->transform = CurveShrinkFatten;
+ t->fac = (float)sqrt( (
+ ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+ +
+ ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+ ) );
+}
+
/* ************************** PUSH/PULL *************************** */
void initPushPull(TransInfo *t)
else td->flag= 0;
td->ext = NULL;
td->tdi = NULL;
- td->val = &(bezt->alfa);
- td->ival = bezt->alfa;
+
+ if (t->mode==TFM_CURVE_SHRINKFATTEN) {
+ td->val = &(bezt->radius);
+ td->ival = bezt->radius;
+ } else {
+ td->val = &(bezt->alfa);
+ td->ival = bezt->alfa;
+ }
Mat3CpyMat3(td->smtx, smtx);
Mat3CpyMat3(td->mtx, mtx);
else td->flag= 0;
td->ext = NULL;
td->tdi = NULL;
- td->val = &(bp->alfa);
- td->ival = bp->alfa;
+
+ if (t->mode==TFM_CURVE_SHRINKFATTEN) {
+ td->val = &(bp->radius);
+ td->ival = bp->radius;
+ } else {
+ td->val = &(bp->alfa);
+ td->ival = bp->alfa;
+ }
Mat3CpyMat3(td->smtx, smtx);
Mat3CpyMat3(td->mtx, mtx);
case TFM_SHEAR:
case TFM_CREASE:
case TFM_BONE_ENVELOPE:
+ case TFM_CURVE_SHRINKFATTEN:
t->flag |= T_NO_CONSTRAINT;
break;
}
if(t->mode==TFM_ROTATION || t->mode==TFM_WARP || t->mode==TFM_TILT || t->mode==TFM_TRACKBALL)
invert = U.flag & USER_AUTOROTGRID;
- else if(t->mode==TFM_RESIZE || t->mode==TFM_SHEAR || t->mode==TFM_BONESIZE || t->mode==TFM_SHRINKFATTEN)
+ else if(t->mode==TFM_RESIZE || t->mode==TFM_SHEAR || t->mode==TFM_BONESIZE || t->mode==TFM_SHRINKFATTEN || t->mode==TFM_CURVE_SHRINKFATTEN)
invert = U.flag & USER_AUTOSIZEGRID;
else
invert = U.flag & USER_AUTOGRABGRID;