Blender  V2.93
editcurve_select.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include "DNA_object_types.h"
25 #include "DNA_scene_types.h"
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "BLI_bitmap.h"
30 #include "BLI_heap_simple.h"
31 #include "BLI_kdtree.h"
32 #include "BLI_listbase.h"
33 #include "BLI_math.h"
34 #include "BLI_rand.h"
35 
36 #include "BKE_context.h"
37 #include "BKE_curve.h"
38 #include "BKE_fcurve.h"
39 #include "BKE_layer.h"
40 #include "BKE_report.h"
41 
42 #include "WM_api.h"
43 #include "WM_types.h"
44 
45 #include "ED_curve.h"
46 #include "ED_object.h"
47 #include "ED_screen.h"
48 #include "ED_select_utils.h"
49 #include "ED_types.h"
50 #include "ED_view3d.h"
51 
52 #include "curve_intern.h"
53 
54 #include "RNA_access.h"
55 #include "RNA_define.h"
56 
57 #include "DEG_depsgraph.h"
58 
59 /* returns 1 in case (de)selection was successful */
60 bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
61 {
62  if ((bezt->hide == 0) || (hidden == HIDDEN)) {
63  if (selstatus == SELECT) { /* selects */
64  bezt->f1 |= flag;
65  bezt->f2 |= flag;
66  bezt->f3 |= flag;
67  return true;
68  }
69  /* deselects */
70  bezt->f1 &= ~flag;
71  bezt->f2 &= ~flag;
72  bezt->f3 &= ~flag;
73  return true;
74  }
75 
76  return false;
77 }
78 
79 /* returns 1 in case (de)selection was successful */
80 bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
81 {
82  if ((bp->hide == 0) || (hidden == 1)) {
83  if (selstatus == SELECT) {
84  bp->f1 |= flag;
85  return true;
86  }
87  bp->f1 &= ~flag;
88  return true;
89  }
90 
91  return false;
92 }
93 
95 {
96  if (bezt->f2 & SELECT) {
97  return select_beztriple(bezt, DESELECT, SELECT, VISIBLE);
98  }
99  return select_beztriple(bezt, SELECT, SELECT, VISIBLE);
100 }
101 
103 {
104  if (bp->f1 & SELECT) {
105  return select_bpoint(bp, DESELECT, SELECT, VISIBLE);
106  }
107  return select_bpoint(bp, SELECT, SELECT, VISIBLE);
108 }
109 
111 {
112  if (nu->type == CU_BEZIER) {
113  BezTriple *bezt;
114  int i;
115 
116  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
117  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
118  return true;
119  }
120  }
121  }
122  else {
123  BPoint *bp;
124  int i;
125 
126  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
127  if (bp->f1 & SELECT) {
128  return true;
129  }
130  }
131  }
132  return false;
133 }
134 
136 {
137  int sel = 0;
138 
139  if (nu->type == CU_BEZIER) {
140  BezTriple *bezt;
141  int i;
142 
143  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
144  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
145  sel++;
146  }
147  }
148  }
149  else {
150  BPoint *bp;
151  int i;
152 
153  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
154  if (bp->f1 & SELECT) {
155  sel++;
156  }
157  }
158  }
159 
160  return sel;
161 }
162 
164 {
165  bool changed = false;
166  int i;
167  if (nu->bezt) {
168  BezTriple *bezt;
169  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
170  if (bezt->hide == 0) {
171  if (BEZT_ISSEL_ALL(bezt) == false) {
172  BEZT_SEL_ALL(bezt);
173  changed = true;
174  }
175  }
176  }
177  }
178  else if (nu->bp) {
179  BPoint *bp;
180  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
181  if (bp->hide == 0) {
182  if ((bp->f1 & SELECT) == 0) {
183  bp->f1 |= SELECT;
184  changed = true;
185  }
186  }
187  }
188  }
189  return changed;
190 }
191 
193 {
194  bool changed = false;
195  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
196  changed |= ED_curve_nurb_select_all(nu);
197  }
198  return changed;
199 }
200 
202 {
203  bool changed = false;
204  int i;
205  if (nu->bezt) {
206  BezTriple *bezt;
207  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
208  if (BEZT_ISSEL_ANY(bezt)) {
209  BEZT_DESEL_ALL(bezt);
210  changed = true;
211  }
212  }
213  }
214  else if (nu->bp) {
215  BPoint *bp;
216  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
217  if (bp->f1 & SELECT) {
218  bp->f1 &= ~SELECT;
219  changed = true;
220  }
221  }
222  }
223  return changed;
224 }
225 
226 int ED_curve_select_count(View3D *v3d, struct EditNurb *editnurb)
227 {
228  int sel = 0;
229  Nurb *nu;
230 
231  for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
232  sel += ED_curve_nurb_select_count(v3d, nu);
233  }
234 
235  return sel;
236 }
237 
238 bool ED_curve_select_check(View3D *v3d, struct EditNurb *editnurb)
239 {
240  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
241  if (ED_curve_nurb_select_check(v3d, nu)) {
242  return true;
243  }
244  }
245 
246  return false;
247 }
248 
250 {
251  bool changed = false;
252  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
253  changed |= ED_curve_nurb_deselect_all(nu);
254  }
255  return changed;
256 }
257 
258 bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len)
259 {
260  bool changed_multi = false;
261  for (uint base_index = 0; base_index < bases_len; base_index++) {
262  Object *obedit = bases[base_index]->object;
263  Curve *cu = obedit->data;
264  changed_multi |= ED_curve_deselect_all(cu->editnurb);
266  }
267  return changed_multi;
268 }
269 
271 {
273  ViewContext vc;
275  uint bases_len = 0;
277  vc.view_layer, vc.v3d, &bases_len);
278  bool changed_multi = ED_curve_deselect_all_multi_ex(bases, bases_len);
279  MEM_freeN(bases);
280  return changed_multi;
281 }
282 
283 bool ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
284 {
285  BPoint *bp;
286  BezTriple *bezt;
287  int a;
288  bool changed = false;
289 
290  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
291  if (nu->type == CU_BEZIER) {
292  bezt = nu->bezt;
293  a = nu->pntsu;
294  while (a--) {
295  if (bezt->hide == 0) {
296  bezt->f2 ^= SELECT; /* always do the center point */
297  if (!hide_handles) {
298  bezt->f1 ^= SELECT;
299  bezt->f3 ^= SELECT;
300  }
301  changed = true;
302  }
303  bezt++;
304  }
305  }
306  else {
307  bp = nu->bp;
308  a = nu->pntsu * nu->pntsv;
309  while (a--) {
310  if (bp->hide == 0) {
312  changed = true;
313  }
314  bp++;
315  }
316  }
317  }
318  return changed;
319 }
320 
326 static void select_adjacent_cp(ListBase *editnurb,
327  short next,
328  const bool cont,
329  const bool selstatus)
330 {
331  BezTriple *bezt;
332  BPoint *bp;
333  int a;
334  bool lastsel = false;
335 
336  if (next == 0) {
337  return;
338  }
339 
340  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
341  lastsel = false;
342  if (nu->type == CU_BEZIER) {
343  a = nu->pntsu;
344  bezt = nu->bezt;
345  if (next < 0) {
346  bezt = &nu->bezt[a - 1];
347  }
348  while (a--) {
349  if (a - abs(next) < 0) {
350  break;
351  }
352  if ((lastsel == false) && (bezt->hide == 0) &&
353  ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
354  bezt += next;
355  if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
356  bool sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
357  if (sel && !cont) {
358  lastsel = true;
359  }
360  }
361  }
362  else {
363  bezt += next;
364  lastsel = false;
365  }
366  /* move around in zigzag way so that we go through each */
367  bezt -= (next - next / abs(next));
368  }
369  }
370  else {
371  a = nu->pntsu * nu->pntsv;
372  bp = nu->bp;
373  if (next < 0) {
374  bp = &nu->bp[a - 1];
375  }
376  while (a--) {
377  if (a - abs(next) < 0) {
378  break;
379  }
380  if ((lastsel == false) && (bp->hide == 0) &&
381  ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
382  bp += next;
383  if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
384  bool sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
385  if (sel && !cont) {
386  lastsel = true;
387  }
388  }
389  }
390  else {
391  bp += next;
392  lastsel = false;
393  }
394  /* move around in zigzag way so that we go through each */
395  bp -= (next - next / abs(next));
396  }
397  }
398  }
399 }
400 
401 /**************** select start/end operators **************/
402 
403 /* (de)selects first or last of visible part of each Nurb depending on selFirst
404  * selFirst: defines the end of which to select
405  * doswap: defines if selection state of each first/last control point is swapped
406  * selstatus: selection status in case doswap is false
407  */
408 static void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus)
409 {
410  ListBase *editnurb = object_editcurve_get(obedit);
411  BPoint *bp;
412  BezTriple *bezt;
413  Curve *cu;
414  int a;
415 
416  if (obedit == NULL) {
417  return;
418  }
419 
420  cu = (Curve *)obedit->data;
421  cu->actvert = CU_ACT_NONE;
422 
423  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
424  if (nu->type == CU_BEZIER) {
425  a = nu->pntsu;
426 
427  /* which point? */
428  if (selfirst == LAST) { /* select last */
429  bezt = &nu->bezt[a - 1];
430  }
431  else { /* select first */
432  bezt = nu->bezt;
433  }
434 
435  while (a--) {
436  bool sel;
437  if (doswap) {
438  sel = swap_selection_beztriple(bezt);
439  }
440  else {
441  sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
442  }
443 
444  if (sel == true) {
445  break;
446  }
447  }
448  }
449  else {
450  a = nu->pntsu * nu->pntsv;
451 
452  /* which point? */
453  if (selfirst == LAST) { /* select last */
454  bp = &nu->bp[a - 1];
455  }
456  else { /* select first */
457  bp = nu->bp;
458  }
459 
460  while (a--) {
461  if (bp->hide == 0) {
462  bool sel;
463  if (doswap) {
464  sel = swap_selection_bpoint(bp);
465  }
466  else {
467  sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
468  }
469 
470  if (sel == true) {
471  break;
472  }
473  }
474  }
475  }
476  }
477 }
478 
480 {
481  ViewLayer *view_layer = CTX_data_view_layer(C);
482  uint objects_len = 0;
484  view_layer, CTX_wm_view3d(C), &objects_len);
485 
486  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
487  Object *obedit = objects[ob_index];
488  selectend_nurb(obedit, FIRST, true, DESELECT);
492  }
493  MEM_freeN(objects);
494  return OPERATOR_FINISHED;
495 }
496 
498 {
499  /* identifiers */
500  ot->name = "(De)select First";
501  ot->idname = "CURVE_OT_de_select_first";
502  ot->description = "(De)select first of visible part of each NURBS";
503 
504  /* api callbacks */
507 
508  /* flags */
510 }
511 
513 {
514  ViewLayer *view_layer = CTX_data_view_layer(C);
515  uint objects_len = 0;
517  view_layer, CTX_wm_view3d(C), &objects_len);
518 
519  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
520  Object *obedit = objects[ob_index];
521  selectend_nurb(obedit, LAST, true, DESELECT);
525  }
526 
527  MEM_freeN(objects);
528  return OPERATOR_FINISHED;
529 }
530 
532 {
533  /* identifiers */
534  ot->name = "(De)select Last";
535  ot->idname = "CURVE_OT_de_select_last";
536  ot->description = "(De)select last of visible part of each NURBS";
537 
538  /* api callbacks */
541 
542  /* flags */
544 }
545 
547 {
548  int action = RNA_enum_get(op->ptr, "action");
549 
550  ViewLayer *view_layer = CTX_data_view_layer(C);
551  View3D *v3d = CTX_wm_view3d(C);
552  uint objects_len = 0;
554  view_layer, CTX_wm_view3d(C), &objects_len);
555  if (action == SEL_TOGGLE) {
556  action = SEL_SELECT;
557  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
558  Object *obedit = objects[ob_index];
559  Curve *cu = obedit->data;
560 
561  if (ED_curve_select_check(v3d, cu->editnurb)) {
562  action = SEL_DESELECT;
563  break;
564  }
565  }
566  }
567 
568  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
569  Object *obedit = objects[ob_index];
570  Curve *cu = obedit->data;
571  bool changed = false;
572 
573  switch (action) {
574  case SEL_SELECT:
575  changed = ED_curve_select_all(cu->editnurb);
576  break;
577  case SEL_DESELECT:
578  changed = ED_curve_deselect_all(cu->editnurb);
579  break;
580  case SEL_INVERT:
581  changed = ED_curve_select_swap(
582  cu->editnurb, (v3d && (v3d->overlay.handle_display == CURVE_HANDLE_NONE)));
583  break;
584  }
585 
586  if (changed) {
590  }
591  }
592 
593  MEM_freeN(objects);
594  return OPERATOR_FINISHED;
595 }
596 
598 {
599  /* identifiers */
600  ot->name = "(De)select All";
601  ot->idname = "CURVE_OT_select_all";
602  ot->description = "(De)select all control points";
603 
604  /* api callbacks */
607 
608  /* flags */
610 
611  /* properties */
613 }
614 
615 /***************** select linked operator ******************/
616 
618 {
619  ViewLayer *view_layer = CTX_data_view_layer(C);
620  View3D *v3d = CTX_wm_view3d(C);
621 
622  uint objects_len = 0;
624  view_layer, CTX_wm_view3d(C), &objects_len);
625  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
626  Object *obedit = objects[ob_index];
627  Curve *cu = obedit->data;
628  EditNurb *editnurb = cu->editnurb;
629  ListBase *nurbs = &editnurb->nurbs;
630  bool changed = false;
631 
632  LISTBASE_FOREACH (Nurb *, nu, nurbs) {
633  if (ED_curve_nurb_select_check(v3d, nu)) {
634  changed |= ED_curve_nurb_select_all(nu);
635  }
636  }
637 
638  if (changed) {
641  }
642  }
643  MEM_freeN(objects);
644 
645  return OPERATOR_FINISHED;
646 }
647 
648 static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
649 {
650  return select_linked_exec(C, op);
651 }
652 
654 {
655  /* identifiers */
656  ot->name = "Select Linked All";
657  ot->idname = "CURVE_OT_select_linked";
658  ot->description = "Select all control points linked to the current selection";
659 
660  /* api callbacks */
664 
665  /* flags */
667 
668  /* properties */
669 }
670 
671 /***************** select linked pick operator ******************/
672 
673 static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
674 {
676  ViewContext vc;
677  Nurb *nu;
678  BezTriple *bezt;
679  BPoint *bp;
680  int a;
681  const bool select = !RNA_boolean_get(op->ptr, "deselect");
682  Base *basact = NULL;
683 
686  copy_v2_v2_int(vc.mval, event->mval);
687 
688  if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) {
689  return OPERATOR_CANCELLED;
690  }
691 
692  if (bezt) {
693  a = nu->pntsu;
694  bezt = nu->bezt;
695  while (a--) {
697  bezt++;
698  }
699  }
700  else if (bp) {
701  a = nu->pntsu * nu->pntsv;
702  bp = nu->bp;
703  while (a--) {
705  bp++;
706  }
707  }
708 
709  Object *obedit = basact->object;
710 
713 
714  if (!select) {
716  }
717 
718  return OPERATOR_FINISHED;
719 }
720 
722 {
723  /* identifiers */
724  ot->name = "Select Linked";
725  ot->idname = "CURVE_OT_select_linked_pick";
726  ot->description = "Select all control points linked to already selected ones";
727 
728  /* api callbacks */
731 
732  /* flags */
734 
735  /* properties */
737  "deselect",
738  0,
739  "Deselect",
740  "Deselect linked control points rather than selecting them");
741 }
742 
743 /***************** select row operator **********************/
744 
746 {
747  Object *obedit = CTX_data_edit_object(C);
748  Curve *cu = obedit->data;
749  ListBase *editnurb = object_editcurve_get(obedit);
750  static BPoint *last = NULL;
751  static int direction = 0;
752  Nurb *nu = NULL;
753  BPoint *bp = NULL;
754  int u = 0, v = 0, a, b;
755 
756  if (!BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bp)) {
757  return OPERATOR_CANCELLED;
758  }
759 
760  if (last == bp) {
761  direction = 1 - direction;
762  BKE_nurbList_flag_set(editnurb, SELECT, false);
763  }
764  last = bp;
765 
766  u = cu->actvert % nu->pntsu;
767  v = cu->actvert / nu->pntsu;
768  bp = nu->bp;
769  for (a = 0; a < nu->pntsv; a++) {
770  for (b = 0; b < nu->pntsu; b++, bp++) {
771  if (direction) {
772  if (a == v) {
774  }
775  }
776  else {
777  if (b == u) {
779  }
780  }
781  }
782  }
783 
786 
787  return OPERATOR_FINISHED;
788 }
789 
791 {
792  /* identifiers */
793  ot->name = "Select Control Point Row";
794  ot->idname = "CURVE_OT_select_row";
795  ot->description = "Select a row of control points including active one";
796 
797  /* api callbacks */
800 
801  /* flags */
803 }
804 
805 /***************** select next operator **********************/
806 
808 {
809  ViewLayer *view_layer = CTX_data_view_layer(C);
810  uint objects_len = 0;
812  view_layer, CTX_wm_view3d(C), &objects_len);
813 
814  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
815  Object *obedit = objects[ob_index];
816 
817  ListBase *editnurb = object_editcurve_get(obedit);
818  select_adjacent_cp(editnurb, 1, 0, SELECT);
819 
822  }
823  MEM_freeN(objects);
824  return OPERATOR_FINISHED;
825 }
826 
828 {
829  /* identifiers */
830  ot->name = "Select Next";
831  ot->idname = "CURVE_OT_select_next";
832  ot->description = "Select control points following already selected ones along the curves";
833 
834  /* api callbacks */
837 
838  /* flags */
840 }
841 
842 /***************** select previous operator **********************/
843 
845 {
846  ViewLayer *view_layer = CTX_data_view_layer(C);
847  uint objects_len = 0;
849  view_layer, CTX_wm_view3d(C), &objects_len);
850 
851  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
852  Object *obedit = objects[ob_index];
853 
854  ListBase *editnurb = object_editcurve_get(obedit);
855  select_adjacent_cp(editnurb, -1, 0, SELECT);
856 
859  }
860  MEM_freeN(objects);
861  return OPERATOR_FINISHED;
862 }
863 
865 {
866  /* identifiers */
867  ot->name = "Select Previous";
868  ot->idname = "CURVE_OT_select_previous";
869  ot->description = "Select control points preceding already selected ones along the curves";
870 
871  /* api callbacks */
874 
875  /* flags */
877 }
878 
879 /***************** select more operator **********************/
880 
881 static void curve_select_more(Object *obedit)
882 {
883  ListBase *editnurb = object_editcurve_get(obedit);
884  BPoint *bp, *tempbp;
885  int a;
886  short sel = 0;
887 
888  /* note that NURBS surface is a special case because we mimic */
889  /* the behavior of "select more" of mesh tools. */
890  /* The algorithm is designed to work in planar cases so it */
891  /* may not be optimal always (example: end of NURBS sphere) */
892  if (obedit->type == OB_SURF) {
893  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
894  BLI_bitmap *selbpoints;
895  a = nu->pntsu * nu->pntsv;
896  bp = nu->bp;
897  selbpoints = BLI_BITMAP_NEW(a, "selectlist");
898  while (a > 0) {
899  if ((!BLI_BITMAP_TEST(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) {
900  /* upper control point */
901  if (a % nu->pntsu != 0) {
902  tempbp = bp - 1;
903  if (!(tempbp->f1 & SELECT)) {
904  select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
905  }
906  }
907 
908  /* left control point. select only if it is not selected already */
909  if (a - nu->pntsu > 0) {
910  sel = 0;
911  tempbp = bp + nu->pntsu;
912  if (!(tempbp->f1 & SELECT)) {
913  sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
914  }
915  /* make sure selected bpoint is discarded */
916  if (sel == 1) {
917  BLI_BITMAP_ENABLE(selbpoints, a - nu->pntsu);
918  }
919  }
920 
921  /* right control point */
922  if (a + nu->pntsu < nu->pntsu * nu->pntsv) {
923  tempbp = bp - nu->pntsu;
924  if (!(tempbp->f1 & SELECT)) {
925  select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
926  }
927  }
928 
929  /* lower control point. skip next bp in case selection was made */
930  if (a % nu->pntsu != 1) {
931  sel = 0;
932  tempbp = bp + 1;
933  if (!(tempbp->f1 & SELECT)) {
934  sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
935  }
936  if (sel) {
937  bp++;
938  a--;
939  }
940  }
941  }
942 
943  bp++;
944  a--;
945  }
946 
947  MEM_freeN(selbpoints);
948  }
949  }
950  else {
951  select_adjacent_cp(editnurb, 1, 0, SELECT);
952  select_adjacent_cp(editnurb, -1, 0, SELECT);
953  }
954 }
955 
957 {
958  ViewLayer *view_layer = CTX_data_view_layer(C);
959  uint objects_len = 0;
961  view_layer, CTX_wm_view3d(C), &objects_len);
962  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
963  Object *obedit = objects[ob_index];
964  curve_select_more(obedit);
967  }
968  MEM_freeN(objects);
969  return OPERATOR_FINISHED;
970 }
971 
973 {
974  /* identifiers */
975  ot->name = "Select More";
976  ot->idname = "CURVE_OT_select_more";
977  ot->description = "Select control points at the boundary of each selection region";
978 
979  /* api callbacks */
982 
983  /* flags */
985 }
986 
987 /******************** select less operator *****************/
988 
989 /* basic method: deselect if control point doesn't have all neighbors selected */
990 static void curve_select_less(Object *obedit)
991 {
992  ListBase *editnurb = object_editcurve_get(obedit);
993  BPoint *bp;
994  BezTriple *bezt;
995  int a;
996  int sel = 0;
997  bool lastsel = false;
998 
999  if (obedit->type == OB_SURF) {
1000  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1001  BLI_bitmap *selbpoints;
1002  a = nu->pntsu * nu->pntsv;
1003  bp = nu->bp;
1004  selbpoints = BLI_BITMAP_NEW(a, "selectlist");
1005  while (a--) {
1006  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1007  sel = 0;
1008 
1009  /* check if neighbors have been selected */
1010  /* edges of surface are an exception */
1011  if ((a + 1) % nu->pntsu == 0) {
1012  sel++;
1013  }
1014  else {
1015  bp--;
1016  if (BLI_BITMAP_TEST(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) {
1017  sel++;
1018  }
1019  bp++;
1020  }
1021 
1022  if ((a + 1) % nu->pntsu == 1) {
1023  sel++;
1024  }
1025  else {
1026  bp++;
1027  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1028  sel++;
1029  }
1030  bp--;
1031  }
1032 
1033  if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) {
1034  sel++;
1035  }
1036  else {
1037  bp -= nu->pntsu;
1038  if (BLI_BITMAP_TEST(selbpoints, a + nu->pntsu) ||
1039  ((bp->hide == 0) && (bp->f1 & SELECT))) {
1040  sel++;
1041  }
1042  bp += nu->pntsu;
1043  }
1044 
1045  if (a < nu->pntsu) {
1046  sel++;
1047  }
1048  else {
1049  bp += nu->pntsu;
1050  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1051  sel++;
1052  }
1053  bp -= nu->pntsu;
1054  }
1055 
1056  if (sel != 4) {
1058  BLI_BITMAP_ENABLE(selbpoints, a);
1059  }
1060  }
1061  else {
1062  lastsel = false;
1063  }
1064 
1065  bp++;
1066  }
1067 
1068  MEM_freeN(selbpoints);
1069  }
1070  }
1071  else {
1072  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1073  lastsel = false;
1074  /* check what type of curve/nurb it is */
1075  if (nu->type == CU_BEZIER) {
1076  a = nu->pntsu;
1077  bezt = nu->bezt;
1078  while (a--) {
1079  if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
1080  sel = (lastsel == 1);
1081 
1082  /* check if neighbors have been selected */
1083  /* first and last are exceptions */
1084  if (a == nu->pntsu - 1) {
1085  sel++;
1086  }
1087  else {
1088  bezt--;
1089  if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
1090  sel++;
1091  }
1092  bezt++;
1093  }
1094 
1095  if (a == 0) {
1096  sel++;
1097  }
1098  else {
1099  bezt++;
1100  if ((bezt->hide == 0) && (bezt->f2 & SELECT)) {
1101  sel++;
1102  }
1103  bezt--;
1104  }
1105 
1106  if (sel != 2) {
1108  lastsel = true;
1109  }
1110  else {
1111  lastsel = false;
1112  }
1113  }
1114  else {
1115  lastsel = false;
1116  }
1117 
1118  bezt++;
1119  }
1120  }
1121  else {
1122  a = nu->pntsu * nu->pntsv;
1123  bp = nu->bp;
1124  while (a--) {
1125  if ((lastsel == false) && (bp->hide == 0) && (bp->f1 & SELECT)) {
1126  sel = 0;
1127 
1128  /* first and last are exceptions */
1129  if (a == nu->pntsu * nu->pntsv - 1) {
1130  sel++;
1131  }
1132  else {
1133  bp--;
1134  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1135  sel++;
1136  }
1137  bp++;
1138  }
1139 
1140  if (a == 0) {
1141  sel++;
1142  }
1143  else {
1144  bp++;
1145  if ((bp->hide == 0) && (bp->f1 & SELECT)) {
1146  sel++;
1147  }
1148  bp--;
1149  }
1150 
1151  if (sel != 2) {
1153  lastsel = true;
1154  }
1155  else {
1156  lastsel = false;
1157  }
1158  }
1159  else {
1160  lastsel = false;
1161  }
1162 
1163  bp++;
1164  }
1165  }
1166  }
1167  }
1168 }
1169 
1171 {
1172  ViewLayer *view_layer = CTX_data_view_layer(C);
1173  uint objects_len = 0;
1175  view_layer, CTX_wm_view3d(C), &objects_len);
1176  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1177  Object *obedit = objects[ob_index];
1178  curve_select_less(obedit);
1181  }
1182  MEM_freeN(objects);
1183  return OPERATOR_FINISHED;
1184 }
1185 
1187 {
1188  /* identifiers */
1189  ot->name = "Select Less";
1190  ot->idname = "CURVE_OT_select_less";
1191  ot->description = "Deselect control points at the boundary of each selection region";
1192 
1193  /* api callbacks */
1196 
1197  /* flags */
1199 }
1200 
1201 /********************** select random *********************/
1202 
1203 static void curve_select_random(ListBase *editnurb, float randfac, int seed, bool select)
1204 {
1205  BezTriple *bezt;
1206  BPoint *bp;
1207  int a;
1208 
1209  RNG *rng = BLI_rng_new_srandom(seed);
1210 
1211  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1212  if (nu->type == CU_BEZIER) {
1213  bezt = nu->bezt;
1214  a = nu->pntsu;
1215  while (a--) {
1216  if (!bezt->hide) {
1217  if (BLI_rng_get_float(rng) < randfac) {
1219  }
1220  }
1221  bezt++;
1222  }
1223  }
1224  else {
1225  bp = nu->bp;
1226  a = nu->pntsu * nu->pntsv;
1227 
1228  while (a--) {
1229  if (!bp->hide) {
1230  if (BLI_rng_get_float(rng) < randfac) {
1232  }
1233  }
1234  bp++;
1235  }
1236  }
1237  }
1238 
1239  BLI_rng_free(rng);
1240 }
1241 
1243 {
1244  const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
1245  const float randfac = RNA_float_get(op->ptr, "ratio");
1247 
1248  ViewLayer *view_layer = CTX_data_view_layer(C);
1249  uint objects_len = 0;
1251  view_layer, CTX_wm_view3d(C), &objects_len);
1252 
1253  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1254  Object *obedit = objects[ob_index];
1255  ListBase *editnurb = object_editcurve_get(obedit);
1256  int seed_iter = seed;
1257 
1258  /* This gives a consistent result regardless of object order. */
1259  if (ob_index) {
1260  seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
1261  }
1262 
1263  curve_select_random(editnurb, randfac, seed_iter, select);
1265 
1268  }
1269 
1270  MEM_freeN(objects);
1271  return OPERATOR_FINISHED;
1272 }
1273 
1275 {
1276  /* identifiers */
1277  ot->name = "Select Random";
1278  ot->idname = "CURVE_OT_select_random";
1279  ot->description = "Randomly select some control points";
1280 
1281  /* api callbacks */
1284 
1285  /* flags */
1287 
1288  /* properties */
1290 }
1291 
1292 /********************* every nth number of point *******************/
1293 
1294 static void select_nth_bezt(Nurb *nu, BezTriple *bezt, const struct CheckerIntervalParams *params)
1295 {
1296  int a, start;
1297 
1298  start = bezt - nu->bezt;
1299  a = nu->pntsu;
1300  bezt = &nu->bezt[a - 1];
1301 
1302  while (a--) {
1303  const int depth = abs(start - a);
1306  }
1307 
1308  bezt--;
1309  }
1310 }
1311 
1312 static void select_nth_bp(Nurb *nu, BPoint *bp, const struct CheckerIntervalParams *params)
1313 {
1314  int a, startrow, startpnt;
1315  int row, pnt;
1316 
1317  startrow = (bp - nu->bp) / nu->pntsu;
1318  startpnt = (bp - nu->bp) % nu->pntsu;
1319 
1320  a = nu->pntsu * nu->pntsv;
1321  bp = &nu->bp[a - 1];
1322  row = nu->pntsv - 1;
1323  pnt = nu->pntsu - 1;
1324 
1325  while (a--) {
1326  const int depth = abs(pnt - startpnt) + abs(row - startrow);
1329  }
1330 
1331  pnt--;
1332  if (pnt < 0) {
1333  pnt = nu->pntsu - 1;
1334  row--;
1335  }
1336 
1337  bp--;
1338  }
1339 }
1340 
1342 {
1343  Nurb *nu = NULL;
1344  void *vert = NULL;
1345 
1346  if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
1347  return false;
1348  }
1349 
1350  if (nu->bezt) {
1351  select_nth_bezt(nu, vert, params);
1352  }
1353  else {
1354  select_nth_bp(nu, vert, params);
1355  }
1356 
1357  return true;
1358 }
1359 
1361 {
1362  ViewLayer *view_layer = CTX_data_view_layer(C);
1363  Object *obact = CTX_data_edit_object(C);
1364  View3D *v3d = CTX_wm_view3d(C);
1365  bool changed = false;
1366 
1367  struct CheckerIntervalParams op_params;
1369 
1370  uint objects_len = 0;
1372  view_layer, CTX_wm_view3d(C), &objects_len);
1373  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1374  Object *obedit = objects[ob_index];
1375  Curve *cu = obedit->data;
1376 
1377  if (!ED_curve_select_check(v3d, cu->editnurb)) {
1378  continue;
1379  }
1380 
1381  if (ed_curve_select_nth(obedit->data, &op_params) == true) {
1382  changed = true;
1383 
1386  }
1387  }
1388  MEM_freeN(objects);
1389 
1390  if (!changed) {
1391  if (obact->type == OB_SURF) {
1392  BKE_report(
1393  op->reports,
1394  RPT_ERROR,
1395  (objects_len == 1 ? "Surface has no active point" : "Surfaces have no active point"));
1396  }
1397  else {
1398  BKE_report(op->reports,
1399  RPT_ERROR,
1400  (objects_len == 1 ? "Curve has no active point" : "Curves have no active point"));
1401  }
1402  return OPERATOR_CANCELLED;
1403  }
1404  return OPERATOR_FINISHED;
1405 }
1406 
1408 {
1409  /* identifiers */
1410  ot->name = "Checker Deselect";
1411  ot->description = "Deselect every Nth point starting from the active one";
1412  ot->idname = "CURVE_OT_select_nth";
1413 
1414  /* api callbacks */
1415  ot->exec = select_nth_exec;
1417 
1418  /* flags */
1420 
1422 }
1423 
1424 /* -------------------------------------------------------------------- */
1429  {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
1430  {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
1431  {SIM_CMP_LT, "LESS", 0, "Less", ""},
1432 
1433  {0, NULL, 0, NULL, NULL},
1434 };
1435 
1436 enum {
1441 };
1442 
1444  {SIMCURHAND_TYPE, "TYPE", 0, "Type", ""},
1445  {SIMCURHAND_RADIUS, "RADIUS", 0, "Radius", ""},
1446  {SIMCURHAND_WEIGHT, "WEIGHT", 0, "Weight", ""},
1447  {SIMCURHAND_DIRECTION, "DIRECTION", 0, "Direction", ""},
1448  {0, NULL, 0, NULL, NULL},
1449 };
1450 
1452  Nurb *nu,
1453  BezTriple *bezt,
1454  float r_dir[3])
1455 {
1456  float rsmat[3][3];
1457  BKE_nurb_bezt_calc_normal(nu, bezt, r_dir);
1458  copy_m3_m4(rsmat, ob->obmat);
1459  mul_m3_v3(rsmat, r_dir);
1460  normalize_v3(r_dir);
1461 }
1462 
1463 static void nurb_bpoint_direction_worldspace_get(Object *ob, Nurb *nu, BPoint *bp, float r_dir[3])
1464 {
1465  float rsmat[3][3];
1466  BKE_nurb_bpoint_calc_normal(nu, bp, r_dir);
1467  copy_m3_m4(rsmat, ob->obmat);
1468  mul_m3_v3(rsmat, r_dir);
1469  normalize_v3(r_dir);
1470 }
1471 
1473  Object *ob, Nurb *nu, const int type, KDTree_1d *tree_1d, KDTree_3d *tree_3d)
1474 {
1475  float tree_entry[3] = {0.0f, 0.0f, 0.0f};
1476 
1477  if (nu->type == CU_BEZIER) {
1478  BezTriple *bezt;
1479  int i;
1480  int tree_index = 0;
1481 
1482  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
1483  if ((!bezt->hide) && (bezt->f1 & SELECT)) {
1484 
1485  switch (type) {
1486  case SIMCURHAND_RADIUS: {
1487  float radius_ref = bezt->radius;
1488  tree_entry[0] = radius_ref;
1489  break;
1490  }
1491  case SIMCURHAND_WEIGHT: {
1492  float weight_ref = bezt->weight;
1493  tree_entry[0] = weight_ref;
1494  break;
1495  }
1496  case SIMCURHAND_DIRECTION: {
1497  nurb_bezt_direction_worldspace_get(ob, nu, bezt, tree_entry);
1498  break;
1499  }
1500  }
1501  if (tree_1d) {
1502  BLI_kdtree_1d_insert(tree_1d, tree_index++, tree_entry);
1503  }
1504  else {
1505  BLI_kdtree_3d_insert(tree_3d, tree_index++, tree_entry);
1506  }
1507  }
1508  }
1509  }
1510  else {
1511  BPoint *bp;
1512  int i;
1513  int tree_index = 0;
1514 
1515  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
1516  if (!bp->hide && bp->f1 & SELECT) {
1517  switch (type) {
1518  case SIMCURHAND_RADIUS: {
1519  float radius_ref = bp->radius;
1520  tree_entry[0] = radius_ref;
1521  break;
1522  }
1523  case SIMCURHAND_WEIGHT: {
1524  float weight_ref = bp->weight;
1525  tree_entry[0] = weight_ref;
1526  break;
1527  }
1528  case SIMCURHAND_DIRECTION: {
1529  nurb_bpoint_direction_worldspace_get(ob, nu, bp, tree_entry);
1530  break;
1531  }
1532  }
1533  if (tree_1d) {
1534  BLI_kdtree_1d_insert(tree_1d, tree_index++, tree_entry);
1535  }
1536  else {
1537  BLI_kdtree_3d_insert(tree_3d, tree_index++, tree_entry);
1538  }
1539  }
1540  }
1541  }
1542 }
1543 
1545  Nurb *nu,
1546  const int type,
1547  const KDTree_1d *tree_1d,
1548  const KDTree_3d *tree_3d,
1549  const float thresh,
1550  const int compare)
1551 {
1552  const float thresh_cos = cosf(thresh * (float)M_PI_2);
1553  bool changed = false;
1554 
1555  if (nu->type == CU_BEZIER) {
1556  BezTriple *bezt;
1557  int i;
1558 
1559  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
1560  if (!bezt->hide) {
1561  bool select = false;
1562 
1563  switch (type) {
1564  case SIMCURHAND_RADIUS: {
1565  float radius_ref = bezt->radius;
1566  if (ED_select_similar_compare_float_tree(tree_1d, radius_ref, thresh, compare)) {
1567  select = true;
1568  }
1569  break;
1570  }
1571  case SIMCURHAND_WEIGHT: {
1572  float weight_ref = bezt->weight;
1573  if (ED_select_similar_compare_float_tree(tree_1d, weight_ref, thresh, compare)) {
1574  select = true;
1575  }
1576  break;
1577  }
1578  case SIMCURHAND_DIRECTION: {
1579  float dir[3];
1580  nurb_bezt_direction_worldspace_get(ob, nu, bezt, dir);
1581  KDTreeNearest_3d nearest;
1582  if (BLI_kdtree_3d_find_nearest(tree_3d, dir, &nearest) != -1) {
1583  float orient = angle_normalized_v3v3(dir, nearest.co);
1584  float delta = thresh_cos - fabsf(cosf(orient));
1585  if (ED_select_similar_compare_float(delta, thresh, compare)) {
1586  select = true;
1587  }
1588  }
1589  break;
1590  }
1591  }
1592 
1593  if (select) {
1595  changed = true;
1596  }
1597  }
1598  }
1599  }
1600  else {
1601  BPoint *bp;
1602  int i;
1603 
1604  for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
1605  if (!bp->hide) {
1606  bool select = false;
1607 
1608  switch (type) {
1609  case SIMCURHAND_RADIUS: {
1610  float radius_ref = bp->radius;
1611  if (ED_select_similar_compare_float_tree(tree_1d, radius_ref, thresh, compare)) {
1612  select = true;
1613  }
1614  break;
1615  }
1616  case SIMCURHAND_WEIGHT: {
1617  float weight_ref = bp->weight;
1618  if (ED_select_similar_compare_float_tree(tree_1d, weight_ref, thresh, compare)) {
1619  select = true;
1620  }
1621  break;
1622  }
1623  case SIMCURHAND_DIRECTION: {
1624  float dir[3];
1625  nurb_bpoint_direction_worldspace_get(ob, nu, bp, dir);
1626  KDTreeNearest_3d nearest;
1627  if (BLI_kdtree_3d_find_nearest(tree_3d, dir, &nearest) != -1) {
1628  float orient = angle_normalized_v3v3(dir, nearest.co);
1629  float delta = fabsf(cosf(orient)) - thresh_cos;
1630  if (ED_select_similar_compare_float(delta, thresh, compare)) {
1631  select = true;
1632  }
1633  }
1634  break;
1635  }
1636  }
1637 
1638  if (select) {
1640  changed = true;
1641  }
1642  }
1643  }
1644  }
1645  return changed;
1646 }
1647 
1649 {
1650  /* Get props. */
1651  const int optype = RNA_enum_get(op->ptr, "type");
1652  const float thresh = RNA_float_get(op->ptr, "threshold");
1653  const int compare = RNA_enum_get(op->ptr, "compare");
1654 
1655  ViewLayer *view_layer = CTX_data_view_layer(C);
1656  View3D *v3d = CTX_wm_view3d(C);
1657  int tot_nurbs_selected_all = 0;
1658  uint objects_len = 0;
1660  view_layer, CTX_wm_view3d(C), &objects_len);
1661 
1662  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1663  Object *obedit = objects[ob_index];
1664  Curve *cu = obedit->data;
1665  tot_nurbs_selected_all += ED_curve_select_count(v3d, cu->editnurb);
1666  }
1667 
1668  if (tot_nurbs_selected_all == 0) {
1669  BKE_report(op->reports, RPT_ERROR, "No control point selected");
1670  MEM_freeN(objects);
1671  return OPERATOR_CANCELLED;
1672  }
1673 
1674  KDTree_1d *tree_1d = NULL;
1675  KDTree_3d *tree_3d = NULL;
1676  short type_ref = 0;
1677 
1678  switch (optype) {
1679  case SIMCURHAND_RADIUS:
1680  case SIMCURHAND_WEIGHT:
1681  tree_1d = BLI_kdtree_1d_new(tot_nurbs_selected_all);
1682  break;
1683  case SIMCURHAND_DIRECTION:
1684  tree_3d = BLI_kdtree_3d_new(tot_nurbs_selected_all);
1685  break;
1686  }
1687 
1688  /* Get type of selected control points. */
1689  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1690  Object *obedit = objects[ob_index];
1691  Curve *cu = obedit->data;
1692  EditNurb *editnurb = cu->editnurb;
1693 
1694  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
1695  if (!ED_curve_nurb_select_check(v3d, nu)) {
1696  continue;
1697  }
1698  switch (optype) {
1699  case SIMCURHAND_TYPE: {
1700  type_ref |= nu->type;
1701  break;
1702  }
1703  case SIMCURHAND_RADIUS:
1704  case SIMCURHAND_WEIGHT:
1705  case SIMCURHAND_DIRECTION:
1706  curve_nurb_selected_type_get(obedit, nu, optype, tree_1d, tree_3d);
1707  break;
1708  }
1709  }
1710  }
1711 
1712  if (tree_1d != NULL) {
1713  BLI_kdtree_1d_deduplicate(tree_1d);
1714  BLI_kdtree_1d_balance(tree_1d);
1715  }
1716  if (tree_3d != NULL) {
1717  BLI_kdtree_3d_deduplicate(tree_3d);
1718  BLI_kdtree_3d_balance(tree_3d);
1719  }
1720 
1721  /* Select control points with desired type. */
1722  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1723  Object *obedit = objects[ob_index];
1724  Curve *cu = obedit->data;
1725  EditNurb *editnurb = cu->editnurb;
1726  bool changed = false;
1727 
1728  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
1729  switch (optype) {
1730  case SIMCURHAND_TYPE: {
1731  if (nu->type & type_ref) {
1732  changed |= ED_curve_nurb_select_all(nu);
1733  }
1734  break;
1735  }
1736  case SIMCURHAND_RADIUS:
1737  case SIMCURHAND_WEIGHT:
1738  case SIMCURHAND_DIRECTION:
1740  obedit, nu, optype, tree_1d, tree_3d, thresh, compare);
1741  break;
1742  }
1743  }
1744 
1745  if (changed) {
1748  }
1749  }
1750 
1751  MEM_freeN(objects);
1752 
1753  if (tree_1d != NULL) {
1754  BLI_kdtree_1d_free(tree_1d);
1755  }
1756  if (tree_3d != NULL) {
1757  BLI_kdtree_3d_free(tree_3d);
1758  }
1759  return OPERATOR_FINISHED;
1760 }
1761 
1763 {
1764  /* identifiers */
1765  ot->name = "Select Similar";
1766  ot->idname = "CURVE_OT_select_similar";
1767  ot->description = "Select similar curve points by property type";
1768 
1769  /* api callbacks */
1773 
1774  /* flags */
1776 
1777  /* properties */
1778  ot->prop = RNA_def_enum(
1779  ot->srna, "type", curve_prop_similar_types, SIMCURHAND_WEIGHT, "Type", "");
1780  RNA_def_enum(ot->srna, "compare", curve_prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
1781  RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.0, 100.0);
1782 }
1783 
1786 /* -------------------------------------------------------------------- */
1790 static float curve_calc_dist_pair(const Nurb *nu, int a, int b)
1791 {
1792  const float *a_fl, *b_fl;
1793 
1794  if (nu->type == CU_BEZIER) {
1795  a_fl = nu->bezt[a].vec[1];
1796  b_fl = nu->bezt[b].vec[1];
1797  }
1798  else {
1799  a_fl = nu->bp[a].vec;
1800  b_fl = nu->bp[b].vec;
1801  }
1802 
1803  return len_v3v3(a_fl, b_fl);
1804 }
1805 
1806 static float curve_calc_dist_span(Nurb *nu, int vert_src, int vert_dst)
1807 {
1808  const int u = nu->pntsu;
1809  int i_prev, i;
1810  float dist = 0.0f;
1811 
1812  BLI_assert(nu->pntsv <= 1);
1813 
1814  i_prev = vert_src;
1815  i = (i_prev + 1) % u;
1816 
1817  while (true) {
1818  dist += curve_calc_dist_pair(nu, i_prev, i);
1819 
1820  if (i == vert_dst) {
1821  break;
1822  }
1823  i = (i + 1) % u;
1824  }
1825  return dist;
1826 }
1827 
1828 static void curve_select_shortest_path_curve(Nurb *nu, int vert_src, int vert_dst)
1829 {
1830  const int u = nu->pntsu;
1831  int i;
1832 
1833  if (vert_src > vert_dst) {
1834  SWAP(int, vert_src, vert_dst);
1835  }
1836 
1837  if (nu->flagu & CU_NURB_CYCLIC) {
1838  if (curve_calc_dist_span(nu, vert_src, vert_dst) >
1839  curve_calc_dist_span(nu, vert_dst, vert_src)) {
1840  SWAP(int, vert_src, vert_dst);
1841  }
1842  }
1843 
1844  i = vert_src;
1845  while (true) {
1846  if (nu->type & CU_BEZIER) {
1848  }
1849  else {
1850  select_bpoint(&nu->bp[i], SELECT, SELECT, HIDDEN);
1851  }
1852 
1853  if (i == vert_dst) {
1854  break;
1855  }
1856  i = (i + 1) % u;
1857  }
1858 }
1859 
1860 static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst)
1861 {
1862  int totu = nu->pntsu;
1863  int totv = nu->pntsv;
1864  int vert_num = totu * totv;
1865 
1866  /* custom data */
1867  struct PointAdj {
1868  int vert, vert_prev;
1869  float cost;
1870  } * data;
1871 
1872  /* init connectivity data */
1873  data = MEM_mallocN(sizeof(*data) * vert_num, __func__);
1874  for (int i = 0; i < vert_num; i++) {
1875  data[i].vert = i;
1876  data[i].vert_prev = -1;
1877  data[i].cost = FLT_MAX;
1878  }
1879 
1880  /* init heap */
1881  HeapSimple *heap = BLI_heapsimple_new();
1882 
1883  int vert_curr = data[vert_src].vert;
1884  BLI_heapsimple_insert(heap, 0.0f, &data[vert_src].vert);
1885  data[vert_src].cost = 0.0f;
1886  data[vert_src].vert_prev = vert_src; /* nop */
1887 
1888  while (!BLI_heapsimple_is_empty(heap)) {
1889  vert_curr = *((int *)BLI_heapsimple_pop_min(heap));
1890  if (vert_curr == vert_dst) {
1891  break;
1892  }
1893 
1894  int u, v;
1895  BKE_nurb_index_to_uv(nu, vert_curr, &u, &v);
1896 
1897  /* loop over 4 adjacent verts */
1898  for (int sign = -1; sign != 3; sign += 2) {
1899  for (int axis = 0; axis != 2; axis += 1) {
1900  int uv_other[2] = {u, v};
1901  int vert_other;
1902 
1903  uv_other[axis] += sign;
1904 
1905  vert_other = BKE_nurb_index_from_uv(nu, uv_other[0], uv_other[1]);
1906  if (vert_other != -1) {
1907  const float dist = data[vert_curr].cost +
1908  curve_calc_dist_pair(nu, vert_curr, vert_other);
1909 
1910  if (data[vert_other].cost > dist) {
1911  data[vert_other].cost = dist;
1912  if (data[vert_other].vert_prev == -1) {
1913  BLI_heapsimple_insert(heap, data[vert_other].cost, &data[vert_other].vert);
1914  }
1915  data[vert_other].vert_prev = vert_curr;
1916  }
1917  }
1918  }
1919  }
1920  }
1921 
1922  BLI_heapsimple_free(heap, NULL);
1923 
1924  if (vert_curr == vert_dst) {
1925  int i = 0;
1926  while (vert_curr != vert_src && i++ < vert_num) {
1927  if (nu->type == CU_BEZIER) {
1928  select_beztriple(&nu->bezt[vert_curr], SELECT, SELECT, HIDDEN);
1929  }
1930  else {
1931  select_bpoint(&nu->bp[vert_curr], SELECT, SELECT, HIDDEN);
1932  }
1933  vert_curr = data[vert_curr].vert_prev;
1934  }
1935  }
1936 
1937  MEM_freeN(data);
1938 }
1939 
1941 {
1943  ViewContext vc;
1944  Nurb *nu_dst;
1945  BezTriple *bezt_dst;
1946  BPoint *bp_dst;
1947  int vert_dst;
1948  void *vert_dst_p;
1949  Base *basact = NULL;
1950 
1953  copy_v2_v2_int(vc.mval, event->mval);
1954 
1955  if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) {
1956  return OPERATOR_PASS_THROUGH;
1957  }
1958 
1960  Object *obedit = basact->object;
1961  Curve *cu = obedit->data;
1962  Nurb *nu_src = BKE_curve_nurb_active_get(cu);
1963  int vert_src = cu->actvert;
1964 
1965  if (vert_src == CU_ACT_NONE) {
1966  return OPERATOR_PASS_THROUGH;
1967  }
1968 
1969  if (nu_src != nu_dst) {
1970  BKE_report(op->reports, RPT_ERROR, "Control point belongs to another spline");
1971  return OPERATOR_CANCELLED;
1972  }
1973 
1974  vert_dst_p = bezt_dst ? (void *)bezt_dst : (void *)bp_dst;
1975  vert_dst = BKE_curve_nurb_vert_index_get(nu_dst, vert_dst_p);
1976  if (vert_src == vert_dst) {
1977  return OPERATOR_CANCELLED;
1978  }
1979 
1980  if ((obedit->type == OB_SURF) && (nu_src->pntsv > 1)) {
1981  curve_select_shortest_path_surf(nu_src, vert_src, vert_dst);
1982  }
1983  else {
1984  curve_select_shortest_path_curve(nu_src, vert_src, vert_dst);
1985  }
1986 
1987  BKE_curve_nurb_vert_active_set(cu, nu_dst, vert_dst_p);
1988 
1989  if (vc.view_layer->basact != basact) {
1990  ED_object_base_activate(C, basact);
1991  }
1992 
1995  return OPERATOR_FINISHED;
1996 }
1997 
1999 {
2000  /* identifiers */
2001  ot->name = "Pick Shortest Path";
2002  ot->idname = "CURVE_OT_shortest_path_pick";
2003  ot->description = "Select shortest path between two selections";
2004 
2005  /* api callbacks */
2008 
2009  /* flags */
2011 }
2012 
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert)
Definition: curve.c:5146
void BKE_nurb_index_to_uv(struct Nurb *nu, int index, int *r_u, int *r_v)
Definition: curve.c:981
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.c:959
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.c:5173
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3])
Definition: curve.c:1128
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.c:5100
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
Definition: curve.c:4475
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:430
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:63
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_NEW(_tot, _alloc_string)
Definition: BLI_bitmap.h:50
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
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:172
#define M_PI_2
Definition: BLI_math_base.h:41
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
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:505
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition: rand.cc:76
struct RNG * BLI_rng_new_srandom(unsigned int seed)
Definition: rand.cc:64
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:120
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ 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:541
bool ED_operator_editcurve(struct bContext *C)
Definition: screen_ops.c:560
bool ED_operator_editsurfcurve_region_view3d(struct bContext *C)
Definition: screen_ops.c:550
bool ED_operator_editsurf(struct bContext *C)
Definition: screen_ops.c:580
int ED_select_similar_compare_float(const float delta, const float thresh, const int compare)
Definition: select_utils.c:87
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree, const float length, const float thresh, const int compare)
@ SIM_CMP_LT
@ SIM_CMP_GT
@ SIM_CMP_EQ
#define DESELECT
Definition: ED_types.h:33
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:39
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_SELECT
Definition: WM_types.h:407
ATTR_WARN_UNUSED_RESULT const BMVert * v
static unsigned long seed
Definition: btSoftBody.h:39
#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:63
@ FIRST
Definition: curve_intern.h:64
@ LAST
Definition: curve_intern.h:65
eVisible_Types
Definition: curve_intern.h:58
@ HIDDEN
Definition: curve_intern.h:59
@ VISIBLE
Definition: curve_intern.h:60
const Depsgraph * depsgraph
ListBase * object_editcurve_get(Object *ob)
Definition: editcurve.c:89
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)
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)
bool ED_curve_select_check(View3D *v3d, struct EditNurb *editnurb)
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))
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)
bool ED_curve_deselect_all_multi(struct bContext *C)
bool ED_curve_nurb_select_check(View3D *v3d, Nurb *nu)
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 void curve_select_random(ListBase *editnurb, float randfac, int seed, bool select)
int ED_curve_nurb_select_count(View3D *v3d, Nurb *nu)
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)
@ SIMCURHAND_WEIGHT
@ SIMCURHAND_DIRECTION
@ SIMCURHAND_RADIUS
@ SIMCURHAND_TYPE
int ED_curve_select_count(View3D *v3d, struct EditNurb *editnurb)
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)
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]
#define cosf(x)
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
static unsigned a[3]
Definition: RandGen.cpp:92
double sign(double arg)
Definition: utility.h:250
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
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:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
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:3771
unsigned char uint8_t
Definition: stdint.h:81
short hide
float weight
uint8_t f1
float vec[4]
float radius
struct Object * object
float vec[3][3]
EditNurb * editnurb
ListBase nurbs
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
short flagu
struct Nurb * next
short type
BezTriple * bezt
BPoint * bp
float obmat[4][4]
void * data
Definition: rand.cc:48
View3DOverlay overlay
int mval[2]
Definition: ED_view3d.h:85
struct ViewLayer * view_layer
Definition: ED_view3d.h:77
struct View3D * v3d
Definition: ED_view3d.h:81
struct Base * basact
int mval[2]
Definition: WM_types.h:583
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct PointerRNA * ptr
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156
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))
Definition: wm_operators.c:982