2015-07-08 23:24:16 +10:00
|
|
|
/*
|
|
|
|
* ***** 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.
|
|
|
|
*
|
2015-07-09 02:58:40 +10:00
|
|
|
* Contributor(s): John Roper
|
2015-07-08 23:24:16 +10:00
|
|
|
*
|
|
|
|
* ***** 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"
|
2015-07-09 13:14:09 +10:00
|
|
|
#include "BLI_heap.h"
|
2015-07-08 23:24:16 +10:00
|
|
|
|
|
|
|
#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);
|
|
|
|
}
|
|
|
|
|
2015-07-09 14:31:27 +10:00
|
|
|
bool ED_curve_nurb_select_check(Curve *cu, Nurb *nu)
|
|
|
|
{
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
BezTriple *bezt;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
|
|
|
if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BPoint *bp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
|
|
|
if (bp->f1 & SELECT) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ED_curve_nurb_select_count(Curve *cu, Nurb *nu)
|
|
|
|
{
|
|
|
|
int sel = 0;
|
|
|
|
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
BezTriple *bezt;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
|
|
|
if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
|
2015-08-03 23:06:03 +10:00
|
|
|
sel++;
|
2015-07-09 14:31:27 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BPoint *bp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
|
|
|
if (bp->f1 & SELECT) {
|
2015-08-03 23:06:03 +10:00
|
|
|
sel++;
|
2015-07-09 14:31:27 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ED_curve_nurb_select_all(Nurb *nu)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (nu->bezt) {
|
|
|
|
BezTriple *bezt;
|
|
|
|
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
|
|
|
if (bezt->hide == 0) {
|
|
|
|
BEZT_SEL_ALL(bezt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (nu->bp) {
|
|
|
|
BPoint *bp;
|
|
|
|
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
|
|
|
if (bp->hide == 0) {
|
|
|
|
bp->f1 |= SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-08 23:24:16 +10:00
|
|
|
|
|
|
|
void ED_curve_select_all(EditNurb *editnurb)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
|
2015-07-09 14:31:27 +10:00
|
|
|
ED_curve_nurb_select_all(nu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ED_curve_nurb_deselect_all(Nurb *nu)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (nu->bezt) {
|
|
|
|
BezTriple *bezt;
|
|
|
|
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
|
|
|
BEZT_DESEL_ALL(bezt);
|
2015-07-08 23:24:16 +10:00
|
|
|
}
|
2015-07-09 14:31:27 +10:00
|
|
|
}
|
|
|
|
else if (nu->bp) {
|
|
|
|
BPoint *bp;
|
|
|
|
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
|
|
|
bp->f1 &= ~SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ED_curve_select_check(Curve *cu, struct EditNurb *editnurb)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
|
|
|
|
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
|
|
|
|
if (ED_curve_nurb_select_check(cu, nu)) {
|
|
|
|
return true;
|
2015-07-08 23:24:16 +10:00
|
|
|
}
|
|
|
|
}
|
2015-07-09 14:31:27 +10:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ED_curve_deselect_all(EditNurb *editnurb)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
|
|
|
|
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
|
|
|
|
ED_curve_nurb_deselect_all(nu);
|
|
|
|
}
|
2015-07-08 23:24:16 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int de_select_all_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
|
|
Curve *cu = obedit->data;
|
|
|
|
int action = RNA_enum_get(op->ptr, "action");
|
|
|
|
|
|
|
|
if (action == SEL_TOGGLE) {
|
|
|
|
action = SEL_SELECT;
|
2015-07-09 14:31:27 +10:00
|
|
|
if (ED_curve_select_check(cu, cu->editnurb)) {
|
2015-07-08 23:24:16 +10:00
|
|
|
action = SEL_DESELECT;
|
2015-07-09 14:31:27 +10:00
|
|
|
}
|
2015-07-08 23:24:16 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (nu = nurbs->first; nu; nu = nu->next) {
|
2015-07-09 14:31:27 +10:00
|
|
|
if (ED_curve_nurb_select_check(cu, nu)) {
|
|
|
|
ED_curve_nurb_select_all(nu);
|
2015-07-08 23:24:16 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2015-07-09 02:58:40 +10:00
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Select Similar */
|
|
|
|
|
|
|
|
/** \name Select Similar
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
SIM_CMP_EQ = 0,
|
|
|
|
SIM_CMP_GT,
|
|
|
|
SIM_CMP_LT,
|
|
|
|
};
|
|
|
|
|
|
|
|
static EnumPropertyItem curve_prop_similar_compare_types[] = {
|
|
|
|
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
|
|
|
|
{SIM_CMP_GT, "GREATER", 0, "Greater", ""},
|
|
|
|
{SIM_CMP_LT, "LESS", 0, "Less", ""},
|
|
|
|
|
|
|
|
{0, NULL, 0, NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
SIMCURHAND_TYPE = 0,
|
|
|
|
SIMCURHAND_RADIUS,
|
|
|
|
SIMCURHAND_WEIGHT,
|
|
|
|
SIMCURHAND_DIRECTION,
|
|
|
|
};
|
|
|
|
|
|
|
|
static EnumPropertyItem curve_prop_similar_types[] = {
|
|
|
|
{SIMCURHAND_TYPE, "TYPE", 0, "Type", ""},
|
|
|
|
{SIMCURHAND_RADIUS, "RADIUS", 0, "Radius", ""},
|
|
|
|
{SIMCURHAND_WEIGHT, "WEIGHT", 0, "Weight", ""},
|
|
|
|
{SIMCURHAND_DIRECTION, "DIRECTION", 0, "Direction", ""},
|
|
|
|
{0, NULL, 0, NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int curve_select_similar_cmp_fl(const float delta, const float thresh, const int compare)
|
|
|
|
{
|
|
|
|
switch (compare) {
|
|
|
|
case SIM_CMP_EQ:
|
|
|
|
return (fabsf(delta) <= thresh);
|
|
|
|
case SIM_CMP_GT:
|
|
|
|
return ((delta + thresh) >= 0.0f);
|
|
|
|
case SIM_CMP_LT:
|
|
|
|
return ((delta - thresh) <= 0.0f);
|
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void curve_select_similar_direction__bezt(Nurb *nu, const float dir_ref[3], float angle_cos)
|
|
|
|
{
|
|
|
|
BezTriple *bezt;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
|
|
|
if (!bezt->hide) {
|
|
|
|
float dir[3];
|
|
|
|
BKE_nurb_bezt_calc_normal(nu, bezt, dir);
|
|
|
|
if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
|
|
|
|
select_beztriple(bezt, SELECT, SELECT, VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void curve_select_similar_direction__bp(Nurb *nu, const float dir_ref[3], float angle_cos)
|
|
|
|
{
|
|
|
|
BPoint *bp;
|
|
|
|
int i;
|
|
|
|
|
2015-07-09 14:31:27 +10:00
|
|
|
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
2015-07-09 02:58:40 +10:00
|
|
|
if (!bp->hide) {
|
|
|
|
float dir[3];
|
|
|
|
BKE_nurb_bpoint_calc_normal(nu, bp, dir);
|
|
|
|
if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
|
|
|
|
select_bpoint(bp, SELECT, SELECT, VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool curve_select_similar_direction(ListBase *editnurb, Curve *cu, float thresh)
|
|
|
|
{
|
|
|
|
Nurb *nu, *act_nu;
|
|
|
|
void *act_vert;
|
|
|
|
float dir[3];
|
|
|
|
float angle_cos;
|
|
|
|
|
|
|
|
if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (act_nu->type == CU_BEZIER) {
|
|
|
|
BKE_nurb_bezt_calc_normal(act_nu, act_vert, dir);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_nurb_bpoint_calc_normal(act_nu, act_vert, dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* map 0-1 to radians, 'cos' for comparison */
|
2015-07-25 13:26:20 +10:00
|
|
|
angle_cos = cosf(thresh * (float)M_PI_2);
|
2015-07-09 02:58:40 +10:00
|
|
|
|
|
|
|
for (nu = editnurb->first; nu; nu = nu->next) {
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
curve_select_similar_direction__bezt(nu, dir, angle_cos);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curve_select_similar_direction__bp(nu, dir, angle_cos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void curve_select_similar_radius__bezt(Nurb *nu, float radius_ref, int compare, float thresh)
|
|
|
|
{
|
|
|
|
BezTriple *bezt;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
|
|
|
if (!bezt->hide) {
|
|
|
|
if (curve_select_similar_cmp_fl(bezt->radius - radius_ref, thresh, compare)) {
|
|
|
|
select_beztriple(bezt, SELECT, SELECT, VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void curve_select_similar_radius__bp(Nurb *nu, float radius_ref, int compare, float thresh)
|
|
|
|
{
|
|
|
|
BPoint *bp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
|
|
|
if (!bp->hide) {
|
|
|
|
if (curve_select_similar_cmp_fl(bp->radius - radius_ref, thresh, compare)) {
|
|
|
|
select_bpoint(bp, SELECT, SELECT, VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool curve_select_similar_radius(ListBase *editnurb, Curve *cu, float compare, float thresh)
|
|
|
|
{
|
|
|
|
Nurb *nu, *act_nu;
|
|
|
|
void *act_vert;
|
|
|
|
float radius_ref;
|
|
|
|
|
|
|
|
if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (act_nu->type == CU_BEZIER) {
|
|
|
|
radius_ref = ((BezTriple *)act_vert)->radius;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
radius_ref = ((BPoint *)act_vert)->radius;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make relative */
|
|
|
|
thresh *= radius_ref;
|
|
|
|
|
|
|
|
for (nu = editnurb->first; nu; nu = nu->next) {
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
curve_select_similar_radius__bezt(nu, radius_ref, compare, thresh);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curve_select_similar_radius__bp(nu, radius_ref, compare, thresh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void curve_select_similar_weight__bezt(Nurb *nu, float weight_ref, int compare, float thresh)
|
|
|
|
{
|
|
|
|
BezTriple *bezt;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
|
|
|
|
if (!bezt->hide) {
|
|
|
|
if (curve_select_similar_cmp_fl(bezt->weight - weight_ref, thresh, compare)) {
|
|
|
|
select_beztriple(bezt, SELECT, SELECT, VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void curve_select_similar_weight__bp(Nurb *nu, float weight_ref, int compare, float thresh)
|
|
|
|
{
|
|
|
|
BPoint *bp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
|
|
|
|
if (!bp->hide) {
|
|
|
|
if (curve_select_similar_cmp_fl(bp->weight - weight_ref, thresh, compare)) {
|
|
|
|
select_bpoint(bp, SELECT, SELECT, VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool curve_select_similar_weight(ListBase *editnurb, Curve *cu, float compare, float thresh)
|
|
|
|
{
|
|
|
|
Nurb *nu, *act_nu;
|
|
|
|
void *act_vert;
|
|
|
|
float weight_ref;
|
|
|
|
|
|
|
|
if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (act_nu->type == CU_BEZIER) {
|
|
|
|
weight_ref = ((BezTriple *)act_vert)->weight;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
weight_ref = ((BPoint *)act_vert)->weight;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (nu = editnurb->first; nu; nu = nu->next) {
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
curve_select_similar_weight__bezt(nu, weight_ref, compare, thresh);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curve_select_similar_weight__bp(nu, weight_ref, compare, thresh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool curve_select_similar_type(ListBase *editnurb, Curve *cu)
|
|
|
|
{
|
|
|
|
Nurb *nu, *act_nu;
|
|
|
|
int type_ref;
|
|
|
|
|
|
|
|
/* Get active nurb type */
|
|
|
|
act_nu = BKE_curve_nurb_active_get(cu);
|
|
|
|
|
|
|
|
if (!act_nu)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Get the active nurb type */
|
|
|
|
type_ref = act_nu->type;
|
|
|
|
|
|
|
|
for (nu = editnurb->first; nu; nu = nu->next) {
|
|
|
|
if (nu->type == type_ref) {
|
2015-07-09 14:31:27 +10:00
|
|
|
ED_curve_nurb_select_all(nu);
|
2015-07-09 02:58:40 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int curve_select_similar_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
|
|
Curve *cu = obedit->data;
|
|
|
|
ListBase *editnurb = object_editcurve_get(obedit);
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
/* Get props */
|
|
|
|
const int type = RNA_enum_get(op->ptr, "type");
|
|
|
|
const float thresh = RNA_float_get(op->ptr, "threshold");
|
|
|
|
const int compare = RNA_enum_get(op->ptr, "compare");
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case SIMCURHAND_TYPE:
|
|
|
|
changed = curve_select_similar_type(editnurb, cu);
|
|
|
|
break;
|
|
|
|
case SIMCURHAND_RADIUS:
|
|
|
|
changed = curve_select_similar_radius(editnurb, cu, compare, thresh);
|
|
|
|
break;
|
|
|
|
case SIMCURHAND_WEIGHT:
|
|
|
|
changed = curve_select_similar_weight(editnurb, cu, compare, thresh);
|
|
|
|
break;
|
|
|
|
case SIMCURHAND_DIRECTION:
|
|
|
|
changed = curve_select_similar_direction(editnurb, cu, thresh);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
|
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CURVE_OT_select_similar(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Select Similar";
|
|
|
|
ot->idname = "CURVE_OT_select_similar";
|
|
|
|
ot->description = "Select similar curve points by property type";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = curve_select_similar_exec;
|
|
|
|
ot->poll = ED_operator_editsurfcurve;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", curve_prop_similar_types, SIMCURHAND_WEIGHT, "Type", "");
|
|
|
|
RNA_def_enum(ot->srna, "compare", curve_prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
|
|
|
|
RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.0, 100.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
2015-07-09 13:14:09 +10:00
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Select Shortest Path */
|
|
|
|
|
|
|
|
/** \name Select Path
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static float curve_calc_dist_pair(const Nurb *nu, int a, int b)
|
|
|
|
{
|
|
|
|
const float *a_fl, *b_fl;
|
|
|
|
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
a_fl = nu->bezt[a].vec[1];
|
|
|
|
b_fl = nu->bezt[b].vec[1];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a_fl = nu->bp[a].vec;
|
|
|
|
b_fl = nu->bp[b].vec;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len_v3v3(a_fl, b_fl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static float curve_calc_dist_span(Nurb *nu, int vert_src, int vert_dst)
|
|
|
|
{
|
|
|
|
const int u = nu->pntsu;
|
|
|
|
int i_prev, i;
|
|
|
|
float dist = 0.0f;
|
|
|
|
|
|
|
|
BLI_assert(nu->pntsv == 1);
|
|
|
|
|
|
|
|
i_prev = vert_src;
|
|
|
|
i = (i_prev + 1) % u;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
dist += curve_calc_dist_pair(nu, i_prev, i);
|
|
|
|
|
|
|
|
if (i == vert_dst) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i = (i + 1) % u;
|
|
|
|
}
|
|
|
|
return dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void curve_select_shortest_path_curve(Nurb *nu, int vert_src, int vert_dst)
|
|
|
|
{
|
|
|
|
const int u = nu->pntsu;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (vert_src > vert_dst) {
|
|
|
|
SWAP(int, vert_src, vert_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nu->flagu & CU_NURB_CYCLIC) {
|
|
|
|
if (curve_calc_dist_span(nu, vert_src, vert_dst) >
|
|
|
|
curve_calc_dist_span(nu, vert_dst, vert_src))
|
|
|
|
{
|
|
|
|
SWAP(int, vert_src, vert_dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
i = vert_src;
|
|
|
|
while (true) {
|
|
|
|
if (nu->type & CU_BEZIER) {
|
|
|
|
select_beztriple(&nu->bezt[i], SELECT, SELECT, HIDDEN);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
select_bpoint(&nu->bp[i], SELECT, SELECT, HIDDEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == vert_dst) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i = (i + 1) % u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst)
|
|
|
|
{
|
|
|
|
Heap *heap;
|
|
|
|
|
|
|
|
int i, vert_curr;
|
|
|
|
|
|
|
|
int totu = nu->pntsu;
|
|
|
|
int totv = nu->pntsv;
|
|
|
|
int vert_num = totu * totv;
|
|
|
|
|
|
|
|
/* custom data */
|
|
|
|
struct PointAdj {
|
|
|
|
int vert, vert_prev;
|
|
|
|
float cost;
|
|
|
|
} *data;
|
|
|
|
|
|
|
|
/* init connectivity data */
|
|
|
|
data = MEM_mallocN(sizeof(*data) * vert_num, __func__);
|
|
|
|
for (i = 0; i < vert_num; i++) {
|
|
|
|
data[i].vert = i;
|
|
|
|
data[i].vert_prev = -1;
|
|
|
|
data[i].cost = FLT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* init heap */
|
|
|
|
heap = BLI_heap_new();
|
|
|
|
|
|
|
|
BLI_heap_insert(heap, 0.0f, &data[vert_src].vert);
|
|
|
|
data[vert_src].cost = 0.0f;
|
|
|
|
data[vert_src].vert_prev = vert_src; /* nop */
|
|
|
|
|
|
|
|
while (!BLI_heap_is_empty(heap)) {
|
|
|
|
int axis, sign;
|
|
|
|
int u, v;
|
|
|
|
|
|
|
|
vert_curr = *((int *)BLI_heap_popmin(heap));
|
|
|
|
if (vert_curr == vert_dst) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
BKE_nurb_index_to_uv(nu, vert_curr, &u, &v);
|
|
|
|
|
|
|
|
/* loop over 4 adjacent verts */
|
|
|
|
for (sign = -1; sign != 3; sign += 2) {
|
|
|
|
for (axis = 0; axis != 2; axis += 1) {
|
|
|
|
int uv_other[2] = {u, v};
|
|
|
|
int vert_other;
|
|
|
|
|
|
|
|
uv_other[axis] += sign;
|
|
|
|
|
|
|
|
vert_other = BKE_nurb_index_from_uv(nu, uv_other[0], uv_other[1]);
|
|
|
|
if (vert_other != -1) {
|
|
|
|
const float dist = data[vert_curr].cost + curve_calc_dist_pair(nu, vert_curr, vert_other);
|
|
|
|
|
|
|
|
if (data[vert_other].cost > dist) {
|
|
|
|
data[vert_other].cost = dist;
|
|
|
|
if (data[vert_other].vert_prev == -1) {
|
|
|
|
BLI_heap_insert(heap, data[vert_other].cost, &data[vert_other].vert);
|
|
|
|
}
|
|
|
|
data[vert_other].vert_prev = vert_curr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_heap_free(heap, NULL);
|
|
|
|
|
|
|
|
if (vert_curr == vert_dst) {
|
|
|
|
i = 0;
|
|
|
|
while (vert_curr != vert_src && i++ < vert_num) {
|
|
|
|
if (nu->type == CU_BEZIER) {
|
|
|
|
select_beztriple(&nu->bezt[vert_curr], SELECT, SELECT, HIDDEN);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
select_bpoint(&nu->bp[vert_curr], SELECT, SELECT, HIDDEN);
|
|
|
|
}
|
|
|
|
vert_curr = data[vert_curr].vert_prev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
{
|
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
|
|
Curve *cu = obedit->data;
|
|
|
|
Nurb *nu_src = BKE_curve_nurb_active_get(cu);
|
|
|
|
int vert_src = cu->actvert;
|
|
|
|
|
|
|
|
ViewContext vc;
|
|
|
|
Nurb *nu_dst;
|
|
|
|
BezTriple *bezt_dst;
|
|
|
|
BPoint *bp_dst;
|
|
|
|
int vert_dst;
|
|
|
|
void *vert_dst_p;
|
|
|
|
|
|
|
|
if (vert_src == CU_ACT_NONE) {
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
|
|
|
view3d_set_viewcontext(C, &vc);
|
|
|
|
|
|
|
|
if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu_dst, &bezt_dst, &bp_dst, NULL)) {
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nu_src != nu_dst) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR, "Control point belongs to another spline");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
vert_dst_p = bezt_dst ? (void *)bezt_dst : (void *)bp_dst;
|
|
|
|
vert_dst = BKE_curve_nurb_vert_index_get(nu_dst, vert_dst_p);
|
|
|
|
if (vert_src == vert_dst) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((obedit->type == OB_SURF) && (nu_src->pntsv > 1)) {
|
|
|
|
curve_select_shortest_path_surf(nu_src, vert_src, vert_dst);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curve_select_shortest_path_curve(nu_src, vert_src, vert_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
BKE_curve_nurb_vert_active_set(cu, nu_dst, vert_dst_p);
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CURVE_OT_shortest_path_pick(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Pick Shortest Path";
|
|
|
|
ot->idname = "CURVE_OT_shortest_path_pick";
|
|
|
|
ot->description = "Select shortest path between two selections";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = edcu_shortest_path_pick_invoke;
|
|
|
|
ot->poll = ED_operator_editsurfcurve_region_view3d;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|