diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-07-08 16:24:16 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-07-08 17:09:26 +0300 |
commit | 4a328a76895c4f03b528b3c7e251475e76c68351 (patch) | |
tree | 6a876d72be674294f63d3619b4464c4e8c262b0b /source/blender/editors/curve/editcurve_select.c | |
parent | de6b4dc7f7f5e78ebfefdfe804218a69631d778e (diff) |
EditCurve: move selection into own file
Diffstat (limited to 'source/blender/editors/curve/editcurve_select.c')
-rw-r--r-- | source/blender/editors/curve/editcurve_select.c | 1156 |
1 files changed, 1156 insertions, 0 deletions
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c new file mode 100644 index 00000000000..0a8c05ba16d --- /dev/null +++ b/source/blender/editors/curve/editcurve_select.c @@ -0,0 +1,1156 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/curve/editcurve_select.c + * \ingroup edcurve + */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap.h" +#include "BLI_math.h" +#include "BLI_rand.h" + + +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_fcurve.h" +#include "BKE_report.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_types.h" +#include "ED_view3d.h" +#include "ED_curve.h" + +#include "curve_intern.h" + + +#include "RNA_access.h" +#include "RNA_define.h" + + +/* returns 1 in case (de)selection was successful */ +bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden) +{ + if ((bezt->hide == 0) || (hidden == HIDDEN)) { + if (selstatus == SELECT) { /* selects */ + bezt->f1 |= flag; + bezt->f2 |= flag; + bezt->f3 |= flag; + return true; + } + else { /* deselects */ + bezt->f1 &= ~flag; + bezt->f2 &= ~flag; + bezt->f3 &= ~flag; + return true; + } + } + + return false; +} + +/* returns 1 in case (de)selection was successful */ +bool select_bpoint(BPoint *bp, bool selstatus, short flag, bool hidden) +{ + if ((bp->hide == 0) || (hidden == 1)) { + if (selstatus == SELECT) { + bp->f1 |= flag; + return true; + } + else { + bp->f1 &= ~flag; + return true; + } + } + + return false; +} + +static bool swap_selection_beztriple(BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + return select_beztriple(bezt, DESELECT, SELECT, VISIBLE); + else + return select_beztriple(bezt, SELECT, SELECT, VISIBLE); +} + +static bool swap_selection_bpoint(BPoint *bp) +{ + if (bp->f1 & SELECT) + return select_bpoint(bp, DESELECT, SELECT, VISIBLE); + else + return select_bpoint(bp, SELECT, SELECT, VISIBLE); +} + + +void ED_curve_select_all(EditNurb *editnurb) +{ + Nurb *nu; + int a; + for (nu = editnurb->nurbs.first; nu; nu = nu->next) { + if (nu->bezt) { + BezTriple *bezt; + for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { + if (bezt->hide == 0) { + bezt->f1 |= SELECT; + bezt->f2 |= SELECT; + bezt->f3 |= SELECT; + } + } + } + else if (nu->bp) { + BPoint *bp; + for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (bp->hide == 0) + bp->f1 |= SELECT; + } + } + } +} + +void ED_curve_select_swap(EditNurb *editnurb, bool hide_handles) +{ + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int a; + + for (nu = editnurb->nurbs.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (bezt->hide == 0) { + bezt->f2 ^= SELECT; /* always do the center point */ + if (!hide_handles) { + bezt->f1 ^= SELECT; + bezt->f3 ^= SELECT; + } + } + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + swap_selection_bpoint(bp); + bp++; + } + } + } +} + +/** + * \param next: -1/1 for prev/next + * \param cont: when true select continuously + * \param selstatus: inverts behavior + */ +static void select_adjacent_cp( + ListBase *editnurb, short next, + const bool cont, const bool selstatus) +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + bool lastsel = false; + + if (next == 0) return; + + for (nu = editnurb->first; nu; nu = nu->next) { + lastsel = false; + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt = nu->bezt; + if (next < 0) bezt = &nu->bezt[a - 1]; + while (a--) { + if (a - abs(next) < 0) break; + if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) { + bezt += next; + if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) { + short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); + if ((sel == 1) && (cont == 0)) lastsel = true; + } + } + else { + bezt += next; + lastsel = false; + } + /* move around in zigzag way so that we go through each */ + bezt -= (next - next / abs(next)); + } + } + else { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + if (next < 0) bp = &nu->bp[a - 1]; + while (a--) { + if (a - abs(next) < 0) break; + if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) { + bp += next; + if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) { + short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); + if ((sel == 1) && (cont == 0)) lastsel = true; + } + } + else { + bp += next; + lastsel = false; + } + /* move around in zigzag way so that we go through each */ + bp -= (next - next / abs(next)); + } + } + } +} + +/**************** select start/end operators **************/ + +/* (de)selects first or last of visible part of each Nurb depending on selFirst + * selFirst: defines the end of which to select + * doswap: defines if selection state of each first/last control point is swapped + * selstatus: selection status in case doswap is false + */ +static void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus) +{ + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + Curve *cu; + int a; + + if (obedit == NULL) return; + + cu = (Curve *)obedit->data; + cu->actvert = CU_ACT_NONE; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + + /* which point? */ + if (selfirst == LAST) { /* select last */ + bezt = &nu->bezt[a - 1]; + } + else { /* select first */ + bezt = nu->bezt; + } + + while (a--) { + bool sel; + if (doswap) sel = swap_selection_beztriple(bezt); + else sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); + + if (sel == true) break; + } + } + else { + a = nu->pntsu * nu->pntsv; + + /* which point? */ + if (selfirst == LAST) { /* select last */ + bp = &nu->bp[a - 1]; + } + else { /* select first */ + bp = nu->bp; + } + + while (a--) { + if (bp->hide == 0) { + bool sel; + if (doswap) sel = swap_selection_bpoint(bp); + else sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); + + if (sel == true) break; + } + } + } + } +} + +static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + + selectend_nurb(obedit, FIRST, true, DESELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + BKE_curve_nurb_vert_active_validate(obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_de_select_first(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "(De)select First"; + ot->idname = "CURVE_OT_de_select_first"; + ot->description = "(De)select first of visible part of each NURBS"; + + /* api cfirstbacks */ + ot->exec = de_select_first_exec; + ot->poll = ED_operator_editcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + + selectend_nurb(obedit, LAST, true, DESELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + BKE_curve_nurb_vert_active_validate(obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_de_select_last(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "(De)select Last"; + ot->idname = "CURVE_OT_de_select_last"; + ot->description = "(De)select last of visible part of each NURBS"; + + /* api clastbacks */ + ot->exec = de_select_last_exec; + ot->poll = ED_operator_editcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/******************* de select all operator ***************/ + +static bool nurb_has_selected_cps(ListBase *editnurb) +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + if (bezt->hide == 0) { + if ((bezt->f1 & SELECT) || + (bezt->f2 & SELECT) || + (bezt->f3 & SELECT)) + { + return 1; + } + } + bezt++; + } + } + else { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + if ((bp->hide == 0) && (bp->f1 & SELECT)) return 1; + bp++; + } + } + } + + return 0; +} + +static int de_select_all_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Curve *cu = obedit->data; + ListBase *editnurb = object_editcurve_get(obedit); + int action = RNA_enum_get(op->ptr, "action"); + + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + if (nurb_has_selected_cps(editnurb)) + action = SEL_DESELECT; + } + + switch (action) { + case SEL_SELECT: + ED_curve_select_all(cu->editnurb); + break; + case SEL_DESELECT: + ED_curve_deselect_all(cu->editnurb); + break; + case SEL_INVERT: + ED_curve_select_swap(cu->editnurb, (cu->drawflag & CU_HIDE_HANDLES) != 0); + break; + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + BKE_curve_nurb_vert_active_validate(cu); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "(De)select All"; + ot->idname = "CURVE_OT_select_all"; + ot->description = "(De)select all control points"; + + /* api callbacks */ + ot->exec = de_select_all_exec; + ot->poll = ED_operator_editsurfcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_select_all(ot); +} + + + +/***************** select linked operator ******************/ + +static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + Curve *cu = (Curve *)obedit->data; + EditNurb *editnurb = cu->editnurb; + ListBase *nurbs = &editnurb->nurbs; + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + for (nu = nurbs->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if ((bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT)) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + select_beztriple(bezt, SELECT, SELECT, VISIBLE); + bezt++; + } + break; + } + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + if (bp->f1 & SELECT) { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + select_bpoint(bp, SELECT, SELECT, VISIBLE); + bp++; + } + break; + } + bp++; + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + return select_linked_exec(C, op); +} + +void CURVE_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Linked All"; + ot->idname = "CURVE_OT_select_linked"; + ot->description = "Select all control points linked to active one"; + + /* api callbacks */ + ot->exec = select_linked_exec; + ot->invoke = select_linked_invoke; + ot->poll = ED_operator_editsurfcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ +} + + +/***************** select linked pick operator ******************/ + +static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *obedit = CTX_data_edit_object(C); + ViewContext vc; + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + const bool select = !RNA_boolean_get(op->ptr, "deselect"); + + view3d_operator_needs_opengl(C); + view3d_set_viewcontext(C, &vc); + + if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu, &bezt, &bp, NULL)) { + return OPERATOR_CANCELLED; + } + + if (bezt) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + select_beztriple(bezt, select, SELECT, VISIBLE); + bezt++; + } + } + else if (bp) { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + select_bpoint(bp, select, SELECT, VISIBLE); + bp++; + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + if (!select) { + BKE_curve_nurb_vert_active_validate(obedit->data); + } + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_linked_pick(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Linked"; + ot->idname = "CURVE_OT_select_linked_pick"; + ot->description = "Select all control points linked to already selected ones"; + + /* api callbacks */ + ot->invoke = select_linked_pick_invoke; + ot->poll = ED_operator_editsurfcurve_region_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked control points rather than selecting them"); +} + +/***************** select row operator **********************/ + +static int select_row_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + Curve *cu = obedit->data; + ListBase *editnurb = object_editcurve_get(obedit); + static BPoint *last = NULL; + static int direction = 0; + Nurb *nu = NULL; + BPoint *bp = NULL; + int u = 0, v = 0, a, b; + + if (!BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bp)) + return OPERATOR_CANCELLED; + + if (last == bp) { + direction = 1 - direction; + BKE_nurbList_flag_set(editnurb, 0); + } + last = bp; + + u = cu->actvert % nu->pntsu; + v = cu->actvert / nu->pntsu; + bp = nu->bp; + for (a = 0; a < nu->pntsv; a++) { + for (b = 0; b < nu->pntsu; b++, bp++) { + if (direction) { + if (a == v) select_bpoint(bp, SELECT, SELECT, VISIBLE); + } + else { + if (b == u) select_bpoint(bp, SELECT, SELECT, VISIBLE); + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_row(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Control Point Row"; + ot->idname = "CURVE_OT_select_row"; + ot->description = "Select a row of control points including active one"; + + /* api callbacks */ + ot->exec = select_row_exec; + ot->poll = ED_operator_editsurf; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/***************** select next operator **********************/ + +static int select_next_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb = object_editcurve_get(obedit); + + select_adjacent_cp(editnurb, 1, 0, SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_next(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Next"; + ot->idname = "CURVE_OT_select_next"; + ot->description = "Select control points following already selected ones along the curves"; + + /* api callbacks */ + ot->exec = select_next_exec; + ot->poll = ED_operator_editcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/***************** select previous operator **********************/ + +static int select_previous_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb = object_editcurve_get(obedit); + + select_adjacent_cp(editnurb, -1, 0, SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_previous(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Previous"; + ot->idname = "CURVE_OT_select_previous"; + ot->description = "Select control points preceding already selected ones along the curves"; + + /* api callbacks */ + ot->exec = select_previous_exec; + ot->poll = ED_operator_editcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/***************** select more operator **********************/ + +static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BPoint *bp, *tempbp; + int a; + short sel = 0; + + /* note that NURBS surface is a special case because we mimic */ + /* the behavior of "select more" of mesh tools. */ + /* The algorithm is designed to work in planar cases so it */ + /* may not be optimal always (example: end of NURBS sphere) */ + if (obedit->type == OB_SURF) { + for (nu = editnurb->first; nu; nu = nu->next) { + BLI_bitmap *selbpoints; + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + selbpoints = BLI_BITMAP_NEW(a, "selectlist"); + while (a > 0) { + if ((!BLI_BITMAP_TEST(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) { + /* upper control point */ + if (a % nu->pntsu != 0) { + tempbp = bp - 1; + if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE); + } + + /* left control point. select only if it is not selected already */ + if (a - nu->pntsu > 0) { + sel = 0; + tempbp = bp + nu->pntsu; + if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE); + /* make sure selected bpoint is discarded */ + if (sel == 1) BLI_BITMAP_ENABLE(selbpoints, a - nu->pntsu); + } + + /* right control point */ + if (a + nu->pntsu < nu->pntsu * nu->pntsv) { + tempbp = bp - nu->pntsu; + if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE); + } + + /* lower control point. skip next bp in case selection was made */ + if (a % nu->pntsu != 1) { + sel = 0; + tempbp = bp + 1; + if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE); + if (sel) { + bp++; + a--; + } + } + } + + bp++; + a--; + } + + MEM_freeN(selbpoints); + } + } + else { + select_adjacent_cp(editnurb, 1, 0, SELECT); + select_adjacent_cp(editnurb, -1, 0, SELECT); + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_more(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select More"; + ot->idname = "CURVE_OT_select_more"; + ot->description = "Select control points directly linked to already selected ones"; + + /* api callbacks */ + ot->exec = select_more_exec; + ot->poll = ED_operator_editsurfcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/******************** select less operator *****************/ + +/* basic method: deselect if control point doesn't have all neighbors selected */ +static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int a; + int sel = 0; + short lastsel = false; + + if (obedit->type == OB_SURF) { + for (nu = editnurb->first; nu; nu = nu->next) { + BLI_bitmap *selbpoints; + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + selbpoints = BLI_BITMAP_NEW(a, "selectlist"); + while (a--) { + if ((bp->hide == 0) && (bp->f1 & SELECT)) { + sel = 0; + + /* check if neighbors have been selected */ + /* edges of surface are an exception */ + if ((a + 1) % nu->pntsu == 0) { + sel++; + } + else { + bp--; + if (BLI_BITMAP_TEST(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++; + bp++; + } + + if ((a + 1) % nu->pntsu == 1) { + sel++; + } + else { + bp++; + if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; + bp--; + } + + if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) { + sel++; + } + else { + bp -= nu->pntsu; + if (BLI_BITMAP_TEST(selbpoints, a + nu->pntsu) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++; + bp += nu->pntsu; + } + + if (a < nu->pntsu) { + sel++; + } + else { + bp += nu->pntsu; + if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; + bp -= nu->pntsu; + } + + if (sel != 4) { + select_bpoint(bp, DESELECT, SELECT, VISIBLE); + BLI_BITMAP_ENABLE(selbpoints, a); + } + } + else { + lastsel = false; + } + + bp++; + } + + MEM_freeN(selbpoints); + } + } + else { + for (nu = editnurb->first; nu; nu = nu->next) { + lastsel = false; + /* check what type of curve/nurb it is */ + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + if ((bezt->hide == 0) && (bezt->f2 & SELECT)) { + sel = (lastsel == 1); + + /* check if neighbors have been selected */ + /* first and last are exceptions */ + if (a == nu->pntsu - 1) { + sel++; + } + else { + bezt--; + if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++; + bezt++; + } + + if (a == 0) { + sel++; + } + else { + bezt++; + if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++; + bezt--; + } + + if (sel != 2) { + select_beztriple(bezt, DESELECT, SELECT, VISIBLE); + lastsel = true; + } + else { + lastsel = false; + } + } + else { + lastsel = false; + } + + bezt++; + } + } + else { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + if ((lastsel == 0) && (bp->hide == 0) && (bp->f1 & SELECT)) { + if (lastsel != 0) sel = 1; + else sel = 0; + + /* first and last are exceptions */ + if (a == nu->pntsu * nu->pntsv - 1) { + sel++; + } + else { + bp--; + if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; + bp++; + } + + if (a == 0) { + sel++; + } + else { + bp++; + if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; + bp--; + } + + if (sel != 2) { + select_bpoint(bp, DESELECT, SELECT, VISIBLE); + lastsel = true; + } + else { + lastsel = false; + } + } + else { + lastsel = false; + } + + bp++; + } + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + BKE_curve_nurb_vert_active_validate(obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_less(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Less"; + ot->idname = "CURVE_OT_select_less"; + ot->description = "Reduce current selection by deselecting boundary elements"; + + /* api callbacks */ + ot->exec = select_less_exec; + ot->poll = ED_operator_editsurfcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** select random *********************/ + +static void curve_select_random(ListBase *editnurb, float randfac, bool select) +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (!bezt->hide) { + if (BLI_frand() < randfac) { + select_beztriple(bezt, select, SELECT, VISIBLE); + } + } + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + + while (a--) { + if (!bp->hide) { + if (BLI_frand() < randfac) { + select_bpoint(bp, select, SELECT, VISIBLE); + } + } + bp++; + } + } + } +} + +static int curve_select_random_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb = object_editcurve_get(obedit); + const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; + + curve_select_random(editnurb, randfac, select); + BKE_curve_nurb_vert_active_validate(obedit->data); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_random(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Random"; + ot->idname = "CURVE_OT_select_random"; + ot->description = "Randomly select some control points"; + + /* api callbacks */ + ot->exec = curve_select_random_exec; + ot->poll = ED_operator_editsurfcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, + "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f); + WM_operator_properties_select_action_simple(ot, SEL_SELECT); +} + +/********************* every nth number of point *******************/ + +static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int offset) +{ + int a, start; + + start = bezt - nu->bezt; + a = nu->pntsu; + bezt = &nu->bezt[a - 1]; + + while (a--) { + const int depth = abs(start - a); + if ((offset + depth) % (skip + nth) >= skip) { + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + } + + bezt--; + } +} + +static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset) +{ + int a, startrow, startpnt; + int row, pnt; + + startrow = (bp - nu->bp) / nu->pntsu; + startpnt = (bp - nu->bp) % nu->pntsu; + + a = nu->pntsu * nu->pntsv; + bp = &nu->bp[a - 1]; + row = nu->pntsv - 1; + pnt = nu->pntsu - 1; + + while (a--) { + const int depth = abs(pnt - startpnt) + abs(row - startrow); + if ((offset + depth) % (skip + nth) >= skip) { + select_bpoint(bp, DESELECT, SELECT, HIDDEN); + } + + pnt--; + if (pnt < 0) { + pnt = nu->pntsu - 1; + row--; + } + + bp--; + } +} + +bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset) +{ + Nurb *nu = NULL; + void *vert = NULL; + + if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) + return false; + + if (nu->bezt) { + select_nth_bezt(nu, vert, nth, skip, offset); + } + else { + select_nth_bp(nu, vert, nth, skip, offset); + } + + return true; +} + +static int select_nth_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + const int nth = RNA_int_get(op->ptr, "nth") - 1; + const int skip = RNA_int_get(op->ptr, "skip"); + int offset = RNA_int_get(op->ptr, "offset"); + + /* so input of offset zero ends up being (nth - 1) */ + offset = mod_i(offset, nth + skip); + + if (!ED_curve_select_nth(obedit->data, nth, skip, offset)) { + if (obedit->type == OB_SURF) { + BKE_report(op->reports, RPT_ERROR, "Surface has not got active point"); + } + else { + BKE_report(op->reports, RPT_ERROR, "Curve has not got active point"); + } + + return OPERATOR_CANCELLED; + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void CURVE_OT_select_nth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Checker Deselect"; + ot->description = "Deselect every other vertex"; + ot->idname = "CURVE_OT_select_nth"; + + /* api callbacks */ + ot->exec = select_nth_exec; + ot->poll = ED_operator_editsurfcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100); + RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100); + RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100); +} |