This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/curve/editcurve_select.c

1157 lines
26 KiB
C
Raw Normal View History

/*
* ***** 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);
}