Blender  V3.3
editcurve_select.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include "DNA_object_types.h"
9 #include "DNA_scene_types.h"
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "BLI_bitmap.h"
14 #include "BLI_heap_simple.h"
15 #include "BLI_kdtree.h"
16 #include "BLI_listbase.h"
17 #include "BLI_math.h"
18 #include "BLI_rand.h"
19 
20 #include "BKE_context.h"
21 #include "BKE_curve.h"
22 #include "BKE_fcurve.h"
23 #include "BKE_layer.h"
24 #include "BKE_report.h"
25 
26 #include "WM_api.h"
27 #include "WM_types.h"
28 
29 #include "ED_curve.h"
30 #include "ED_object.h"
31 #include "ED_screen.h"
32 #include "ED_select_utils.h"
33 #include "ED_types.h"
34 #include "ED_view3d.h"
35 
36 #include "curve_intern.h"
37 
38 #include "RNA_access.h"
39 #include "RNA_define.h"
40 
41 #include "DEG_depsgraph.h"
42 
43 /* -------------------------------------------------------------------- */
47 bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
48 {
49  if ((bezt->hide == 0) || (hidden == HIDDEN)) {
50  if (selstatus == SELECT) { /* selects */
51  bezt->f1 |= flag;
52  bezt->f2 |= flag;
53  bezt->f3 |= flag;
54  return true;
55  }
56  /* deselects */
57  bezt->f1 &= ~flag;
58  bezt->f2 &= ~flag;
59  bezt->f3 &= ~flag;
60  return true;
61  }
62 
63  return false;
64 }
65 
66 bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
67 {
68  if ((bp->hide == 0) || (hidden == 1)) {
69  if (selstatus == SELECT) {
70  bp->f1 |= flag;
71  return true;
72  }
73  bp->f1 &= ~flag;
74  return true;
75  }
76 
77  return false;
78 }
79 
81 {
82  if (bezt->f2 & SELECT) {
83  return select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
84  }
85  return select_beztriple(bezt, SELECT, SELECT, VISIBLE);
86 }
87 
88 static bool swap_selection_bpoint(BPoint *bp)
89 {
90  if (bp->f1 & SELECT) {
91  return select_bpoint(bp, DESELECT, SELECT, VISIBLE);
92  }
93  return select_bpoint(bp, SELECT, SELECT, VISIBLE);
94 }
95 
96 bool ED_curve_nurb_select_check(const View3D *v3d, const Nurb *nu)
97 {
98  if (nu->type == CU_BEZIER) {
99  const BezTriple *bezt;
100  int i;
101 
102  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
103  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
104  return true;
105  }
106  }
107  }
108  else {
109  const BPoint *bp;
110  int i;
111 
112  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
113  if (bp->f1 & SELECT) {
114  return true;
115  }
116  }
117  }
118  return false;
119 }
120 
121 int ED_curve_nurb_select_count(const View3D *v3d, const Nurb *nu)
122 {
123  int sel = 0;
124 
125  if (nu->type == CU_BEZIER) {
126  const BezTriple *bezt;
127  int i;
128 
129  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
130  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
131  sel++;
132  }
133  }
134  }
135  else {
136  const BPoint *bp;
137  int i;
138 
139  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
140  if (bp->f1 & SELECT) {
141  sel++;
142  }
143  }
144  }
145 
146  return sel;
147 }
148 
150 {
151  bool changed = false;
152  int i;
153  if (nu->bezt) {
154  BezTriple *bezt;
155  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
156  if (bezt->hide == 0) {
157  if (BEZT_ISSEL_ALL(bezt) == false) {
158  BEZT_SEL_ALL(bezt);
159  changed = true;
160  }
161  }
162  }
163  }
164  else if (nu->bp) {
165  BPoint *bp;
166  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
167  if (bp->hide == 0) {
168  if ((bp->f1 & SELECT) == 0) {
169  bp->f1 |= SELECT;
170  changed = true;
171  }
172  }
173  }
174  }
175  return changed;
176 }
177 
179 {
180  bool changed = false;
181  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
182  changed |= ED_curve_nurb_select_all(nu);
183  }
184  return changed;
185 }
186 
188 {
189  bool changed = false;
190  int i;
191  if (nu->bezt) {
192  BezTriple *bezt;
193  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
194  if (BEZT_ISSEL_ANY(bezt)) {
195  BEZT_DESEL_ALL(bezt);
196  changed = true;
197  }
198  }
199  }
200  else if (nu->bp) {
201  BPoint *bp;
202  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
203  if (bp->f1 & SELECT) {
204  bp->f1 &= ~SELECT;
205  changed = true;
206  }
207  }
208  }
209  return changed;
210 }
211 
212 int ED_curve_select_count(const View3D *v3d, const EditNurb *editnurb)
213 {
214  int sel = 0;
215  Nurb *nu;
216 
217  for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
218  sel += ED_curve_nurb_select_count(v3d, nu);
219  }
220 
221  return sel;
222 }
223 
224 bool ED_curve_select_check(const View3D *v3d, const EditNurb *editnurb)
225 {
226  LISTBASE_FOREACH (const Nurb *, nu, &editnurb->nurbs) {
227  if (ED_curve_nurb_select_check(v3d, nu)) {
228  return true;
229  }
230  }
231 
232  return false;
233 }
234 
236 {
237  bool changed = false;
238  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
239  changed |= ED_curve_nurb_deselect_all(nu);
240  }
241  return changed;
242 }
243 
244 bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len)
245 {
246  bool changed_multi = false;
247  for (uint base_index = 0; base_index < bases_len; base_index++) {
248  Object *obedit = bases[base_index]->object;
249  Curve *cu = obedit->data;
250  changed_multi |= ED_curve_deselect_all(cu->editnurb);
252  }
253  return changed_multi;
254 }
255 
257 {
259  ViewContext vc;
261  uint bases_len = 0;
263  vc.view_layer, vc.v3d, &bases_len);
264  bool changed_multi = ED_curve_deselect_all_multi_ex(bases, bases_len);
265  MEM_freeN(bases);
266  return changed_multi;
267 }
268 
269 bool ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
270 {
271  BPoint *bp;
272  BezTriple *bezt;
273  int a;
274  bool changed = false;
275 
276  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
277  if (nu->type == CU_BEZIER) {
278  bezt = nu->bezt;
279  a = nu->pntsu;
280  while (a--) {
281  if (bezt->hide == 0) {
282  bezt->f2 ^= SELECT; /* always do the center point */
283  if (!hide_handles) {
284  bezt->f1 ^= SELECT;
285  bezt->f3 ^= SELECT;
286  }
287  changed = true;
288  }
289  bezt++;
290  }
291  }
292  else {
293  bp = nu->bp;
294  a = nu->pntsu * nu->pntsv;
295  while (a--) {
296  if (bp->hide == 0) {
298  changed = true;
299  }
300  bp++;
301  }
302  }
303  }
304  return changed;
305 }
306 
312 static void select_adjacent_cp(ListBase *editnurb,
313  short next,
314  const bool cont,
315  const bool selstatus)
316 {
317  BezTriple *bezt;
318  BPoint *bp;
319  int a;
320  bool lastsel = false;
321 
322  if (next == 0) {
323  return;
324  }
325 
326  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
327  lastsel = false;
328  if (nu->type == CU_BEZIER) {
329  a = nu->pntsu;
330  bezt = nu->bezt;
331  if (next < 0) {
332  bezt = &nu->bezt[a - 1];
333  }
334  while (a--) {
335  if (a - abs(next) < 0) {
336  break;
337  }
338  if ((lastsel == false) && (bezt->hide == 0) &&
339  ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
340  bezt += next;
341  if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
342  bool sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
343  if (sel && !cont) {
344  lastsel = true;
345  }
346  }
347  }
348  else {
349  bezt += next;
350  lastsel = false;
351  }
352  /* move around in zigzag way so that we go through each */
353  bezt -= (next - next / abs(next));
354  }
355  }
356  else {
357  a = nu->pntsu * nu->pntsv;
358  bp = nu->bp;
359  if (next < 0) {
360  bp = &nu->bp[a - 1];
361  }
362  while (a--) {
363  if (a - abs(next) < 0) {
364  break;
365  }
366  if ((lastsel == false) && (bp->hide == 0) &&
367  ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
368  bp += next;
369  if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
370  bool sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
371  if (sel && !cont) {
372  lastsel = true;
373  }
374  }
375  }
376  else {
377  bp += next;
378  lastsel = false;
379  }
380  /* move around in zigzag way so that we go through each */
381  bp -= (next - next / abs(next));
382  }
383  }
384  }
385 }
386 
389 /* -------------------------------------------------------------------- */
400 static void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus)
401 {
402  ListBase *editnurb = object_editcurve_get(obedit);
403  BPoint *bp;
404  BezTriple *bezt;
405  Curve *cu;
406  int a;
407 
408  if (obedit == NULL) {
409  return;
410  }
411 
412  cu = (Curve *)obedit->data;
413  cu->actvert = CU_ACT_NONE;
414 
415  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
416  if (nu->type == CU_BEZIER) {
417  a = nu->pntsu;
418 
419  /* which point? */
420  if (selfirst == LAST) { /* select last */
421  bezt = &nu->bezt[a - 1];
422  }
423  else { /* select first */
424  bezt = nu->bezt;
425  }
426 
427  while (a--) {
428  bool sel;
429  if (doswap) {
430  sel = swap_selection_beztriple(bezt);
431  }
432  else {
433  sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
434  }
435 
436  if (sel == true) {
437  break;
438  }
439  }
440  }
441  else {
442  a = nu->pntsu * nu->pntsv;
443 
444  /* which point? */
445  if (selfirst == LAST) { /* select last */
446  bp = &nu->bp[a - 1];
447  }
448  else { /* select first */
449  bp = nu->bp;
450  }
451 
452  while (a--) {
453  if (bp->hide == 0) {
454  bool sel;
455  if (doswap) {
456  sel = swap_selection_bpoint(bp);
457  }
458  else {
459  sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
460  }
461 
462  if (sel == true) {
463  break;
464  }
465  }
466  }
467  }
468  }
469 }
470 
472 {
473  ViewLayer *view_layer = CTX_data_view_layer(C);
474  uint objects_len = 0;
476  view_layer, CTX_wm_view3d(C), &objects_len);
477 
478  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
479  Object *obedit = objects[ob_index];
480  selectend_nurb(obedit, FIRST, true, DESELECT);
484  }
485  MEM_freeN(objects);
486  return OPERATOR_FINISHED;
487 }
488 
490 {
491  /* identifiers */
492  ot->name = "(De)select First";
493  ot->idname = "CURVE_OT_de_select_first";
494  ot->description = "(De)select first of visible part of each NURBS";
495 
496  /* api callbacks */
499 
500  /* flags */
502 }
503 
505 {
506  ViewLayer *view_layer = CTX_data_view_layer(C);
507  uint objects_len = 0;
509  view_layer, CTX_wm_view3d(C), &objects_len);
510 
511  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
512  Object *obedit = objects[ob_index];
513  selectend_nurb(obedit, LAST, true, DESELECT);
517  }
518 
519  MEM_freeN(objects);
520  return OPERATOR_FINISHED;
521 }
522 
524 {
525  /* identifiers */
526  ot->name = "(De)select Last";
527  ot->idname = "CURVE_OT_de_select_last";
528  ot->description = "(De)select last of visible part of each NURBS";
529 
530  /* api callbacks */
533 
534  /* flags */
536 }
537 
540 /* -------------------------------------------------------------------- */
545 {
546  int action = RNA_enum_get(op->ptr, "action");
547 
548  ViewLayer *view_layer = CTX_data_view_layer(C);
549  View3D *v3d = CTX_wm_view3d(C);
550  uint objects_len = 0;
552  view_layer, CTX_wm_view3d(C), &objects_len);
553  if (action == SEL_TOGGLE) {
554  action = SEL_SELECT;
555  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
556  Object *obedit = objects[ob_index];
557  Curve *cu = obedit->data;
558 
559  if (ED_curve_select_check(v3d, cu->editnurb)) {
560  action = SEL_DESELECT;
561  break;
562  }
563  }
564  }
565 
566  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
567  Object *obedit = objects[ob_index];
568  Curve *cu = obedit->data;
569  bool changed = false;
570 
571  switch (action) {
572  case SEL_SELECT:
573  changed = ED_curve_select_all(cu->editnurb);
574  break;
575  case SEL_DESELECT:
576  changed = ED_curve_deselect_all(cu->editnurb);
577  break;
578  case SEL_INVERT:
579  changed = ED_curve_select_swap(
580  cu->editnurb, (v3d && (v3d->overlay.handle_display == CURVE_HANDLE_NONE)));
581  break;
582  }
583 
584  if (changed) {
588  }
589  }
590 
591  MEM_freeN(objects);
592  return OPERATOR_FINISHED;
593 }
594 
596 {
597  /* identifiers */
598  ot->name = "(De)select All";
599  ot->idname = "CURVE_OT_select_all";
600  ot->description = "(De)select all control points";
601 
602  /* api callbacks */
605 
606  /* flags */
608 
609  /* properties */
611 }
612 
615 /* -------------------------------------------------------------------- */
620 {
621  ViewLayer *view_layer = CTX_data_view_layer(C);
622  View3D *v3d = CTX_wm_view3d(C);
623 
624  uint objects_len = 0;
626  view_layer, CTX_wm_view3d(C), &objects_len);
627  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
628  Object *obedit = objects[ob_index];
629  Curve *cu = obedit->data;
630  EditNurb *editnurb = cu->editnurb;
631  ListBase *nurbs = &editnurb->nurbs;
632  bool changed = false;
633 
634  LISTBASE_FOREACH (Nurb *, nu, nurbs) {
635  if (ED_curve_nurb_select_check(v3d, nu)) {
636  changed |= ED_curve_nurb_select_all(nu);
637  }
638  }
639 
640  if (changed) {
643  }
644  }
645  MEM_freeN(objects);
646 
647  return OPERATOR_FINISHED;
648 }
649 
650 static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
651 {
652  return select_linked_exec(C, op);
653 }
654 
656 {
657  /* identifiers */
658  ot->name = "Select Linked All";
659  ot->idname = "CURVE_OT_select_linked";
660  ot->description = "Select all control points linked to the current selection";
661 
662  /* api callbacks */
666 
667  /* flags */
669 
670  /* properties */
671 }
672 
675 /* -------------------------------------------------------------------- */
679 static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
680 {
682  ViewContext vc;
683  Nurb *nu;
684  BezTriple *bezt;
685  BPoint *bp;
686  int a;
687  const bool select = !RNA_boolean_get(op->ptr, "deselect");
688  Base *basact = NULL;
689 
692  copy_v2_v2_int(vc.mval, event->mval);
693 
694  if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) {
695  return OPERATOR_CANCELLED;
696  }
697 
698  if (bezt) {
699  a = nu->pntsu;
700  bezt = nu->bezt;
701  while (a--) {
703  bezt++;
704  }
705  }
706  else if (bp) {
707  a = nu->pntsu * nu->pntsv;
708  bp = nu->bp;
709  while (a--) {
711  bp++;
712  }
713  }
714 
715  Object *obedit = basact->object;
716 
719 
720  if (!select) {
722  }
723 
724  return OPERATOR_FINISHED;
725 }
726 
728 {
729  /* identifiers */
730  ot->name = "Select Linked";
731  ot->idname = "CURVE_OT_select_linked_pick";
732  ot->description = "Select all control points linked to already selected ones";
733 
734  /* api callbacks */
737 
738  /* flags */
740 
741  /* properties */
743  "deselect",
744  0,
745  "Deselect",
746  "Deselect linked control points rather than selecting them");
747 }
748 
751 /* -------------------------------------------------------------------- */
756 {
757  Object *obedit = CTX_data_edit_object(C);
758  Curve *cu = obedit->data;
759  ListBase *editnurb = object_editcurve_get(obedit);
760  static BPoint *last = NULL;
761  static int direction = 0;
762  Nurb *nu = NULL;
763  BPoint *bp = NULL;
764  int u = 0, v = 0, a, b;
765 
766  if (!BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bp)) {
767  return OPERATOR_CANCELLED;
768  }
769 
770  if (last == bp) {
771  direction = 1 - direction;
772  BKE_nurbList_flag_set(editnurb, SELECT, false);
773  }
774  last = bp;
775 
776  u = cu->actvert % nu->pntsu;
777  v = cu->actvert / nu->pntsu;
778  bp = nu->bp;
779  for (a = 0; a < nu->pntsv; a++) {
780  for (b = 0; b < nu->pntsu; b++, bp++) {
781  if (direction) {
782  if (a == v) {
784  }
785  }
786  else {
787  if (b == u) {
789  }
790  }
791  }
792  }
793 
796 
797  return OPERATOR_FINISHED;
798 }
799 
801 {
802  /* identifiers */
803  ot->name = "Select Control Point Row";
804  ot->idname = "CURVE_OT_select_row";
805  ot->description = "Select a row of control points including active one";
806 
807  /* api callbacks */
810 
811  /* flags */
813 }
814 
817 /* -------------------------------------------------------------------- */
822 {
823  ViewLayer *view_layer = CTX_data_view_layer(C);
824  uint objects_len = 0;
826  view_layer, CTX_wm_view3d(C), &objects_len);
827 
828  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
829  Object *obedit = objects[ob_index];
830 
831  ListBase *editnurb = object_editcurve_get(obedit);
832  select_adjacent_cp(editnurb, 1, 0, SELECT);
833 
836  }
837  MEM_freeN(objects);
838  return OPERATOR_FINISHED;
839 }
840 
842 {
843  /* identifiers */
844  ot->name = "Select Next";
845  ot->idname = "CURVE_OT_select_next";
846  ot->description = "Select control points following already selected ones along the curves";
847 
848  /* api callbacks */
851 
852  /* flags */
854 }
855 
858 /* -------------------------------------------------------------------- */
863 {
864  ViewLayer *view_layer = CTX_data_view_layer(C);
865  uint objects_len = 0;
867  view_layer, CTX_wm_view3d(C), &objects_len);
868 
869  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
870  Object *obedit = objects[ob_index];
871 
872  ListBase *editnurb = object_editcurve_get(obedit);
873  select_adjacent_cp(editnurb, -1, 0, SELECT);
874 
877  }
878  MEM_freeN(objects);
879  return OPERATOR_FINISHED;
880 }
881 
883 {
884  /* identifiers */
885  ot->name = "Select Previous";
886  ot->idname = "CURVE_OT_select_previous";
887  ot->description = "Select control points preceding already selected ones along the curves";
888 
889  /* api callbacks */
892 
893  /* flags */
895 }
896 
899 /* -------------------------------------------------------------------- */
903 static void curve_select_more(Object *obedit)
904 {
905  ListBase *editnurb = object_editcurve_get(obedit);
906  BPoint *bp, *tempbp;
907  int a;
908  short sel = 0;
909 
910  /* NOTE: NURBS surface is a special case because we mimic
911  * the behavior of "select more" of mesh tools.
912  * The algorithm is designed to work in planar cases so it
913  * may not be optimal always (example: end of NURBS sphere). */
914  if (obedit->type == OB_SURF) {
915  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
916  BLI_bitmap *selbpoints;
917  a = nu->pntsu * nu->pntsv;
918  bp = nu->bp;
919  selbpoints = BLI_BITMAP_NEW(a, "selectlist");
920  while (a > 0) {
921  if ((!BLI_BITMAP_TEST(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) {
922  /* upper control point */
923  if (a % nu->pntsu != 0) {
924  tempbp = bp - 1;
925  if (!(tempbp->f1 & SELECT)) {
926  select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
927  }
928  }
929 
930  /* left control point. select only if it is not selected already */
931  if (a - nu->pntsu > 0) {
932  sel = 0;
933  tempbp = bp + nu->pntsu;
934  if (!(tempbp->f1 & SELECT)) {
935  sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
936  }
937  /* make sure selected bpoint is discarded */
938  if (sel == 1) {
939  BLI_BITMAP_ENABLE(selbpoints, a - nu->pntsu);
940  }
941  }
942 
943  /* right control point */
944  if (a + nu->pntsu < nu->pntsu * nu->pntsv) {
945  tempbp = bp - nu->pntsu;
946  if (!(tempbp->f1 & SELECT)) {
947  select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
948  }
949  }
950 
951  /* lower control point. skip next bp in case selection was made */
952  if (a % nu->pntsu != 1) {
953  sel = 0;
954  tempbp = bp + 1;
955  if (!(tempbp->f1 & SELECT)) {
956  sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
957  }
958  if (sel) {
959  bp++;
960  a--;
961  }
962  }
963  }
964 
965  bp++;
966  a--;
967  }
968 
969  MEM_freeN(selbpoints);
970  }
971  }
972  else {
973  select_adjacent_cp(editnurb, 1, 0, SELECT);
974  select_adjacent_cp(editnurb, -1, 0, SELECT);
975  }
976 }
977 
979 {
980  ViewLayer *view_layer = CTX_data_view_layer(C);
981  uint objects_len = 0;
983  view_layer, CTX_wm_view3d(C), &objects_len);
984  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
985  Object *obedit = objects[ob_index];
986  curve_select_more(obedit);
989  }
990  MEM_freeN(objects);
991  return OPERATOR_FINISHED;
992 }
993 
995 {
996  /* identifiers */
997  ot->name = "Select More";
998  ot->idname = "CURVE_OT_select_more";
999  ot->description = "Select control points at the boundary of each selection region";
1000 
1001  /* api callbacks */
1004 
1005  /* flags */
1007 }
1008 
1011 /* -------------------------------------------------------------------- */
1015 /* basic method: deselect if control point doesn't have all neighbors selected */
1016 static void curve_select_less(Object *obedit)
1017 {
1018  ListBase *editnurb = object_editcurve_get(obedit);
1019  BPoint *bp;
1020  BezTriple *bezt;
1021  int a;
1022  int sel = 0;
1023  bool lastsel = false;
1024 
1025  if (obedit->type == OB_SURF) {
1026  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1027  BLI_bitmap *selbpoints;
1028  a = nu->pntsu * nu->pntsv;
1029  bp = nu->bp;
1030  selbpoints = BLI_BITMAP_NEW(a, "selectlist");
1031  while (a--) {
1032  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1033  sel = 0;
1034 
1035  /* check if neighbors have been selected */
1036  /* edges of surface are an exception */
1037  if ((a + 1) % nu->pntsu == 0) {
1038  sel++;
1039  }
1040  else {
1041  bp--;
1042  if (BLI_BITMAP_TEST(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) {
1043  sel++;
1044  }
1045  bp++;
1046  }
1047 
1048  if ((a + 1) % nu->pntsu == 1) {
1049  sel++;
1050  }
1051  else {
1052  bp++;
1053  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1054  sel++;
1055  }
1056  bp--;
1057  }
1058 
1059  if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) {
1060  sel++;
1061  }
1062  else {
1063  bp -= nu->pntsu;
1064  if (BLI_BITMAP_TEST(selbpoints, a + nu->pntsu) ||
1065  ((bp->hide == 0) && (bp->f1 & SELECT))) {
1066  sel++;
1067  }
1068  bp += nu->pntsu;
1069  }
1070 
1071  if (a < nu->pntsu) {
1072  sel++;
1073  }
1074  else {
1075  bp += nu->pntsu;
1076  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1077  sel++;
1078  }
1079  bp -= nu->pntsu;
1080  }
1081 
1082  if (sel != 4) {
1084  BLI_BITMAP_ENABLE(selbpoints, a);
1085  }
1086  }
1087  else {
1088  lastsel = false;
1089  }
1090 
1091  bp++;
1092  }
1093 
1094  MEM_freeN(selbpoints);
1095  }
1096  }
1097  else {
1098  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1099  lastsel = false;
1100  /* check what type of curve/nurb it is */
1101  if (nu->type == CU_BEZIER) {
1102  a = nu->pntsu;
1103  bezt = nu->bezt;
1104  while (a--) {
1105  if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
1106  sel = (lastsel == 1);
1107 
1108  /* check if neighbors have been selected */
1109  /* first and last are exceptions */
1110  if (a == nu->pntsu - 1) {
1111  sel++;
1112  }
1113  else {
1114  bezt--;
1115  if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
1116  sel++;
1117  }
1118  bezt++;
1119  }
1120 
1121  if (a == 0) {
1122  sel++;
1123  }
1124  else {
1125  bezt++;
1126  if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
1127  sel++;
1128  }
1129  bezt--;
1130  }
1131 
1132  if (sel != 2) {
1134  lastsel = true;
1135  }
1136  else {
1137  lastsel = false;
1138  }
1139  }
1140  else {
1141  lastsel = false;
1142  }
1143 
1144  bezt++;
1145  }
1146  }
1147  else {
1148  a = nu->pntsu * nu->pntsv;
1149  bp = nu->bp;
1150  while (a--) {
1151  if ((lastsel == false) && (bp->hide == 0) && (bp->f1 & SELECT)) {
1152  sel = 0;
1153 
1154  /* first and last are exceptions */
1155  if (a == nu->pntsu * nu->pntsv - 1) {
1156  sel++;
1157  }
1158  else {
1159  bp--;
1160  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1161  sel++;
1162  }
1163  bp++;
1164  }
1165 
1166  if (a == 0) {
1167  sel++;
1168  }
1169  else {
1170  bp++;
1171  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1172  sel++;
1173  }
1174  bp--;
1175  }
1176 
1177  if (sel != 2) {
1179  lastsel = true;
1180  }
1181  else {
1182  lastsel = false;
1183  }
1184  }
1185  else {
1186  lastsel = false;
1187  }
1188 
1189  bp++;
1190  }
1191  }
1192  }
1193  }
1194 }
1195 
1197 {
1198  ViewLayer *view_layer = CTX_data_view_layer(C);
1199  uint objects_len = 0;
1201  view_layer, CTX_wm_view3d(C), &objects_len);
1202  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1203  Object *obedit = objects[ob_index];
1204  curve_select_less(obedit);
1207  }
1208  MEM_freeN(objects);
1209  return OPERATOR_FINISHED;
1210 }
1211 
1213 {
1214  /* identifiers */
1215  ot->name = "Select Less";
1216  ot->idname = "CURVE_OT_select_less";
1217  ot->description = "Deselect control points at the boundary of each selection region";
1218 
1219  /* api callbacks */
1222 
1223  /* flags */
1225 }
1226 
1229 /* -------------------------------------------------------------------- */
1234 {
1235  const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
1236  const float randfac = RNA_float_get(op->ptr, "ratio");
1238 
1239  ViewLayer *view_layer = CTX_data_view_layer(C);
1240  uint objects_len = 0;
1242  view_layer, CTX_wm_view3d(C), &objects_len);
1243 
1244  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1245  Object *obedit = objects[ob_index];
1246  ListBase *editnurb = object_editcurve_get(obedit);
1247  int seed_iter = seed;
1248 
1249  /* This gives a consistent result regardless of object order. */
1250  if (ob_index) {
1251  seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
1252  }
1253 
1254  int totvert = 0;
1255  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1256  if (nu->type == CU_BEZIER) {
1257  int a = nu->pntsu;
1258  BezTriple *bezt = nu->bezt;
1259  while (a--) {
1260  if (!bezt->hide) {
1261  totvert++;
1262  }
1263  bezt++;
1264  }
1265  }
1266  else {
1267  int a = nu->pntsu * nu->pntsv;
1268  BPoint *bp = nu->bp;
1269  while (a--) {
1270  if (!bp->hide) {
1271  totvert++;
1272  }
1273  bp++;
1274  }
1275  }
1276  }
1277 
1278  BLI_bitmap *verts_selection_mask = BLI_BITMAP_NEW(totvert, __func__);
1279  const int count_select = totvert * randfac;
1280  for (int i = 0; i < count_select; i++) {
1281  BLI_BITMAP_SET(verts_selection_mask, i, true);
1282  }
1283  BLI_bitmap_randomize(verts_selection_mask, totvert, seed_iter);
1284 
1285  int bit_index = 0;
1286  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1287  if (nu->type == CU_BEZIER) {
1288  int a = nu->pntsu;
1289  BezTriple *bezt = nu->bezt;
1290 
1291  while (a--) {
1292  if (!bezt->hide) {
1293  if (BLI_BITMAP_TEST(verts_selection_mask, bit_index)) {
1295  }
1296  bit_index++;
1297  }
1298  bezt++;
1299  }
1300  }
1301  else {
1302  int a = nu->pntsu * nu->pntsv;
1303  BPoint *bp = nu->bp;
1304 
1305  while (a--) {
1306  if (!bp->hide) {
1307  if (BLI_BITMAP_TEST(verts_selection_mask, bit_index)) {
1309  }
1310  bit_index++;
1311  }
1312  bp++;
1313  }
1314  }
1315  }
1316 
1317  MEM_freeN(verts_selection_mask);
1321  }
1322 
1323  MEM_freeN(objects);
1324  return OPERATOR_FINISHED;
1325 }
1326 
1328 {
1329  /* identifiers */
1330  ot->name = "Select Random";
1331  ot->idname = "CURVE_OT_select_random";
1332  ot->description = "Randomly select some control points";
1333 
1334  /* api callbacks */
1337 
1338  /* flags */
1340 
1341  /* properties */
1343 }
1344 
1347 /* -------------------------------------------------------------------- */
1351 static void select_nth_bezt(Nurb *nu, BezTriple *bezt, const struct CheckerIntervalParams *params)
1352 {
1353  int a, start;
1354 
1355  start = bezt - nu->bezt;
1356  a = nu->pntsu;
1357  bezt = &nu->bezt[a - 1];
1358 
1359  while (a--) {
1360  const int depth = abs(start - a);
1363  }
1364 
1365  bezt--;
1366  }
1367 }
1368 
1369 static void select_nth_bp(Nurb *nu, BPoint *bp, const struct CheckerIntervalParams *params)
1370 {
1371  int a, startrow, startpnt;
1372  int row, pnt;
1373 
1374  startrow = (bp - nu->bp) / nu->pntsu;
1375  startpnt = (bp - nu->bp) % nu->pntsu;
1376 
1377  a = nu->pntsu * nu->pntsv;
1378  bp = &nu->bp[a - 1];
1379  row = nu->pntsv - 1;
1380  pnt = nu->pntsu - 1;
1381 
1382  while (a--) {
1383  const int depth = abs(pnt - startpnt) + abs(row - startrow);
1386  }
1387 
1388  pnt--;
1389  if (pnt < 0) {
1390  pnt = nu->pntsu - 1;
1391  row--;
1392  }
1393 
1394  bp--;
1395  }
1396 }
1397 
1399 {
1400  Nurb *nu = NULL;
1401  void *vert = NULL;
1402 
1403  if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
1404  return false;
1405  }
1406 
1407  if (nu->bezt) {
1408  select_nth_bezt(nu, vert, params);
1409  }
1410  else {
1411  select_nth_bp(nu, vert, params);
1412  }
1413 
1414  return true;
1415 }
1416 
1418 {
1419  ViewLayer *view_layer = CTX_data_view_layer(C);
1420  Object *obact = CTX_data_edit_object(C);
1421  View3D *v3d = CTX_wm_view3d(C);
1422  bool changed = false;
1423 
1424  struct CheckerIntervalParams op_params;
1426 
1427  uint objects_len = 0;
1429  view_layer, CTX_wm_view3d(C), &objects_len);
1430  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1431  Object *obedit = objects[ob_index];
1432  Curve *cu = obedit->data;
1433 
1434  if (!ED_curve_select_check(v3d, cu->editnurb)) {
1435  continue;
1436  }
1437 
1438  if (ed_curve_select_nth(obedit->data, &op_params) == true) {
1439  changed = true;
1440 
1443  }
1444  }
1445  MEM_freeN(objects);
1446 
1447  if (!changed) {
1448  if (obact->type == OB_SURF) {
1449  BKE_report(op->reports, RPT_ERROR, "Surface(s) have no active point");
1450  }
1451  else {
1452  BKE_report(op->reports, RPT_ERROR, "Curve(s) have no active point");
1453  }
1454  return OPERATOR_CANCELLED;
1455  }
1456  return OPERATOR_FINISHED;
1457 }
1458 
1460 {
1461  /* identifiers */
1462  ot->name = "Checker Deselect";
1463  ot->description = "Deselect every Nth point starting from the active one";
1464  ot->idname = "CURVE_OT_select_nth";
1465 
1466  /* api callbacks */
1467  ot->exec = select_nth_exec;
1469 
1470  /* flags */
1472 
1474 }
1475 
1478 /* -------------------------------------------------------------------- */
1483  {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
1484  {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
1485  {SIM_CMP_LT, "LESS", 0, "Less", ""},
1486 
1487  {0, NULL, 0, NULL, NULL},
1488 };
1489 
1490 enum {
1495 };
1496 
1498  {SIMCURHAND_TYPE, "TYPE", 0, "Type", ""},
1499  {SIMCURHAND_RADIUS, "RADIUS", 0, "Radius", ""},
1500  {SIMCURHAND_WEIGHT, "WEIGHT", 0, "Weight", ""},
1501  {SIMCURHAND_DIRECTION, "DIRECTION", 0, "Direction", ""},
1502  {0, NULL, 0, NULL, NULL},
1503 };
1504 
1506  Nurb *nu,
1507  BezTriple *bezt,
1508  float r_dir[3])
1509 {
1510  float rsmat[3][3];
1511  BKE_nurb_bezt_calc_normal(nu, bezt, r_dir);
1512  copy_m3_m4(rsmat, ob->obmat);
1513  mul_m3_v3(rsmat, r_dir);
1514  normalize_v3(r_dir);
1515 }
1516 
1517 static void nurb_bpoint_direction_worldspace_get(Object *ob, Nurb *nu, BPoint *bp, float r_dir[3])
1518 {
1519  float rsmat[3][3];
1520  BKE_nurb_bpoint_calc_normal(nu, bp, r_dir);
1521  copy_m3_m4(rsmat, ob->obmat);
1522  mul_m3_v3(rsmat, r_dir);
1523  normalize_v3(r_dir);
1524 }
1525 
1527  Object *ob, Nurb *nu, const int type, KDTree_1d *tree_1d, KDTree_3d *tree_3d)
1528 {
1529  float tree_entry[3] = {0.0f, 0.0f, 0.0f};
1530 
1531  if (nu->type == CU_BEZIER) {
1532  BezTriple *bezt;
1533  int i;
1534  int tree_index = 0;
1535 
1536  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
1537  if ((!bezt->hide) && (bezt->f1 & SELECT)) {
1538 
1539  switch (type) {
1540  case SIMCURHAND_RADIUS: {
1541  float radius_ref = bezt->radius;
1542  tree_entry[0] = radius_ref;
1543  break;
1544  }
1545  case SIMCURHAND_WEIGHT: {
1546  float weight_ref = bezt->weight;
1547  tree_entry[0] = weight_ref;
1548  break;
1549  }
1550  case SIMCURHAND_DIRECTION: {
1551  nurb_bezt_direction_worldspace_get(ob, nu, bezt, tree_entry);
1552  break;
1553  }
1554  }
1555  if (tree_1d) {
1556  BLI_kdtree_1d_insert(tree_1d, tree_index++, tree_entry);
1557  }
1558  else {
1559  BLI_kdtree_3d_insert(tree_3d, tree_index++, tree_entry);
1560  }
1561  }
1562  }
1563  }
1564  else {
1565  BPoint *bp;
1566  int i;
1567  int tree_index = 0;
1568 
1569  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
1570  if (!bp->hide && bp->f1 & SELECT) {
1571  switch (type) {
1572  case SIMCURHAND_RADIUS: {
1573  float radius_ref = bp->radius;
1574  tree_entry[0] = radius_ref;
1575  break;
1576  }
1577  case SIMCURHAND_WEIGHT: {
1578  float weight_ref = bp->weight;
1579  tree_entry[0] = weight_ref;
1580  break;
1581  }
1582  case SIMCURHAND_DIRECTION: {
1583  nurb_bpoint_direction_worldspace_get(ob, nu, bp, tree_entry);
1584  break;
1585  }
1586  }
1587  if (tree_1d) {
1588  BLI_kdtree_1d_insert(tree_1d, tree_index++, tree_entry);
1589  }
1590  else {
1591  BLI_kdtree_3d_insert(tree_3d, tree_index++, tree_entry);
1592  }
1593  }
1594  }
1595  }
1596 }
1597 
1599  Nurb *nu,
1600  const int type,
1601  const KDTree_1d *tree_1d,
1602  const KDTree_3d *tree_3d,
1603  const float thresh,
1604  const int compare)
1605 {
1606  const float thresh_cos = cosf(thresh * (float)M_PI_2);
1607  bool changed = false;
1608 
1609  if (nu->type == CU_BEZIER) {
1610  BezTriple *bezt;
1611  int i;
1612 
1613  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
1614  if (!bezt->hide) {
1615  bool select = false;
1616 
1617  switch (type) {
1618  case SIMCURHAND_RADIUS: {
1619  float radius_ref = bezt->radius;
1620  if (ED_select_similar_compare_float_tree(tree_1d, radius_ref, thresh, compare)) {
1621  select = true;
1622  }
1623  break;
1624  }
1625  case SIMCURHAND_WEIGHT: {
1626  float weight_ref = bezt->weight;
1627  if (ED_select_similar_compare_float_tree(tree_1d, weight_ref, thresh, compare)) {
1628  select = true;
1629  }
1630  break;
1631  }
1632  case SIMCURHAND_DIRECTION: {
1633  float dir[3];
1634  nurb_bezt_direction_worldspace_get(ob, nu, bezt, dir);
1635  KDTreeNearest_3d nearest;
1636  if (BLI_kdtree_3d_find_nearest(tree_3d, dir, &nearest) != -1) {
1637  float orient = angle_normalized_v3v3(dir, nearest.co);
1638  float delta = thresh_cos - fabsf(cosf(orient));
1639  if (ED_select_similar_compare_float(delta, thresh, compare)) {
1640  select = true;
1641  }
1642  }
1643  break;
1644  }
1645  }
1646 
1647  if (select) {
1649  changed = true;
1650  }
1651  }
1652  }
1653  }
1654  else {
1655  BPoint *bp;
1656  int i;
1657 
1658  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
1659  if (!bp->hide) {
1660  bool select = false;
1661 
1662  switch (type) {
1663  case SIMCURHAND_RADIUS: {
1664  float radius_ref = bp->radius;
1665  if (ED_select_similar_compare_float_tree(tree_1d, radius_ref, thresh, compare)) {
1666  select = true;
1667  }
1668  break;
1669  }
1670  case SIMCURHAND_WEIGHT: {
1671  float weight_ref = bp->weight;
1672  if (ED_select_similar_compare_float_tree(tree_1d, weight_ref, thresh, compare)) {
1673  select = true;
1674  }
1675  break;
1676  }
1677  case SIMCURHAND_DIRECTION: {
1678  float dir[3];
1679  nurb_bpoint_direction_worldspace_get(ob, nu, bp, dir);
1680  KDTreeNearest_3d nearest;
1681  if (BLI_kdtree_3d_find_nearest(tree_3d, dir, &nearest) != -1) {
1682  float orient = angle_normalized_v3v3(dir, nearest.co);
1683  float delta = fabsf(cosf(orient)) - thresh_cos;
1684  if (ED_select_similar_compare_float(delta, thresh, compare)) {
1685  select = true;
1686  }
1687  }
1688  break;
1689  }
1690  }
1691 
1692  if (select) {
1694  changed = true;
1695  }
1696  }
1697  }
1698  }
1699  return changed;
1700 }
1701 
1703 {
1704  /* Get props. */
1705  const int optype = RNA_enum_get(op->ptr, "type");
1706  const float thresh = RNA_float_get(op->ptr, "threshold");
1707  const int compare = RNA_enum_get(op->ptr, "compare");
1708 
1709  ViewLayer *view_layer = CTX_data_view_layer(C);
1710  View3D *v3d = CTX_wm_view3d(C);
1711  int tot_nurbs_selected_all = 0;
1712  uint objects_len = 0;
1714  view_layer, CTX_wm_view3d(C), &objects_len);
1715 
1716  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1717  Object *obedit = objects[ob_index];
1718  Curve *cu = obedit->data;
1719  tot_nurbs_selected_all += ED_curve_select_count(v3d, cu->editnurb);
1720  }
1721 
1722  if (tot_nurbs_selected_all == 0) {
1723  BKE_report(op->reports, RPT_ERROR, "No control point selected");
1724  MEM_freeN(objects);
1725  return OPERATOR_CANCELLED;
1726  }
1727 
1728  KDTree_1d *tree_1d = NULL;
1729  KDTree_3d *tree_3d = NULL;
1730  short type_ref = 0;
1731 
1732  switch (optype) {
1733  case SIMCURHAND_RADIUS:
1734  case SIMCURHAND_WEIGHT:
1735  tree_1d = BLI_kdtree_1d_new(tot_nurbs_selected_all);
1736  break;
1737  case SIMCURHAND_DIRECTION:
1738  tree_3d = BLI_kdtree_3d_new(tot_nurbs_selected_all);
1739  break;
1740  }
1741 
1742  /* Get type of selected control points. */
1743  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1744  Object *obedit = objects[ob_index];
1745  Curve *cu = obedit->data;
1746  EditNurb *editnurb = cu->editnurb;
1747 
1748  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
1749  if (!ED_curve_nurb_select_check(v3d, nu)) {
1750  continue;
1751  }
1752  switch (optype) {
1753  case SIMCURHAND_TYPE: {
1754  type_ref |= nu->type;
1755  break;
1756  }
1757  case SIMCURHAND_RADIUS:
1758  case SIMCURHAND_WEIGHT:
1759  case SIMCURHAND_DIRECTION:
1760  curve_nurb_selected_type_get(obedit, nu, optype, tree_1d, tree_3d);
1761  break;
1762  }
1763  }
1764  }
1765 
1766  if (tree_1d != NULL) {
1767  BLI_kdtree_1d_deduplicate(tree_1d);
1768  BLI_kdtree_1d_balance(tree_1d);
1769  }
1770  if (tree_3d != NULL) {
1771  BLI_kdtree_3d_deduplicate(tree_3d);
1772  BLI_kdtree_3d_balance(tree_3d);
1773  }
1774 
1775  /* Select control points with desired type. */
1776  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1777  Object *obedit = objects[ob_index];
1778  Curve *cu = obedit->data;
1779  EditNurb *editnurb = cu->editnurb;
1780  bool changed = false;
1781 
1782  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
1783  switch (optype) {
1784  case SIMCURHAND_TYPE: {
1785  if (nu->type & type_ref) {
1786  changed |= ED_curve_nurb_select_all(nu);
1787  }
1788  break;
1789  }
1790  case SIMCURHAND_RADIUS:
1791  case SIMCURHAND_WEIGHT:
1792  case SIMCURHAND_DIRECTION:
1794  obedit, nu, optype, tree_1d, tree_3d, thresh, compare);
1795  break;
1796  }
1797  }
1798 
1799  if (changed) {
1802  }
1803  }
1804 
1805  MEM_freeN(objects);
1806 
1807  if (tree_1d != NULL) {
1808  BLI_kdtree_1d_free(tree_1d);
1809  }
1810  if (tree_3d != NULL) {
1811  BLI_kdtree_3d_free(tree_3d);
1812  }
1813  return OPERATOR_FINISHED;
1814 }
1815 
1817 {
1818  /* identifiers */
1819  ot->name = "Select Similar";
1820  ot->idname = "CURVE_OT_select_similar";
1821  ot->description = "Select similar curve points by property type";
1822 
1823  /* api callbacks */
1827 
1828  /* flags */
1830 
1831  /* properties */
1832  ot->prop = RNA_def_enum(
1833  ot->srna, "type", curve_prop_similar_types, SIMCURHAND_WEIGHT, "Type", "");
1834  RNA_def_enum(ot->srna, "compare", curve_prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
1835  RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.0, 100.0);
1836 }
1837 
1840 /* -------------------------------------------------------------------- */
1844 static float curve_calc_dist_pair(const Nurb *nu, int a, int b)
1845 {
1846  const float *a_fl, *b_fl;
1847 
1848  if (nu->type == CU_BEZIER) {
1849  a_fl = nu->bezt[a].vec[1];
1850  b_fl = nu->bezt[b].vec[1];
1851  }
1852  else {
1853  a_fl = nu->bp[a].vec;
1854  b_fl = nu->bp[b].vec;
1855  }
1856 
1857  return len_v3v3(a_fl, b_fl);
1858 }
1859 
1860 static float curve_calc_dist_span(Nurb *nu, int vert_src, int vert_dst)
1861 {
1862  const int u = nu->pntsu;
1863  int i_prev, i;
1864  float dist = 0.0f;
1865 
1866  BLI_assert(nu->pntsv <= 1);
1867 
1868  i_prev = vert_src;
1869  i = (i_prev + 1) % u;
1870 
1871  while (true) {
1872  dist += curve_calc_dist_pair(nu, i_prev, i);
1873 
1874  if (i == vert_dst) {
1875  break;
1876  }
1877  i = (i + 1) % u;
1878  }
1879  return dist;
1880 }
1881 
1882 static void curve_select_shortest_path_curve(Nurb *nu, int vert_src, int vert_dst)
1883 {
1884  const int u = nu->pntsu;
1885  int i;
1886 
1887  if (vert_src > vert_dst) {
1888  SWAP(int, vert_src, vert_dst);
1889  }
1890 
1891  if (nu->flagu & CU_NURB_CYCLIC) {
1892  if (curve_calc_dist_span(nu, vert_src, vert_dst) >
1893  curve_calc_dist_span(nu, vert_dst, vert_src)) {
1894  SWAP(int, vert_src, vert_dst);
1895  }
1896  }
1897 
1898  i = vert_src;
1899  while (true) {
1900  if (nu->type & CU_BEZIER) {
1902  }
1903  else {
1904  select_bpoint(&nu->bp[i], SELECT, SELECT, HIDDEN);
1905  }
1906 
1907  if (i == vert_dst) {
1908  break;
1909  }
1910  i = (i + 1) % u;
1911  }
1912 }
1913 
1914 static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst)
1915 {
1916  int totu = nu->pntsu;
1917  int totv = nu->pntsv;
1918  int vert_num = totu * totv;
1919 
1920  /* custom data */
1921  struct PointAdj {
1922  int vert, vert_prev;
1923  float cost;
1924  } * data;
1925 
1926  /* init connectivity data */
1927  data = MEM_mallocN(sizeof(*data) * vert_num, __func__);
1928  for (int i = 0; i < vert_num; i++) {
1929  data[i].vert = i;
1930  data[i].vert_prev = -1;
1931  data[i].cost = FLT_MAX;
1932  }
1933 
1934  /* init heap */
1935  HeapSimple *heap = BLI_heapsimple_new();
1936 
1937  int vert_curr = data[vert_src].vert;
1938  BLI_heapsimple_insert(heap, 0.0f, &data[vert_src].vert);
1939  data[vert_src].cost = 0.0f;
1940  data[vert_src].vert_prev = vert_src; /* nop */
1941 
1942  while (!BLI_heapsimple_is_empty(heap)) {
1943  vert_curr = *((int *)BLI_heapsimple_pop_min(heap));
1944  if (vert_curr == vert_dst) {
1945  break;
1946  }
1947 
1948  int u, v;
1949  BKE_nurb_index_to_uv(nu, vert_curr, &u, &v);
1950 
1951  /* loop over 4 adjacent verts */
1952  for (int sign = -1; sign != 3; sign += 2) {
1953  for (int axis = 0; axis != 2; axis += 1) {
1954  int uv_other[2] = {u, v};
1955  int vert_other;
1956 
1957  uv_other[axis] += sign;
1958 
1959  vert_other = BKE_nurb_index_from_uv(nu, uv_other[0], uv_other[1]);
1960  if (vert_other != -1) {
1961  const float dist = data[vert_curr].cost +
1962  curve_calc_dist_pair(nu, vert_curr, vert_other);
1963 
1964  if (data[vert_other].cost > dist) {
1965  data[vert_other].cost = dist;
1966  if (data[vert_other].vert_prev == -1) {
1967  BLI_heapsimple_insert(heap, data[vert_other].cost, &data[vert_other].vert);
1968  }
1969  data[vert_other].vert_prev = vert_curr;
1970  }
1971  }
1972  }
1973  }
1974  }
1975 
1976  BLI_heapsimple_free(heap, NULL);
1977 
1978  if (vert_curr == vert_dst) {
1979  int i = 0;
1980  while (vert_curr != vert_src && i++ < vert_num) {
1981  if (nu->type == CU_BEZIER) {
1982  select_beztriple(&nu->bezt[vert_curr], SELECT, SELECT, HIDDEN);
1983  }
1984  else {
1985  select_bpoint(&nu->bp[vert_curr], SELECT, SELECT, HIDDEN);
1986  }
1987  vert_curr = data[vert_curr].vert_prev;
1988  }
1989  }
1990 
1991  MEM_freeN(data);
1992 }
1993 
1995 {
1997  ViewContext vc;
1998  Nurb *nu_dst;
1999  BezTriple *bezt_dst;
2000  BPoint *bp_dst;
2001  int vert_dst;
2002  void *vert_dst_p;
2003  Base *basact = NULL;
2004 
2007  copy_v2_v2_int(vc.mval, event->mval);
2008 
2009  if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) {
2010  return OPERATOR_PASS_THROUGH;
2011  }
2012 
2014  Object *obedit = basact->object;
2015  Curve *cu = obedit->data;
2016  Nurb *nu_src = BKE_curve_nurb_active_get(cu);
2017  int vert_src = cu->actvert;
2018 
2019  if (vert_src == CU_ACT_NONE) {
2020  return OPERATOR_PASS_THROUGH;
2021  }
2022 
2023  if (nu_src != nu_dst) {
2024  BKE_report(op->reports, RPT_ERROR, "Control point belongs to another spline");
2025  return OPERATOR_CANCELLED;
2026  }
2027 
2028  vert_dst_p = bezt_dst ? (void *)bezt_dst : (void *)bp_dst;
2029  vert_dst = BKE_curve_nurb_vert_index_get(nu_dst, vert_dst_p);
2030  if (vert_src == vert_dst) {
2031  return OPERATOR_CANCELLED;
2032  }
2033 
2034  if ((obedit->type == OB_SURF) && (nu_src->pntsv > 1)) {
2035  curve_select_shortest_path_surf(nu_src, vert_src, vert_dst);
2036  }
2037  else {
2038  curve_select_shortest_path_curve(nu_src, vert_src, vert_dst);
2039  }
2040 
2041  BKE_curve_nurb_vert_active_set(cu, nu_dst, vert_dst_p);
2042 
2043  if (vc.view_layer->basact != basact) {
2044  ED_object_base_activate(C, basact);
2045  }
2046 
2049  return OPERATOR_FINISHED;
2050 }
2051 
2053 {
2054  /* identifiers */
2055  ot->name = "Pick Shortest Path";
2056  ot->idname = "CURVE_OT_shortest_path_pick";
2057  ot->description = "Select shortest path between two selections";
2058 
2059  /* api callbacks */
2062 
2063  /* flags */
2065 }
2066 
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert)
Definition: curve.cc:5049
void BKE_nurb_index_to_uv(struct Nurb *nu, int index, int *r_u, int *r_v)
Definition: curve.cc:964
void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, const void *vert)
int BKE_nurb_index_from_uv(struct Nurb *nu, int u, int v)
Definition: curve.cc:942
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert)
void BKE_curve_nurb_vert_active_validate(struct Curve *cu)
Definition: curve.cc:5076
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3])
Definition: curve.cc:1111
void BKE_nurb_bezt_calc_normal(struct Nurb *nu, struct BezTriple *bezt, float r_normal[3])
struct Nurb * BKE_curve_nurb_active_get(struct Curve *cu)
Definition: curve.cc:5006
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
Definition: curve.cc:4354
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:546
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
#define BLI_BITMAP_SET(_bitmap, _index, _set)
Definition: BLI_bitmap.h:102
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
A min-heap / priority queue ADT.
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void * BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1)
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
A KD-tree for nearest neighbor search.
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define M_PI_2
Definition: BLI_math_base.h:23
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:445
Random number functions.
void BLI_bitmap_randomize(unsigned int *bitmap, unsigned int bits_num, unsigned int seed) ATTR_NONNULL(1)
Definition: rand.cc:199
unsigned int uint
Definition: BLI_sys_types.h:67
#define SWAP(type, a, b)
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ CU_BEZIER
#define BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)
#define BEZT_SEL_ALL(bezt)
#define BEZT_ISSEL_ANY(bezt)
#define CU_ACT_NONE
#define BEZT_DESEL_ALL(bezt)
@ CU_NURB_CYCLIC
#define BEZT_ISSEL_ALL(bezt)
Object is a sort of wrapper for general info.
@ OB_SURF
@ CURVE_HANDLE_NONE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
void ED_object_base_activate(struct bContext *C, struct Base *base)
bool ED_operator_editsurfcurve(struct bContext *C)
Definition: screen_ops.c:587
bool ED_operator_editcurve(struct bContext *C)
Definition: screen_ops.c:606
bool ED_operator_editsurfcurve_region_view3d(struct bContext *C)
Definition: screen_ops.c:596
bool ED_operator_editsurf(struct bContext *C)
Definition: screen_ops.c:626
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
bool ED_select_similar_compare_float(float delta, float thresh, eSimilarCmp compare)
Definition: select_utils.c:69
@ SIM_CMP_LT
@ SIM_CMP_GT
@ SIM_CMP_EQ
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree, float length, float thresh, eSimilarCmp compare)
#define DESELECT
Definition: ED_types.h:17
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact)
void view3d_operator_needs_opengl(const struct bContext *C)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_SELECT
Definition: WM_types.h:455
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
ATTR_WARN_UNUSED_RESULT const BMVert * v
static unsigned long seed
Definition: btSoftBody.h:39
#define cosf(x)
Definition: cuda/compat.h:101
#define SELECT
bool ED_curve_pick_vert(struct ViewContext *vc, short sel, struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle, struct Base **r_base)
eEndPoint_Types
Definition: curve_intern.h:48
@ FIRST
Definition: curve_intern.h:49
@ LAST
Definition: curve_intern.h:50
eVisible_Types
Definition: curve_intern.h:43
@ HIDDEN
Definition: curve_intern.h:44
@ VISIBLE
Definition: curve_intern.h:45
const Depsgraph * depsgraph
ListBase * object_editcurve_get(Object *ob)
Definition: editcurve.c:74
void CURVE_OT_select_random(wmOperatorType *ot)
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
static bool ed_curve_select_nth(Curve *cu, const struct CheckerIntervalParams *params)
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
bool ED_curve_select_check(const View3D *v3d, const EditNurb *editnurb)
bool ED_curve_nurb_select_check(const View3D *v3d, const Nurb *nu)
void CURVE_OT_select_less(wmOperatorType *ot)
void CURVE_OT_select_similar(wmOperatorType *ot)
static void curve_select_more(Object *obedit)
static void curve_nurb_selected_type_get(Object *ob, Nurb *nu, const int type, KDTree_1d *tree_1d, KDTree_3d *tree_3d)
bool ED_curve_select_all(EditNurb *editnurb)
void CURVE_OT_select_previous(wmOperatorType *ot)
static const EnumPropertyItem curve_prop_similar_types[]
static void nurb_bezt_direction_worldspace_get(Object *ob, Nurb *nu, BezTriple *bezt, float r_dir[3])
static const EnumPropertyItem curve_prop_similar_compare_types[]
static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void CURVE_OT_shortest_path_pick(wmOperatorType *ot)
void CURVE_OT_select_linked(wmOperatorType *ot)
bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len)
bool ED_curve_nurb_deselect_all(const Nurb *nu)
static void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus)
static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
@ SIMCURHAND_WEIGHT
@ SIMCURHAND_DIRECTION
@ SIMCURHAND_RADIUS
@ SIMCURHAND_TYPE
static void select_adjacent_cp(ListBase *editnurb, short next, const bool cont, const bool selstatus)
bool ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
static void curve_select_less(Object *obedit)
static int curve_select_random_exec(bContext *C, wmOperator *op)
void CURVE_OT_select_next(wmOperatorType *ot)
int ED_curve_select_count(const View3D *v3d, const EditNurb *editnurb)
bool ED_curve_deselect_all_multi(struct bContext *C)
static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
static void select_nth_bp(Nurb *nu, BPoint *bp, const struct CheckerIntervalParams *params)
static bool curve_nurb_select_similar_type(Object *ob, Nurb *nu, const int type, const KDTree_1d *tree_1d, const KDTree_3d *tree_3d, const float thresh, const int compare)
static bool swap_selection_bpoint(BPoint *bp)
static int curve_select_more_exec(bContext *C, wmOperator *UNUSED(op))
bool ED_curve_nurb_select_all(const Nurb *nu)
static int select_nth_exec(bContext *C, wmOperator *op)
static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
void CURVE_OT_select_all(wmOperatorType *ot)
static int curve_select_less_exec(bContext *C, wmOperator *UNUSED(op))
static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static void select_nth_bezt(Nurb *nu, BezTriple *bezt, const struct CheckerIntervalParams *params)
static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
bool ED_curve_deselect_all(EditNurb *editnurb)
static bool swap_selection_beztriple(BezTriple *bezt)
void CURVE_OT_select_nth(wmOperatorType *ot)
void CURVE_OT_de_select_first(wmOperatorType *ot)
static int curve_select_similar_exec(bContext *C, wmOperator *op)
void CURVE_OT_select_more(wmOperatorType *ot)
static void nurb_bpoint_direction_worldspace_get(Object *ob, Nurb *nu, BPoint *bp, float r_dir[3])
void CURVE_OT_select_row(wmOperatorType *ot)
int ED_curve_nurb_select_count(const View3D *v3d, const Nurb *nu)
void CURVE_OT_de_select_last(wmOperatorType *ot)
static float curve_calc_dist_span(Nurb *nu, int vert_src, int vert_dst)
static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
void CURVE_OT_select_linked_pick(wmOperatorType *ot)
static void curve_select_shortest_path_curve(Nurb *nu, int vert_src, int vert_dst)
static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst)
static float curve_calc_dist_pair(const Nurb *nu, int a, int b)
static int de_select_all_exec(bContext *C, wmOperator *op)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned a[3]
Definition: RandGen.cpp:78
double sign(double arg)
Definition: utility.h:250
T abs(const T &a)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
unsigned char uint8_t
Definition: stdint.h:78
short hide
float weight
uint8_t f1
float vec[4]
float radius
struct Object * object
uint8_t f3
float vec[3][3]
uint8_t f1
uint8_t f2
EditNurb * editnurb
ListBase nurbs
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
short flagu
struct Nurb * next
short type
BezTriple * bezt
BPoint * bp
float obmat[4][4]
void * data
View3DOverlay overlay
int mval[2]
Definition: ED_view3d.h:74
struct ViewLayer * view_layer
Definition: ED_view3d.h:66
struct View3D * v3d
Definition: ED_view3d.h:70
struct Base * basact
int mval[2]
Definition: WM_types.h:684
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op)
bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalParams *op_params, int depth)
void WM_operator_properties_select_random(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op, struct CheckerIntervalParams *op_params)
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))