Edit Curve: Improve Curve extrude

The original code has two logics, extrude the end points or duplicate points (making new splines).
Now all the logic has been redone by extruding contiguous selected segments.

Fix T47169

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D6982
This commit is contained in:
2020-03-30 10:10:43 -03:00
parent 1c1a14dcdf
commit 38685b5a39

View File

@@ -5217,9 +5217,6 @@ void CURVE_OT_spin(wmOperatorType *ot)
static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
{
Nurb *nu = NULL;
Nurb *nu_last = NULL;
bool changed = false;
Nurb *cu_actnu;
@@ -5234,211 +5231,168 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
}
BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p);
BKE_curve_nurb_vert_active_set(cu, NULL, NULL);
/* first pass (endpoints) */
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
continue;
}
int act_offset = 0;
for (Nurb *nu = editnurb->nurbs.first; nu; nu = nu->next) {
BLI_assert(nu->pntsu > 0);
int i;
int pnt_len = nu->pntsu;
int new_points = 0;
int offset = 0;
bool is_prev_selected = false;
if (nu->type == CU_BEZIER) {
/* Check to see if the first bezier point is selected */
if (nu->pntsu > 0 && nu->bezt != NULL) {
BezTriple *nu_bezt_old = nu->bezt;
BezTriple *bezt = nu->bezt;
if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
BezTriple *bezt_new;
BEZT_DESEL_ALL(bezt);
bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
ED_curve_beztcpy(editnurb, bezt_new + 1, bezt, nu->pntsu);
*bezt_new = *bezt;
MEM_freeN(nu->bezt);
nu->bezt = bezt_new;
nu->pntsu += 1;
if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
cu_actvert.bezt = (cu_actvert.bezt == bezt) ?
bezt_new :
&nu->bezt[(cu_actvert.bezt - nu_bezt_old) + 1];
BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
}
BEZT_SEL_ALL(bezt_new);
changed = true;
BezTriple *bezt, *bezt_prev = NULL;
bool is_cyclic = false;
if (pnt_len == 1) {
/* Single point extrusion.
* Keep `is_prev_selected` false to force extrude. */
bezt_prev = &nu->bezt[0];
}
else if (nu->flagu & CU_NURB_CYCLIC) {
is_cyclic = true;
bezt_prev = &nu->bezt[pnt_len - 1];
is_prev_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev);
}
i = pnt_len;
for (bezt = &nu->bezt[0]; i--; bezt++) {
bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
if (bezt_prev && is_prev_selected != is_selected) {
new_points++;
}
if (bezt == cu_actvert.bezt) {
act_offset = new_points;
}
bezt_prev = bezt;
is_prev_selected = is_selected;
}
/* Check to see if the last bezier point is selected */
if (nu->pntsu > 1) {
BezTriple *nu_bezt_old = nu->bezt;
BezTriple *bezt = &nu->bezt[nu->pntsu - 1];
if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
BezTriple *bezt_new;
BEZT_DESEL_ALL(bezt);
bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
ED_curve_beztcpy(editnurb, bezt_new, nu->bezt, nu->pntsu);
bezt_new[nu->pntsu] = *bezt;
MEM_freeN(nu->bezt);
nu->bezt = bezt_new;
bezt_new += nu->pntsu;
nu->pntsu += 1;
if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
cu_actvert.bezt = (cu_actvert.bezt == bezt) ? bezt_new :
&nu->bezt[cu_actvert.bezt - nu_bezt_old];
BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
}
BEZT_SEL_ALL(bezt_new);
changed = true;
if (new_points) {
if (pnt_len == 1) {
/* Single point extrusion.
* Set `is_prev_selected` as false to force extrude. */
BLI_assert(bezt_prev == &nu->bezt[0]);
is_prev_selected = false;
}
else if (is_cyclic) {
BLI_assert(bezt_prev == &nu->bezt[pnt_len - 1]);
BLI_assert(is_prev_selected == BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev));
}
else {
bezt_prev = NULL;
}
BezTriple *bezt_src, *bezt_dst, *bezt_src_iter, *bezt_dst_iter;
bezt_src = nu->bezt;
bezt_dst = MEM_mallocN((pnt_len + new_points) * sizeof(BezTriple), __func__);
bezt_src_iter = &bezt_src[0];
bezt_dst_iter = &bezt_dst[0];
i = 0;
for (bezt = &nu->bezt[0]; i < pnt_len; i++, bezt++) {
bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
if (bezt_prev && is_prev_selected != is_selected) {
int count = i - offset + 1;
if (is_prev_selected) {
ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count - 1);
ED_curve_beztcpy(editnurb, &bezt_dst_iter[count - 1], bezt_prev, 1);
}
else {
ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count);
}
ED_curve_beztcpy(editnurb, &bezt_dst_iter[count], bezt, 1);
BEZT_DESEL_ALL(&bezt_dst_iter[count - 1]);
bezt_dst_iter += count + 1;
bezt_src_iter += count;
offset = i + 1;
}
bezt_prev = bezt;
is_prev_selected = is_selected;
}
int remain = pnt_len - offset;
if (remain) {
ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, pnt_len - offset);
}
MEM_freeN(nu->bezt);
nu->bezt = bezt_dst;
nu->pntsu += new_points;
changed = true;
}
}
else {
/* Check to see if the first bpoint is selected */
if (nu->pntsu > 0 && nu->bp != NULL) {
BPoint *nu_bp_old = nu->bp;
BPoint *bp = nu->bp;
if (bp->f1 & SELECT) {
BPoint *bp_new;
bp->f1 &= ~SELECT;
bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
ED_curve_bpcpy(editnurb, bp_new + 1, bp, nu->pntsu);
*bp_new = *bp;
MEM_freeN(nu->bp);
nu->bp = bp_new;
nu->pntsu += 1;
BKE_nurb_knot_calc_u(nu);
if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
cu_actvert.bp = (cu_actvert.bp == bp) ? bp_new :
&nu->bp[(cu_actvert.bp - nu_bp_old) + 1];
BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
}
bp_new->f1 |= SELECT;
changed = true;
BPoint *bp, *bp_prev = NULL;
if (pnt_len == 1) {
/* Single point extrusion.
* Reference a `prev_bp` to force extrude. */
bp_prev = &nu->bp[0];
}
i = pnt_len;
for (bp = &nu->bp[0]; i--; bp++) {
bool is_selected = (bp->f1 & SELECT) != 0;
if (bp_prev && is_prev_selected != is_selected) {
new_points++;
}
if (bp == cu_actvert.bp) {
act_offset = new_points;
}
bp_prev = bp;
is_prev_selected = is_selected;
}
/* Check to see if the last bpoint is selected */
if (nu->pntsu > 1) {
BPoint *nu_bp_old = nu->bp;
BPoint *bp = &nu->bp[nu->pntsu - 1];
if (bp->f1 & SELECT) {
BPoint *bp_new;
bp->f1 &= ~SELECT;
bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
ED_curve_bpcpy(editnurb, bp_new, nu->bp, nu->pntsu);
bp_new[nu->pntsu] = *bp;
MEM_freeN(nu->bp);
nu->bp = bp_new;
bp_new += nu->pntsu;
nu->pntsu += 1;
if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
cu_actvert.bp = (cu_actvert.bp == bp) ? bp_new : &nu->bp[cu_actvert.bp - nu_bp_old];
BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
}
BKE_nurb_knot_calc_u(nu);
bp_new->f1 |= SELECT;
changed = true;
if (new_points) {
BPoint *bp_src, *bp_dst, *bp_src_iter, *bp_dst_iter;
is_prev_selected = false;
if (pnt_len == 1) {
/* Single point extrusion.
* Keep `is_prev_selected` false to force extrude. */
BLI_assert(bp_prev == &nu->bp[0]);
}
else {
bp_prev = NULL;
}
bp_src = nu->bp;
bp_dst = MEM_mallocN((pnt_len + new_points) * sizeof(BPoint), __func__);
bp_src_iter = &bp_src[0];
bp_dst_iter = &bp_dst[0];
i = 0;
for (bp = &nu->bp[0]; i < pnt_len; i++, bp++) {
bool is_selected = (bp->f1 & SELECT) != 0;
if (bp_prev && is_prev_selected != is_selected) {
int count = i - offset + 1;
if (is_prev_selected) {
ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count - 1);
ED_curve_bpcpy(editnurb, &bp_dst_iter[count - 1], bp_prev, 1);
}
else {
ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count);
}
ED_curve_bpcpy(editnurb, &bp_dst_iter[count], bp, 1);
bp_dst_iter[count - 1].f1 &= ~SELECT;
bp_dst_iter += count + 1;
bp_src_iter += count;
offset = i + 1;
}
bp_prev = bp;
is_prev_selected = is_selected;
}
int remain = pnt_len - offset;
if (remain) {
ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, pnt_len - offset);
}
MEM_freeN(nu->bp);
nu->bp = bp_dst;
nu->pntsu += new_points;
BKE_nurb_knot_calc_u(nu);
changed = true;
}
}
}
/* second pass (interior points) */
nu_last = editnurb->nurbs.last;
for (nu = editnurb->nurbs.first; (nu != nu_last->next); nu = nu->next) {
int i, i_end;
if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
/* all points are interior */
i = 0;
i_end = nu->pntsu;
}
else {
/* skip endpoints */
i = 1;
i_end = nu->pntsu - 1;
}
if (nu->type == CU_BEZIER) {
BezTriple *bezt;
for (bezt = &nu->bezt[i]; i < i_end; i++, bezt++) {
if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
Nurb *nurb_new;
BezTriple *bezt_new;
BEZT_DESEL_ALL(bezt);
nurb_new = BKE_nurb_copy(nu, 1, 1);
nurb_new->flagu &= ~CU_NURB_CYCLIC;
BLI_addtail(&editnurb->nurbs, nurb_new);
bezt_new = nurb_new->bezt;
ED_curve_beztcpy(editnurb, bezt_new, bezt, 1);
BEZT_SEL_ALL(bezt_new);
if (cu_actvert.bezt == bezt || cu_actnu == NULL) {
BKE_curve_nurb_vert_active_set(cu, nurb_new, bezt_new);
}
changed = true;
}
}
}
else {
BPoint *bp;
for (bp = &nu->bp[i]; i < i_end; i++, bp++) {
if (bp->f1 & SELECT) {
Nurb *nurb_new;
BPoint *bp_new;
bp->f1 &= ~SELECT;
nurb_new = BKE_nurb_copy(nu, 1, 1);
nurb_new->flagu &= ~CU_NURB_CYCLIC;
BLI_addtail(&editnurb->nurbs, nurb_new);
bp_new = nurb_new->bp;
ED_curve_bpcpy(editnurb, bp_new, bp, 1);
bp_new->f1 |= SELECT;
if (cu_actvert.bp == bp || cu_actnu == NULL) {
BKE_curve_nurb_vert_active_set(cu, nurb_new, bp_new);
}
changed = true;
}
}
}
}
if (changed == false) {
BKE_curve_nurb_vert_active_set(cu, cu_actnu, cu_actvert.p);
}
cu->actvert += act_offset;
return changed;
}