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:
@@ -5217,9 +5217,6 @@ void CURVE_OT_spin(wmOperatorType *ot)
|
|||||||
|
|
||||||
static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
|
static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
|
||||||
{
|
{
|
||||||
Nurb *nu = NULL;
|
|
||||||
Nurb *nu_last = NULL;
|
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
Nurb *cu_actnu;
|
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_get(cu, &cu_actnu, &cu_actvert.p);
|
||||||
BKE_curve_nurb_vert_active_set(cu, NULL, NULL);
|
int act_offset = 0;
|
||||||
|
|
||||||
/* first pass (endpoints) */
|
|
||||||
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
|
|
||||||
|
|
||||||
if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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) {
|
if (nu->type == CU_BEZIER) {
|
||||||
|
BezTriple *bezt, *bezt_prev = NULL;
|
||||||
/* Check to see if the first bezier point is selected */
|
bool is_cyclic = false;
|
||||||
if (nu->pntsu > 0 && nu->bezt != NULL) {
|
if (pnt_len == 1) {
|
||||||
BezTriple *nu_bezt_old = nu->bezt;
|
/* Single point extrusion.
|
||||||
BezTriple *bezt = nu->bezt;
|
* Keep `is_prev_selected` false to force extrude. */
|
||||||
|
bezt_prev = &nu->bezt[0];
|
||||||
if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
|
}
|
||||||
BezTriple *bezt_new;
|
else if (nu->flagu & CU_NURB_CYCLIC) {
|
||||||
BEZT_DESEL_ALL(bezt);
|
is_cyclic = true;
|
||||||
|
bezt_prev = &nu->bezt[pnt_len - 1];
|
||||||
bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
|
is_prev_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev);
|
||||||
ED_curve_beztcpy(editnurb, bezt_new + 1, bezt, nu->pntsu);
|
}
|
||||||
*bezt_new = *bezt;
|
i = pnt_len;
|
||||||
|
for (bezt = &nu->bezt[0]; i--; bezt++) {
|
||||||
MEM_freeN(nu->bezt);
|
bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
|
||||||
nu->bezt = bezt_new;
|
if (bezt_prev && is_prev_selected != is_selected) {
|
||||||
|
new_points++;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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 (new_points) {
|
||||||
if (nu->pntsu > 1) {
|
if (pnt_len == 1) {
|
||||||
BezTriple *nu_bezt_old = nu->bezt;
|
/* Single point extrusion.
|
||||||
BezTriple *bezt = &nu->bezt[nu->pntsu - 1];
|
* Set `is_prev_selected` as false to force extrude. */
|
||||||
|
BLI_assert(bezt_prev == &nu->bezt[0]);
|
||||||
if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
|
is_prev_selected = false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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 {
|
else {
|
||||||
|
BPoint *bp, *bp_prev = NULL;
|
||||||
/* Check to see if the first bpoint is selected */
|
if (pnt_len == 1) {
|
||||||
if (nu->pntsu > 0 && nu->bp != NULL) {
|
/* Single point extrusion.
|
||||||
BPoint *nu_bp_old = nu->bp;
|
* Reference a `prev_bp` to force extrude. */
|
||||||
BPoint *bp = nu->bp;
|
bp_prev = &nu->bp[0];
|
||||||
|
}
|
||||||
if (bp->f1 & SELECT) {
|
i = pnt_len;
|
||||||
BPoint *bp_new;
|
for (bp = &nu->bp[0]; i--; bp++) {
|
||||||
bp->f1 &= ~SELECT;
|
bool is_selected = (bp->f1 & SELECT) != 0;
|
||||||
|
if (bp_prev && is_prev_selected != is_selected) {
|
||||||
bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
|
new_points++;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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 (new_points) {
|
||||||
if (nu->pntsu > 1) {
|
BPoint *bp_src, *bp_dst, *bp_src_iter, *bp_dst_iter;
|
||||||
BPoint *nu_bp_old = nu->bp;
|
is_prev_selected = false;
|
||||||
BPoint *bp = &nu->bp[nu->pntsu - 1];
|
if (pnt_len == 1) {
|
||||||
|
/* Single point extrusion.
|
||||||
if (bp->f1 & SELECT) {
|
* Keep `is_prev_selected` false to force extrude. */
|
||||||
BPoint *bp_new;
|
BLI_assert(bp_prev == &nu->bp[0]);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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) */
|
cu->actvert += act_offset;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user