Index: source/blender/editors/curve/curve_ops.c =================================================================== --- source/blender/editors/curve/curve_ops.c (revision 58862) +++ source/blender/editors/curve/curve_ops.c (working copy) @@ -87,6 +87,7 @@ WM_operatortype_append(CURVE_OT_reveal); WM_operatortype_append(CURVE_OT_separate); + WM_operatortype_append(CURVE_OT_split); WM_operatortype_append(CURVE_OT_duplicate); WM_operatortype_append(CURVE_OT_delete); @@ -244,6 +245,7 @@ RNA_boolean_set(kmi->ptr, "deselect", TRUE); WM_keymap_add_item(keymap, "CURVE_OT_separate", PKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "CURVE_OT_split", YKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "CURVE_OT_extrude_move", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "CURVE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "CURVE_OT_make_segment", FKEY, KM_PRESS, 0, 0); Index: source/blender/editors/curve/curve_intern.h =================================================================== --- source/blender/editors/curve/curve_intern.h (revision 58862) +++ source/blender/editors/curve/curve_intern.h (working copy) @@ -76,6 +76,7 @@ void CURVE_OT_reveal(struct wmOperatorType *ot); void CURVE_OT_separate(struct wmOperatorType *ot); +void CURVE_OT_split(struct wmOperatorType *ot); void CURVE_OT_duplicate(struct wmOperatorType *ot); void CURVE_OT_delete(struct wmOperatorType *ot); Index: source/blender/editors/curve/editcurve.c =================================================================== --- source/blender/editors/curve/editcurve.c (revision 58862) +++ source/blender/editors/curve/editcurve.c (working copy) @@ -108,6 +108,8 @@ void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus); static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus); +static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, short flag, short split); +static int delete_selected(Object *obedit, int type); /* still need to eradicate a few :( */ #define CALLOC_STRUCT_N(x, y, name) (x *)MEM_callocN((y) * sizeof(x), name) @@ -1387,16 +1389,15 @@ { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Nurb *nu, *nu1; Object *oldob, *newob; Base *oldbase, *newbase; Curve *oldcu, *newcu; - EditNurb *oldedit, *newedit; + EditNurb *newedit; + ListBase newnurb = {NULL, NULL}; oldbase = CTX_data_active_base(C); oldob = oldbase->object; oldcu = oldob->data; - oldedit = oldcu->editnurb; if (oldcu->key) { BKE_report(op->reports, RPT_ERROR, "Cannot separate a curve with vertex keys"); @@ -1405,43 +1406,42 @@ WM_cursor_wait(1); - /* 1. duplicate the object and data */ + /* 1. duplicate geometry and check for valid separation */ + adduplicateflagNurb(oldob, &newnurb, 1, 1); + + if (newnurb.first == NULL) { + WM_cursor_wait(0); + BKE_report(op->reports, RPT_ERROR, "Cannot separate current selection"); + return OPERATOR_CANCELLED; + } + + /* 2. duplicate the object and data */ newbase = ED_object_add_duplicate(bmain, scene, oldbase, 0); /* 0 = fully linked */ DAG_relations_tag_update(bmain); - ED_base_object_select(newbase, BA_DESELECT); newob = newbase->object; - newcu = newob->data = BKE_curve_copy(oldcu); newcu->editnurb = NULL; oldcu->id.us--; /* because new curve is a copy: reduce user count */ - /* 2. put new object in editmode and clear it */ + /* 3. put new object in editmode, clear it and set separated nurbs */ make_editNurb(newob); newedit = newcu->editnurb; BKE_nurbList_free(&newedit->nurbs); BKE_curve_editNurb_keyIndex_free(newedit); newedit->keyindex = NULL; + BLI_movelisttolist(&newedit->nurbs, &newnurb); - /* 3. move over parts from old object */ - for (nu = oldedit->nurbs.first; nu; nu = nu1) { - nu1 = nu->next; - - if (isNurbsel(nu)) { - keyIndex_delNurb(oldedit, nu); - BLI_remlink(&oldedit->nurbs, nu); - BLI_addtail(&newedit->nurbs, nu); - } - } - - /* 4. put old object out of editmode */ + /* 4. put old object out of editmode and delete separated geometry */ load_editNurb(newob); free_editNurb(newob); + delete_selected(oldob, 0); DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */ DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */ WM_event_add_notifier(C, NC_GEOM | ND_DATA, oldob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob); WM_cursor_wait(0); @@ -1453,7 +1453,7 @@ /* identifiers */ ot->name = "Separate"; ot->idname = "CURVE_OT_separate"; - ot->description = "Separate (partly) selected curves or surfaces into a new object"; + ot->description = "Separate selected geometry into a new curve or surface"; /* api callbacks */ ot->exec = separate_exec; @@ -1463,6 +1463,48 @@ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/******************** split operator ***********************/ + +static int split_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase newnurb = {NULL, NULL}; + + adduplicateflagNurb(obedit, &newnurb, 1, 1); + + if (newnurb.first != NULL) { + delete_selected(obedit, 0); + BLI_movelisttolist(object_editcurve_get(obedit), &newnurb); + + if (ED_curve_updateAnimPaths(obedit->data)) + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + } + else { + BKE_report(op->reports, RPT_ERROR, "Cannot split current selection"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +void CURVE_OT_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split"; + ot->idname = "CURVE_OT_split"; + ot->description = "Split off selected geometry from connected unselected geometry"; + + /* api callbacks */ + ot->exec = split_exec; + ot->poll = ED_operator_editsurfcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ******************* FLAGS ********************* */ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag) @@ -1614,9 +1656,8 @@ } } -static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag) +static int deleteflagNurb(Object *obedit, int flag) { - Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; ListBase *editnurb = object_editcurve_get(obedit); Nurb *nu, *next; @@ -1744,9 +1785,6 @@ nu = next; } - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - return OPERATOR_FINISHED; } @@ -1869,14 +1907,14 @@ return ok; } -static void adduplicateflagNurb(Object *obedit, short flag) +static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, short flag, short split) { ListBase *editnurb = object_editcurve_get(obedit); Nurb *nu, *newnu; BezTriple *bezt, *bezt1; BPoint *bp, *bp1; Curve *cu = (Curve *)obedit->data; - int a, b, starta, enda, newu, newv; + int a, b, starta, enda, diffa, newu, newv; char *usel; cu->lastsel = NULL; @@ -1889,27 +1927,42 @@ enda = -1; starta = a; while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) { - select_beztriple(bezt, DESELECT, flag, HIDDEN); + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; enda = a; if (a >= nu->pntsu - 1) break; a++; bezt++; } if (enda >= starta) { + diffa = enda - starta; + newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN"); memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(editnurb, newnu); + BLI_addtail(newnurb, newnu); set_actNurb(obedit, newnu); - newnu->pntsu = enda - starta + 1; - newnu->bezt = (BezTriple *)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN"); + newnu->pntsu = diffa + 1; + newnu->bezt = (BezTriple *)MEM_mallocN((diffa + 1) * sizeof(BezTriple), "adduplicateN"); memcpy(newnu->bezt, &nu->bezt[starta], newnu->pntsu * sizeof(BezTriple)); - b = newnu->pntsu; - bezt1 = newnu->bezt; - while (b--) { - select_beztriple(bezt1, SELECT, flag, HIDDEN); - bezt1++; + if (!split || nu->pntsu == diffa + 1) { + /* if not split then deselect all, otherwise select all for deletion */ + for (b = 0, bezt1 = nu->bezt; b <= enda; b++, bezt1++) { + select_beztriple(bezt1, split, flag, HIDDEN); + } } + else if (starta == 0) { + /* start of curve, deselect last selected */ + select_beztriple(bezt - 1, DESELECT, flag, HIDDEN); + } + else if (enda >= nu->pntsu - 1) { + /* end of curve, deselect first selected */ + select_beztriple(bezt - diffa, DESELECT, flag, HIDDEN); + } + else if (enda != nu->pntsu - 1 && starta != 0) { + /* deselect both beginning and end of selection */ + select_beztriple(bezt - 1, DESELECT, flag, HIDDEN); + select_beztriple(bezt - diffa - 1, DESELECT, flag, HIDDEN); + } if (nu->flagu & CU_NURB_CYCLIC) { if (starta != 0 || enda != nu->pntsu - 1) { @@ -1926,27 +1979,41 @@ enda = -1; starta = a; while (bp->f1 & flag) { - select_bpoint(bp, DESELECT, flag, HIDDEN); enda = a; if (a >= nu->pntsu - 1) break; a++; bp++; } if (enda >= starta) { + diffa = enda - starta; + newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN3"); memcpy(newnu, nu, sizeof(Nurb)); set_actNurb(obedit, newnu); - BLI_addtail(editnurb, newnu); - newnu->pntsu = enda - starta + 1; - newnu->bp = (BPoint *)MEM_mallocN((enda - starta + 1) * sizeof(BPoint), "adduplicateN4"); + BLI_addtail(newnurb, newnu); + newnu->pntsu = diffa + 1; + newnu->bp = (BPoint *)MEM_mallocN((diffa + 1) * sizeof(BPoint), "adduplicateN4"); memcpy(newnu->bp, &nu->bp[starta], newnu->pntsu * sizeof(BPoint)); - b = newnu->pntsu; - bp1 = newnu->bp; - while (b--) { - select_bpoint(bp1, SELECT, flag, HIDDEN); - bp1++; + if (split == 0 || nu->pntsu == diffa + 1) { + /* if not split then deselect all, otherwise select all for deletion */ + for (b = 0, bp1 = nu->bp; b <= enda; b++, bp1++) { + select_bpoint(bp1, split, flag, HIDDEN); + } } + else if (starta == 0) { + /* start of curve, deselect last selected */ + select_bpoint(bp - 1, DESELECT, flag, HIDDEN); + } + else if (enda >= nu->pntsu - 1) { + /* end of curve, deselect first selected */ + select_bpoint(bp - diffa, DESELECT, flag, HIDDEN); + } + else if (enda != nu->pntsu - 1 && starta != 0) { + /* deselect both beginning and end of selection */ + select_bpoint(bp - 1, DESELECT, flag, HIDDEN); + select_bpoint(bp - diffa - 1, DESELECT, flag, HIDDEN); + } if (nu->flagu & CU_NURB_CYCLIC) { if (starta != 0 || enda != nu->pntsu - 1) { @@ -1990,12 +2057,16 @@ printf("Can't duplicate Nurb\n"); } else { + int startu = -1, startv = -1; + /* selection of points too small, set split to 0 to deselect all */ + if (newu != nu->pntsu && newv != nu->pntsv) split = 0; + if (newu == 1) SWAP(int, newu, newv); newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN5"); memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(editnurb, newnu); + BLI_addtail(newnurb, newnu); set_actNurb(obedit, newnu); newnu->pntsu = newu; newnu->pntsv = newv; @@ -2011,10 +2082,50 @@ for (b = 0; b < nu->pntsu; b++, bp1++) { if (bp1->f1 & flag) { memcpy(bp, bp1, sizeof(BPoint)); - select_bpoint(bp1, DESELECT, flag, HIDDEN); bp++; + + if (split) { + BPoint *bpv = bp1, *bpu = bp1; + + /* get 'next' v and u points and set start points */ + if (a != nu->pntsv - 1) bpv = bp1 + nu->pntsu; + if (b != nu->pntsu - 1) bpu = bp1 + 1; + if (startv == -1) startv = a; + if (startu == -1) startu = b; + + if (bpv->f1 & flag) { + if (a != 0 && startv == a) { + /* deselect start of mid point selection or single end point */ + select_bpoint(bp1, DESELECT, flag, HIDDEN); + continue; + } + } + else { + /* deselect single start or mid point */ + select_bpoint(bp1, DESELECT, flag, HIDDEN); + continue; + } + + if (bpu->f1 & flag) { + if (b != 0 && startu == b) { + select_bpoint(bp1, DESELECT, flag, HIDDEN); + } + } + else { + select_bpoint(bp1, DESELECT, flag, HIDDEN); + } + } + else { + /* deselect all for duplicate */ + select_bpoint(bp1, DESELECT, flag, HIDDEN); + } } } + if (startu == -1) { + /* if no points from u selected, reset startv */ + startv = -1; + } + startu = -1; } if (BKE_nurb_check_valid_u(newnu)) { if (nu->pntsu == newnu->pntsu && nu->knotsu) { @@ -5672,10 +5783,15 @@ static int duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); + ListBase newnurb = {NULL, NULL}; - adduplicateflagNurb(obedit, 1); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + adduplicateflagNurb(obedit, &newnurb, 1, 0); + if (newnurb.first != NULL) { + BLI_movelisttolist(object_editcurve_get(obedit), &newnurb); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + return OPERATOR_FINISHED; } @@ -5696,34 +5812,27 @@ /********************** delete operator *********************/ -static int delete_exec(bContext *C, wmOperator *op) +static int delete_selected(Object *obedit, int type) { - Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; EditNurb *editnurb = cu->editnurb; ListBase *nubase = &editnurb->nurbs; Nurb *nu, *nu1; BezTriple *bezt, *bezt1, *bezt2; BPoint *bp, *bp1, *bp2; - int a, cut = 0, type = RNA_enum_get(op->ptr, "type"); + int a, cut = 0; int nuindex = 0; if (obedit->type == OB_SURF) { if (type == 0) { - deleteflagNurb(C, op, 1); + return deleteflagNurb(obedit, 1); } else { keyIndex_delNurbList(editnurb, nubase); BKE_nurbList_free(nubase); - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + return OPERATOR_FINISHED; } - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); - - return OPERATOR_FINISHED; } if (type == 0) { @@ -5883,8 +5992,6 @@ if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) { nu->flagu &= ~CU_NURB_CYCLIC; BKE_nurb_handles_calc(nu); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); } } @@ -5911,8 +6018,6 @@ bp2 = bp + (nu->pntsu - 1); if (bp2->f1 & SELECT) { nu->flagu &= ~CU_NURB_CYCLIC; - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); } } @@ -6019,15 +6124,27 @@ BKE_nurbList_free(nubase); } - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); - return OPERATOR_FINISHED; } +static int delete_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + int retval = delete_selected(obedit, RNA_enum_get(op->ptr, "type")); + + if (retval == OPERATOR_FINISHED) { + if (ED_curve_updateAnimPaths(obedit->data)) + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + + return retval; + } + + return retval; +} + static int delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *obedit = CTX_data_edit_object(C); Index: release/scripts/startup/bl_ui/space_view3d.py =================================================================== --- release/scripts/startup/bl_ui/space_view3d.py (revision 58862) +++ release/scripts/startup/bl_ui/space_view3d.py (working copy) @@ -2141,6 +2141,7 @@ layout.operator("curve.extrude_move") layout.operator("curve.duplicate_move") + layout.operator("curve.split") layout.operator("curve.separate") layout.operator("curve.make_segment") layout.operator("curve.cyclic_toggle")