Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-09-05 13:54:01 +0400
committerCampbell Barton <ideasman42@gmail.com>2009-09-05 13:54:01 +0400
commit3b743ac5565663d2fd0be4bbbc92e404afafbce4 (patch)
treeb9091982dc98ee28d609dc249381fa1e6ce79f08 /source/blender
parent959757c2d7bdfe7955e2c645a511ac450a607c47 (diff)
Option to correct for 3D curve twist error. example before and after.
http://www.graphicall.org/ftp/ideasman42/curve_auto_twist.png Access next to the "3D" edit button. details... - open curves use the first points orientation and minimize twist for each new segment. - cyclic curves calculate the least twist in both directions and blend between them - AxisAngleToQuat replaced inline code. - Notice the model on the right now has more even corners. added Vec3ToTangent to arithb.c.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/intern/curve.c172
-rw-r--r--source/blender/blenlib/BLI_arithb.h1
-rw-r--r--source/blender/blenlib/intern/arithb.c13
-rw-r--r--source/blender/makesdna/DNA_curve_types.h2
-rw-r--r--source/blender/src/buttons_editing.c3
5 files changed, 156 insertions, 35 deletions
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 0d6382a8d37..709507a9b26 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1513,7 +1513,7 @@ void makeBevelList(Object *ob)
BPoint *bp;
BevList *bl, *blnew, *blnext;
BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
- float min, inp, x1, x2, y1, y2, vec[3];
+ float min, inp, x1, x2, y1, y2, vec[3], vec_prev[3], q[4], quat[4], quat_prev[4], cross[3];
float *coord_array, *tilt_array=NULL, *radius_array=NULL, *coord_fp, *tilt_fp=NULL, *radius_fp=NULL;
float *v1, *v2;
struct bevelsort *sortdata, *sd, *sd1;
@@ -1872,7 +1872,10 @@ void makeBevelList(Object *ob)
bl= cu->bev.first;
while(bl) {
- if(bl->nr==2) { /* 2 pnt, treat separate */
+ if(bl->nr < 2) {
+ /* do nothing */
+ }
+ else if(bl->nr==2) { /* 2 pnt, treat separate */
bevp2= (BevPoint *)(bl+1);
bevp1= bevp2+1;
@@ -1886,68 +1889,169 @@ void makeBevelList(Object *ob)
if(cu->flag & CU_3D) { /* 3D */
float quat[4], q[4];
- vec[0]= bevp1->x - bevp2->x;
- vec[1]= bevp1->y - bevp2->y;
- vec[2]= bevp1->z - bevp2->z;
+ VecSubf(vec, &bevp1->x, &bevp2->x);
vectoquat(vec, 5, 1, quat);
- Normalize(vec);
- q[0]= (float)cos(0.5*bevp1->alfa);
- x1= (float)sin(0.5*bevp1->alfa);
- q[1]= x1*vec[0];
- q[2]= x1*vec[1];
- q[3]= x1*vec[2];
+ AxisAngleToQuat(q, vec, bevp1->alfa);
QuatMul(quat, q, quat);
QuatToMat3(quat, bevp1->mat);
Mat3CpyMat3(bevp2->mat, bevp1->mat);
}
+ } /* this has to be >2 points */
+ else if(cu->flag & CU_NO_TWIST && cu->flag & CU_3D && bl->poly != -1) {
+
+ /* Special case, cyclic curve with no twisy. tricky... */
+
+ float quat[4], q[4], cross[3];
+
+ /* correcting a cyclic curve is more complicated, need to be corrected from both ends */
+ float *quat_tmp1, *quat_tmp2; /* store a quat in the matrix temporarily */
+ int iter_dir;
+ BevPoint *bevp_start= (BevPoint *)(bl+1);
+
+ /* loop over the points twice, once up, once back, accumulate the quat rotations
+ * in both directions, then blend them in the 3rd loop and apply the tilt */
+ for(iter_dir = 0; iter_dir < 2; iter_dir++) {
+
+ bevp2= (BevPoint *)(bl+1);
+ bevp1= bevp2+(bl->nr-1);
+ bevp0= bevp1-1;
+
+ nr= bl->nr;
+ while(nr--) {
+
+ /* Normalizes */
+ Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+ if(bl->nr==nr+1) { /* first time */
+ vectoquat(vec, 5, 1, quat);
+ }
+ else {
+ float angle = NormalizedVecAngle2(vec_prev, vec);
+
+ if(angle > 0.0f) { /* otherwise we can keep as is */
+ Crossf(cross, vec_prev, vec);
+ AxisAngleToQuat(q, cross, angle);
+ QuatMul(quat, q, quat_prev);
+ }
+ else {
+ QUATCOPY(quat, quat_prev);
+ }
+ }
+ QUATCOPY(quat_prev, quat); /* quat_prev can't have the tilt applied */
+ VECCOPY(vec_prev, vec);
+
+ if(iter_dir==0) { /* up, first time */
+ quat_tmp1= (float *)bevp1->mat;
+
+ bevp0= bevp1;
+ bevp1= bevp2;
+ bevp2++;
+ }
+ else { /* down second time */
+ quat_tmp1= ((float *)bevp1->mat)+4;
+
+ bevp2= bevp1;
+ bevp1= bevp0;
+ bevp0--;
+
+ /* wrap around */
+ if (bevp0 < bevp_start)
+ bevp0= bevp_start+(bl->nr-1);
+ }
+
+ QUATCOPY(quat_tmp1, quat);
+ }
+ }
+
+ /* Now interpolate the 2 quats and apply tilt */
+
+ bevp2= (BevPoint *)(bl+1);
+ bevp1= bevp2+(bl->nr-1);
+ bevp0= bevp1-1;
+
+ nr= bl->nr;
+ while(nr--) {
+
+ Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+ quat_tmp1= (float *)bevp1->mat;
+ quat_tmp2= quat_tmp1+4;
+
+ /* blend the 2 rotations gathered from both directions */
+ QuatInterpol(quat, quat_tmp1, quat_tmp2, 1.0 - (((float)nr)/bl->nr));
+
+ AxisAngleToQuat(q, vec, bevp1->alfa);
+ QuatMul(quat, q, quat);
+ QuatToMat3(quat, bevp1->mat);
+
+ /* generic */
+ x1= bevp1->x- bevp0->x;
+ x2= bevp1->x- bevp2->x;
+ y1= bevp1->y- bevp0->y;
+ y2= bevp1->y- bevp2->y;
+
+ calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
+
+ bevp0= bevp1;
+ bevp1= bevp2;
+ bevp2++;
+ }
}
- else if(bl->nr>2) {
+ else {
+ /* Any curve with 3 or more points */
+
bevp2= (BevPoint *)(bl+1);
bevp1= bevp2+(bl->nr-1);
bevp0= bevp1-1;
-
nr= bl->nr;
-
while(nr--) {
-
+
if(cu->flag & CU_3D) { /* 3D */
- float quat[4], q[4];
-
- vec[0]= bevp2->x - bevp0->x;
- vec[1]= bevp2->y - bevp0->y;
- vec[2]= bevp2->z - bevp0->z;
-
- Normalize(vec);
- vectoquat(vec, 5, 1, quat);
-
- q[0]= (float)cos(0.5*bevp1->alfa);
- x1= (float)sin(0.5*bevp1->alfa);
- q[1]= x1*vec[0];
- q[2]= x1*vec[1];
- q[3]= x1*vec[2];
+ /* Normalizes */
+ Vec3ToTangent(vec, &bevp0->x, &bevp1->x, &bevp2->x);
+
+ if(bl->nr==nr+1 || !(cu->flag & CU_NO_TWIST)) { /* first time */
+ vectoquat(vec, 5, 1, quat);
+ }
+ else {
+ float angle = NormalizedVecAngle2(vec_prev, vec);
+
+ if(angle > 0.0f) { /* otherwise we can keep as is */
+ Crossf(cross, vec_prev, vec);
+ AxisAngleToQuat(q, cross, angle);
+ QuatMul(quat, q, quat_prev);
+ }
+ else {
+ QUATCOPY(quat, quat_prev);
+ }
+ }
+ QUATCOPY(quat_prev, quat); /* quat_prev can't have the tilt applied */
+ VECCOPY(vec_prev, vec);
+
+ AxisAngleToQuat(q, vec, bevp1->alfa);
QuatMul(quat, q, quat);
-
QuatToMat3(quat, bevp1->mat);
}
-
+
x1= bevp1->x- bevp0->x;
x2= bevp1->x- bevp2->x;
y1= bevp1->y- bevp0->y;
y2= bevp1->y- bevp2->y;
-
+
calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
-
-
+
+
bevp0= bevp1;
bevp1= bevp2;
bevp2++;
}
+
/* correct non-cyclic cases */
if(bl->poly== -1) {
if(bl->nr>2) {
diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h
index 092ed00fbe5..63b351016d4 100644
--- a/source/blender/blenlib/BLI_arithb.h
+++ b/source/blender/blenlib/BLI_arithb.h
@@ -270,6 +270,7 @@ void AxisAngleToQuat(float *q, float *axis, float angle);
void RotationBetweenVectorsToQuat(float *q, float v1[3], float v2[3]);
void vectoquat(float *vec, short axis, short upflag, float *q);
+void Vec3ToTangent(float *v, float *v1, float *v2, float *v3);
float VecAngle2(float *v1, float *v2);
float VecAngle3(float *v1, float *v2, float *v3);
float NormalizedVecAngle2(float *v1, float *v2);
diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c
index ad1dc1ca12c..970d8f7d0de 100644
--- a/source/blender/blenlib/intern/arithb.c
+++ b/source/blender/blenlib/intern/arithb.c
@@ -2969,6 +2969,19 @@ void VecRotToQuat( float *vec, float phi, float *quat)
}
}
+/* get a direction from 3 vectors that wont depend
+ * on the distance between the points */
+void Vec3ToTangent(float *v, float *v1, float *v2, float *v3)
+{
+ float d_12[3], d_23[3];
+ VecSubf(d_12, v2, v1);
+ VecSubf(d_23, v3, v2);
+ Normalize(d_12);
+ Normalize(d_23);
+ VecAddf(v, d_12, d_23);
+ Normalize(v);
+}
+
/* Return the angle in degrees between vecs 1-2 and 2-3 in degrees
If v1 is a shoulder, v2 is the elbow and v3 is the hand,
this would return the angle at the elbow */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index f809cac037d..88c03a41160 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -205,6 +205,8 @@ typedef struct Curve {
#define CU_FAST 512 /* Font: no filling inside editmode */
#define CU_RETOPO 1024
+#define CU_NO_TWIST 4096
+
/* spacemode */
#define CU_LEFT 0
#define CU_MIDDLE 1
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index 2f9eac67d94..1e37fd0b9f8 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -3671,7 +3671,8 @@ static void editing_panel_curve_type(Object *ob, Curve *cu)
uiBlockSetCol(block, TH_BUT_SETTING1);
uiDefButBitS(block, TOG, CU_BACK, B_MAKEDISP, "Back", 760,115,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled back for extruded/beveled curves");
uiDefButBitS(block, TOG, CU_FRONT, B_MAKEDISP, "Front",810,115,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled front for extruded/beveled curves");
- uiDefButBitS(block, TOG, CU_3D, B_CU3D, "3D", 860,115,50,19, &cu->flag, 0, 0, 0, 0, "Allow Curve to be 3d, it doesn't fill then");
+ uiDefButBitS(block, TOG, CU_3D, B_CU3D, "3D", 860,115,30,19, &cu->flag, 0, 0, 0, 0, "Allow Curve to be 3d, it doesn't fill then");
+ uiDefIconButBitS(block, TOG, CU_NO_TWIST, B_MAKEDISP, ICON_AUTO, 890,115,20,19, &cu->flag, 0.0, 0.0, 0, 0, "Avoid twisting artifacts for 3D beveled/extruded curves");
}
}