Select Shortest Path for edit-curve
D1391 by @pink.vertex with own fixes/edits
This commit is contained in:
parent
ee1b1b9e59
commit
cdbb60b0a3
@ -94,10 +94,11 @@ void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsig
|
|||||||
|
|
||||||
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
|
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
|
||||||
|
|
||||||
void BKE_curve_nurb_active_set(struct Curve *cu, struct Nurb *nu);
|
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert);
|
||||||
|
void BKE_curve_nurb_active_set(struct Curve *cu, const struct Nurb *nu);
|
||||||
struct Nurb *BKE_curve_nurb_active_get(struct Curve *cu);
|
struct Nurb *BKE_curve_nurb_active_get(struct Curve *cu);
|
||||||
void *BKE_curve_vert_active_get(struct Curve *cu);
|
void *BKE_curve_vert_active_get(struct Curve *cu);
|
||||||
void BKE_curve_nurb_vert_active_set(struct Curve *cu, struct Nurb *nu, void *vert);
|
void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, const void *vert);
|
||||||
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert);
|
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert);
|
||||||
void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
|
void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
|
||||||
|
|
||||||
@ -166,6 +167,9 @@ bool BKE_nurb_type_convert(struct Nurb *nu, const short type, const bool use_han
|
|||||||
void BKE_nurb_points_add(struct Nurb *nu, int number);
|
void BKE_nurb_points_add(struct Nurb *nu, int number);
|
||||||
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number);
|
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number);
|
||||||
|
|
||||||
|
int BKE_nurb_index_from_uv(struct Nurb *nu, int u, int v);
|
||||||
|
void BKE_nurb_index_to_uv(struct Nurb *nu, int index, int *r_u, int *r_v);
|
||||||
|
|
||||||
struct BezTriple *BKE_nurb_bezt_get_next(struct Nurb *nu, struct BezTriple *bezt);
|
struct BezTriple *BKE_nurb_bezt_get_next(struct Nurb *nu, struct BezTriple *bezt);
|
||||||
struct BezTriple *BKE_nurb_bezt_get_prev(struct Nurb *nu, struct BezTriple *bezt);
|
struct BezTriple *BKE_nurb_bezt_get_prev(struct Nurb *nu, struct BezTriple *bezt);
|
||||||
struct BPoint *BKE_nurb_bpoint_get_next(struct Nurb *nu, struct BPoint *bp);
|
struct BPoint *BKE_nurb_bpoint_get_next(struct Nurb *nu, struct BPoint *bp);
|
||||||
|
@ -737,6 +737,41 @@ void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int BKE_nurb_index_from_uv(
|
||||||
|
Nurb *nu,
|
||||||
|
int u, int v)
|
||||||
|
{
|
||||||
|
const int totu = nu->pntsu;
|
||||||
|
const int totv = nu->pntsv;
|
||||||
|
|
||||||
|
if (nu->flagu & CU_NURB_CYCLIC) {
|
||||||
|
u = mod_i(u, totu);
|
||||||
|
}
|
||||||
|
else if (u < 0 || u >= totu) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nu->flagv & CU_NURB_CYCLIC) {
|
||||||
|
v = mod_i(v, totv);
|
||||||
|
}
|
||||||
|
else if (v < 0 || v >= totv) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (v * totu) + u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_nurb_index_to_uv(
|
||||||
|
Nurb *nu, int index,
|
||||||
|
int *r_u, int *r_v)
|
||||||
|
{
|
||||||
|
const int totu = nu->pntsu;
|
||||||
|
const int totv = nu->pntsv;
|
||||||
|
BLI_assert(index >= 0 && index < (nu->pntsu * nu->pntsv));
|
||||||
|
*r_u = (index % totu);
|
||||||
|
*r_v = (index / totu) % totv;
|
||||||
|
}
|
||||||
|
|
||||||
BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
|
BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
|
||||||
{
|
{
|
||||||
BezTriple *bezt_next;
|
BezTriple *bezt_next;
|
||||||
@ -4204,7 +4239,7 @@ ListBase *BKE_curve_nurbs_get(Curve *cu)
|
|||||||
return &cu->nurb;
|
return &cu->nurb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_curve_nurb_active_set(Curve *cu, Nurb *nu)
|
void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
|
||||||
{
|
{
|
||||||
if (nu == NULL) {
|
if (nu == NULL) {
|
||||||
cu->actnu = CU_ACT_NONE;
|
cu->actnu = CU_ACT_NONE;
|
||||||
@ -4231,21 +4266,26 @@ void *BKE_curve_vert_active_get(Curve *cu)
|
|||||||
return vert;
|
return vert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
|
||||||
|
{
|
||||||
|
if (nu->type == CU_BEZIER) {
|
||||||
|
BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
|
||||||
|
return (BezTriple *)vert - nu->bezt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
|
||||||
|
return (BPoint *)vert - nu->bp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Set active nurb and active vert for curve */
|
/* Set active nurb and active vert for curve */
|
||||||
void BKE_curve_nurb_vert_active_set(Curve *cu, Nurb *nu, void *vert)
|
void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
|
||||||
{
|
{
|
||||||
if (nu) {
|
if (nu) {
|
||||||
BKE_curve_nurb_active_set(cu, nu);
|
BKE_curve_nurb_active_set(cu, nu);
|
||||||
|
|
||||||
if (vert) {
|
if (vert) {
|
||||||
if (nu->type == CU_BEZIER) {
|
cu->actvert = BKE_curve_nurb_vert_index_get(nu, vert);
|
||||||
BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
|
|
||||||
cu->actvert = (BezTriple *)vert - nu->bezt;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
|
|
||||||
cu->actvert = (BPoint *)vert - nu->bp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cu->actvert = CU_ACT_NONE;
|
cu->actvert = CU_ACT_NONE;
|
||||||
|
@ -151,6 +151,7 @@ void CURVE_OT_select_less(struct wmOperatorType *ot);
|
|||||||
void CURVE_OT_select_random(struct wmOperatorType *ot);
|
void CURVE_OT_select_random(struct wmOperatorType *ot);
|
||||||
void CURVE_OT_select_nth(struct wmOperatorType *ot);
|
void CURVE_OT_select_nth(struct wmOperatorType *ot);
|
||||||
void CURVE_OT_select_similar(struct wmOperatorType *ot);
|
void CURVE_OT_select_similar(struct wmOperatorType *ot);
|
||||||
|
void CURVE_OT_shortest_path_pick(struct wmOperatorType *ot);
|
||||||
|
|
||||||
/* editcurve_add.c */
|
/* editcurve_add.c */
|
||||||
void CURVE_OT_primitive_bezier_curve_add(struct wmOperatorType *ot);
|
void CURVE_OT_primitive_bezier_curve_add(struct wmOperatorType *ot);
|
||||||
|
@ -129,6 +129,7 @@ void ED_operatortypes_curve(void)
|
|||||||
WM_operatortype_append(CURVE_OT_select_random);
|
WM_operatortype_append(CURVE_OT_select_random);
|
||||||
WM_operatortype_append(CURVE_OT_select_nth);
|
WM_operatortype_append(CURVE_OT_select_nth);
|
||||||
WM_operatortype_append(CURVE_OT_select_similar);
|
WM_operatortype_append(CURVE_OT_select_similar);
|
||||||
|
WM_operatortype_append(CURVE_OT_shortest_path_pick);
|
||||||
|
|
||||||
WM_operatortype_append(CURVE_OT_switch_direction);
|
WM_operatortype_append(CURVE_OT_switch_direction);
|
||||||
WM_operatortype_append(CURVE_OT_subdivide);
|
WM_operatortype_append(CURVE_OT_subdivide);
|
||||||
@ -249,6 +250,8 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
|
|||||||
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
|
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
|
||||||
RNA_boolean_set(kmi->ptr, "deselect", true);
|
RNA_boolean_set(kmi->ptr, "deselect", true);
|
||||||
|
|
||||||
|
WM_keymap_add_item(keymap, "CURVE_OT_shortest_path_pick", SELECTMOUSE, KM_CLICK, KM_CTRL, 0);
|
||||||
|
|
||||||
WM_keymap_add_item(keymap, "CURVE_OT_separate", PKEY, KM_PRESS, 0, 0);
|
WM_keymap_add_item(keymap, "CURVE_OT_separate", PKEY, KM_PRESS, 0, 0);
|
||||||
WM_keymap_add_item(keymap, "CURVE_OT_split", YKEY, KM_PRESS, 0, 0);
|
WM_keymap_add_item(keymap, "CURVE_OT_split", YKEY, KM_PRESS, 0, 0);
|
||||||
WM_keymap_add_item(keymap, "CURVE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
|
WM_keymap_add_item(keymap, "CURVE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#include "BLI_bitmap.h"
|
#include "BLI_bitmap.h"
|
||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
#include "BLI_rand.h"
|
#include "BLI_rand.h"
|
||||||
|
#include "BLI_heap.h"
|
||||||
|
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_curve.h"
|
#include "BKE_curve.h"
|
||||||
@ -1496,3 +1496,233 @@ void CURVE_OT_select_similar(wmOperatorType *ot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
Loading…
Reference in New Issue
Block a user