- add individual origin support for curves and improve the orientation calculations for curve handles,

- add support for using the active point's orientation.
- add support for creating new custom orientations from curves.
- fix error where only the last selected curve handle was taken into account for manipulator orientations.
This commit is contained in:
Campbell Barton 2013-07-24 13:56:36 +00:00
parent 57a4070b9d
commit b6f58d0ea1
7 changed files with 264 additions and 74 deletions

@ -129,6 +129,14 @@ bool BKE_nurb_type_convert(struct Nurb *nu, const short type, const bool use_han
void BKE_nurb_points_add(struct Nurb *nu, int number);
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number);
struct BezTriple *BKE_nurb_bezt_get_next(struct Nurb *nu, struct BezTriple *bezt);
struct BezTriple *BKE_nurb_bezt_get_prev(struct Nurb *nu, struct BezTriple *bezt);
struct BPoint *BKE_nurb_bpoint_get_next(struct Nurb *nu, struct BPoint *bp);
struct BPoint *BKE_nurb_bpoint_get_prev(struct Nurb *nu, struct BPoint *bp);
void BKE_nurb_bezt_calc_normal(struct Nurb *nu, struct BezTriple *bezt, float r_normal[3]);
void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3]);
void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, int mode);
void BKE_nurb_handles_calc(struct Nurb *nu);

@ -681,6 +681,143 @@ void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
nu->pntsu += number;
}
BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
{
BezTriple *bezt_next;
BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
if (bezt == &nu->bezt[nu->pntsu - 1]) {
if (nu->flagu & CU_NURB_CYCLIC) {
bezt_next = nu->bezt;
}
else {
bezt_next = NULL;
}
}
else {
bezt_next = bezt + 1;
}
return bezt_next;
}
BPoint *BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
{
BPoint *bp_next;
BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
if (bp == &nu->bp[nu->pntsu - 1]) {
if (nu->flagu & CU_NURB_CYCLIC) {
bp_next = nu->bp;
}
else {
bp_next = NULL;
}
}
else {
bp_next = bp + 1;
}
return bp_next;
}
BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
{
BezTriple *bezt_prev;
BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
if (bezt == nu->bezt) {
if (nu->flagu & CU_NURB_CYCLIC) {
bezt_prev = &nu->bezt[nu->pntsu - 1];
}
else {
bezt_prev = NULL;
}
}
else {
bezt_prev = bezt - 1;
}
return bezt_prev;
}
BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
{
BPoint *bp_prev;
BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
if (bp == nu->bp) {
if (nu->flagu & CU_NURB_CYCLIC) {
bp_prev = &nu->bp[nu->pntsu - 1];
}
else {
bp_prev = NULL;
}
}
else {
bp_prev = bp - 1;
}
return bp_prev;
}
void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), struct BezTriple *bezt, float r_normal[3])
{
/* calculate the axis matrix from the spline */
float dir_prev[3], dir_next[3];
sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
normalize_v3(dir_prev);
normalize_v3(dir_next);
add_v3_v3v3(r_normal, dir_prev, dir_next);
normalize_v3(r_normal);
}
void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3])
{
float dir_prev[3], dir_next[3];
sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
normalize_v3(dir_prev);
normalize_v3(dir_next);
cross_v3_v3v3(r_plane, dir_prev, dir_next);
if (normalize_v3(r_plane) < FLT_EPSILON) {
BezTriple *bezt_prev = BKE_nurb_bezt_get_prev(nu, bezt);
BezTriple *bezt_next = BKE_nurb_bezt_get_next(nu, bezt);
if (bezt_prev) {
sub_v3_v3v3(dir_prev, bezt_prev->vec[1], bezt->vec[1]);
normalize_v3(dir_prev);
}
if (bezt_next) {
sub_v3_v3v3(dir_next, bezt->vec[1], bezt_next->vec[1]);
normalize_v3(dir_next);
}
cross_v3_v3v3(r_plane, dir_prev, dir_next);
}
/* matches with bones more closely */
{
float dir_mid[3], tvec[3];
add_v3_v3v3(dir_mid, dir_prev, dir_next);
cross_v3_v3v3(tvec, r_plane, dir_mid);
copy_v3_v3(r_plane, tvec);
}
normalize_v3(r_plane);
}
/* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */

@ -2833,44 +2833,6 @@ void CURVE_OT_reveal(wmOperatorType *ot)
/********************** subdivide operator *********************/
static BezTriple *next_spline_bezier_point_get(Nurb *nu, BezTriple *bezt)
{
BezTriple *nextbezt;
if (bezt == nu->bezt + nu->pntsu - 1) {
if (nu->flagu & CU_NURB_CYCLIC) {
nextbezt = nu->bezt;
}
else {
nextbezt = NULL;
}
}
else {
nextbezt = bezt + 1;
}
return nextbezt;
}
static BPoint *next_spline_bpoint_get(Nurb *nu, BPoint *bp)
{
BPoint *nextbp;
if (bp == nu->bp + nu->pntsu - 1) {
if (nu->flagu & CU_NURB_CYCLIC) {
nextbp = nu->bp;
}
else {
nextbp = NULL;
}
}
else {
nextbp = bp + 1;
}
return nextbp;
}
/** Divide the line segments associated with the currently selected
* curve nodes (Bezier or NURB). If there are no valid segment
* selections within the current selection, nothing happens.
@ -2902,7 +2864,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
nextbezt = next_spline_bezier_point_get(nu, bezt);
nextbezt = BKE_nurb_bezt_get_next(nu, bezt);
if (nextbezt == NULL) {
break;
}
@ -2924,7 +2886,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
keyIndex_updateBezt(editnurb, bezt, beztn, 1);
beztn++;
nextbezt = next_spline_bezier_point_get(nu, bezt);
nextbezt = BKE_nurb_bezt_get_next(nu, bezt);
if (nextbezt == NULL) {
break;
}
@ -2988,7 +2950,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
a = nu->pntsu;
bp = nu->bp;
while (a--) {
nextbp = next_spline_bpoint_get(nu, bp);
nextbp = BKE_nurb_bpoint_get_next(nu, bp);
if (nextbp == NULL) {
break;
}
@ -3013,7 +2975,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
keyIndex_updateBP(editnurb, bp, bpn, 1);
bpn++;
nextbp = next_spline_bpoint_get(nu, bp);
nextbp = BKE_nurb_bpoint_get_next(nu, bp);
if (nextbp == NULL) {
break;
}

@ -110,7 +110,7 @@ static bool transdata_check_local_center(TransInfo *t)
{
return ((t->around == V3D_LOCAL) && (
(t->flag & (T_OBJECT | T_POSE)) ||
(t->obedit && ELEM3(t->obedit->type, OB_MESH, OB_MBALL, OB_ARMATURE)) ||
(t->obedit && ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
(t->spacetype == SPACE_IPO))
);
}
@ -7355,7 +7355,7 @@ bool checkUseAxisMatrix(TransInfo *t)
{
/* currenly only checks for editmode */
if (t->flag & T_EDIT) {
if ((t->around == V3D_LOCAL) && (ELEM3(t->obedit->type, OB_MESH, OB_MBALL, OB_ARMATURE))) {
if ((t->around == V3D_LOCAL) && (ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) {
/* not all editmode supports axis-matrix */
return true;
}

@ -725,7 +725,7 @@ void initTransformOrientation(struct bContext *C, TransInfo *t);
/* Those two fill in mat and return non-zero on success */
bool createSpaceNormal(float mat[3][3], const float normal[3]);
bool createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]);
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3]);
struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3], char name[], int overwrite);
void applyTransformOrientation(const struct bContext *C, float mat[3][3], char *name);

@ -1417,6 +1417,23 @@ static void createTransCurveVerts(TransInfo *t)
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == 0) {
TransDataCurveHandleFlags *hdata = NULL;
float axismtx[3][3];
if (t->around == V3D_LOCAL) {
float normal[3], plane[3];
BKE_nurb_bezt_calc_normal(nu, bezt, normal);
BKE_nurb_bezt_calc_plane(nu, bezt, plane);
if (createSpaceNormalTangent(axismtx, normal, plane)) {
/* pass */
}
else {
normalize_v3(normal);
axis_dominant_v3_to_m3(axismtx, normal);
invert_m3(axismtx);
}
}
if (propmode ||
((bezt->f2 & SELECT) && hide_handles) ||
@ -1440,6 +1457,9 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
if (t->around == V3D_LOCAL) {
copy_m3_m3(td->axismtx, axismtx);
}
td++;
count++;
@ -1469,6 +1489,9 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
if (t->around == V3D_LOCAL) {
copy_m3_m3(td->axismtx, axismtx);
}
if ((bezt->f1 & SELECT) == 0 && (bezt->f3 & SELECT) == 0)
/* If the middle is selected but the sides arnt, this is needed */
@ -1504,6 +1527,9 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
if (t->around == V3D_LOCAL) {
copy_m3_m3(td->axismtx, axismtx);
}
td++;
count++;

@ -166,6 +166,26 @@ static TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, c
return addMatrixSpace(C, mat, name, overwrite);
}
static TransformOrientation *createCurveSpace(bContext *C, ReportList *reports, char *name, int overwrite)
{
float mat[3][3];
float normal[3], plane[3];
getTransformOrientation(C, normal, plane, 0);
if (createSpaceNormalTangent(mat, normal, plane) == 0) {
BKE_reports_prepend(reports, "Cannot use zero-length curve");
return NULL;
}
if (name[0] == 0) {
strcpy(name, "Curve");
}
return addMatrixSpace(C, mat, name, overwrite);
}
static TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *name, int overwrite)
{
float mat[3][3];
@ -236,26 +256,28 @@ bool createSpaceNormal(float mat[3][3], const float normal[3])
return true;
}
bool createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3])
{
copy_v3_v3(mat[2], normal);
if (normalize_v3(mat[2]) == 0.0f) {
if (normalize_v3_v3(mat[2], normal) == 0.0f) {
return false; /* error return */
}
copy_v3_v3(mat[1], tangent);
/* preempt zero length tangent from causing trouble */
if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0) {
tangent[2] = 1;
if (is_zero_v3(mat[1])) {
mat[1][2] = 1.0f;
}
cross_v3_v3v3(mat[0], mat[2], tangent);
cross_v3_v3v3(mat[0], mat[2], mat[1]);
if (normalize_v3(mat[0]) == 0.0f) {
return false; /* error return */
}
cross_v3_v3v3(mat[1], mat[2], mat[0]);
normalize_v3(mat[1]);
normalize_m3(mat);
/* final matrix must be normalized, do inline */
// normalize_m3(mat);
return true;
}
@ -276,6 +298,8 @@ void BIF_createTransformOrientation(bContext *C, ReportList *reports, char *name
ts = createMeshSpace(C, reports, name, overwrite);
else if (obedit->type == OB_ARMATURE)
ts = createBoneSpace(C, reports, name, overwrite);
else if (obedit->type == OB_CURVE)
ts = createCurveSpace(C, reports, name, overwrite);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
ts = createBoneSpace(C, reports, name, overwrite);
@ -675,34 +699,67 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
int a;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
/* exception */
if ((bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT) {
sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
if (activeOnly && cu->lastsel) {
for (nu = nurbs->first; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
if (ARRAY_HAS_ITEM((BezTriple *)cu->lastsel, nu->bezt, nu->pntsu)) {
bezt = cu->lastsel;
BKE_nurb_bezt_calc_normal(nu, bezt, normal);
BKE_nurb_bezt_calc_plane(nu, bezt, plane);
break;
}
else {
if (bezt->f1) {
sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[1]);
}
if (bezt->f2) {
sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
}
if (bezt->f3) {
sub_v3_v3v3(normal, bezt->vec[1], bezt->vec[2]);
}
}
else {
if (ARRAY_HAS_ITEM((BPoint *)cu->lastsel, nu->bp, nu->pntsu)) {
/* do nothing */
break;
}
}
}
}
else {
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
/* exception */
if ((bezt->f1 | bezt->f2 | bezt->f3) & SELECT) {
float tvec[3];
if ((bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT) {
BKE_nurb_bezt_calc_normal(nu, bezt, tvec);
add_v3_v3(normal, tvec);
}
else {
if (bezt->f1 & SELECT) {
sub_v3_v3v3(tvec, bezt->vec[0], bezt->vec[1]);
normalize_v3(tvec);
add_v3_v3(normal, tvec);
}
if (bezt->f2 & SELECT) {
sub_v3_v3v3(tvec, bezt->vec[0], bezt->vec[2]);
normalize_v3(tvec);
add_v3_v3(normal, tvec);
}
if (bezt->f3 & SELECT) {
sub_v3_v3v3(tvec, bezt->vec[1], bezt->vec[2]);
normalize_v3(tvec);
add_v3_v3(normal, tvec);
}
}
BKE_nurb_bezt_calc_plane(nu, bezt, tvec);
add_v3_v3(plane, tvec);
}
bezt++;
}
bezt++;
}
}
}
if (!is_zero_v3(normal)) {
result = ORIENTATION_NORMAL;
result = ORIENTATION_FACE;
}
}
else if (obedit->type == OB_MBALL) {