Merge branch 'blender-v2.91-release'
[blender.git] / source / blender / editors / curve / editcurve.c
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
20 /** \file
21  * \ingroup edcurve
22  */
23
24 #include "DNA_anim_types.h"
25 #include "DNA_key_types.h"
26 #include "DNA_object_types.h"
27 #include "DNA_scene_types.h"
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_array_utils.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_ghash.h"
34 #include "BLI_math.h"
35
36 #include "BLT_translation.h"
37
38 #include "BKE_action.h"
39 #include "BKE_anim_data.h"
40 #include "BKE_context.h"
41 #include "BKE_curve.h"
42 #include "BKE_displist.h"
43 #include "BKE_fcurve.h"
44 #include "BKE_global.h"
45 #include "BKE_key.h"
46 #include "BKE_layer.h"
47 #include "BKE_lib_id.h"
48 #include "BKE_main.h"
49 #include "BKE_modifier.h"
50 #include "BKE_report.h"
51
52 #include "DEG_depsgraph.h"
53 #include "DEG_depsgraph_build.h"
54 #include "DEG_depsgraph_query.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "ED_curve.h"
60 #include "ED_object.h"
61 #include "ED_outliner.h"
62 #include "ED_screen.h"
63 #include "ED_transform.h"
64 #include "ED_transform_snap_object_context.h"
65 #include "ED_types.h"
66 #include "ED_view3d.h"
67
68 #include "curve_intern.h"
69
70 #include "curve_fit_nd.h"
71
72 #include "UI_interface.h"
73 #include "UI_resources.h"
74
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77 #include "RNA_enum_types.h"
78
79 void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus);
80 static void adduplicateflagNurb(
81     Object *obedit, View3D *v3d, ListBase *newnurb, const uint8_t flag, const bool split);
82 static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split);
83 static bool curve_delete_vertices(Object *obedit, View3D *v3d);
84
85 /* -------------------------------------------------------------------- */
86 /** \name Utility Functions
87  * \{ */
88
89 ListBase *object_editcurve_get(Object *ob)
90 {
91   if (ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
92     Curve *cu = ob->data;
93     return &cu->editnurb->nurbs;
94   }
95   return NULL;
96 }
97
98 /** \} */
99
100 /* -------------------------------------------------------------------- */
101 /** \name Debug Printing
102  * \{ */
103
104 #if 0
105 void printknots(Object *obedit)
106 {
107   ListBase *editnurb = object_editcurve_get(obedit);
108   Nurb *nu;
109   int a, num;
110
111   for (nu = editnurb->first; nu; nu = nu->next) {
112     if (ED_curve_nurb_select_check(nu) && nu->type == CU_NURBS) {
113       if (nu->knotsu) {
114         num = KNOTSU(nu);
115         for (a = 0; a < num; a++) {
116           printf("knotu %d: %f\n", a, nu->knotsu[a]);
117         }
118       }
119       if (nu->knotsv) {
120         num = KNOTSV(nu);
121         for (a = 0; a < num; a++) {
122           printf("knotv %d: %f\n", a, nu->knotsv[a]);
123         }
124       }
125     }
126   }
127 }
128 #endif
129
130 /** \} */
131
132 /* -------------------------------------------------------------------- */
133 /** \name Shape keys
134  * \{ */
135
136 static CVKeyIndex *init_cvKeyIndex(
137     void *cv, int key_index, int nu_index, int pt_index, int vertex_index)
138 {
139   CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), __func__);
140
141   cvIndex->orig_cv = cv;
142   cvIndex->key_index = key_index;
143   cvIndex->nu_index = nu_index;
144   cvIndex->pt_index = pt_index;
145   cvIndex->vertex_index = vertex_index;
146   cvIndex->switched = false;
147
148   return cvIndex;
149 }
150
151 static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
152 {
153   Nurb *nu = editnurb->nurbs.first;
154   Nurb *orignu = origBase->first;
155   GHash *gh;
156   BezTriple *bezt, *origbezt;
157   BPoint *bp, *origbp;
158   CVKeyIndex *keyIndex;
159   int a, key_index = 0, nu_index = 0, pt_index = 0, vertex_index = 0;
160
161   if (editnurb->keyindex) {
162     return;
163   }
164
165   gh = BLI_ghash_ptr_new("editNurb keyIndex");
166
167   while (orignu) {
168     if (orignu->bezt) {
169       a = orignu->pntsu;
170       bezt = nu->bezt;
171       origbezt = orignu->bezt;
172       pt_index = 0;
173       while (a--) {
174         /* We cannot keep *any* reference to curve obdata,
175          * it might be replaced and freed while editcurve remain in use
176          * (in viewport render case e.g.). Note that we could use a pool to avoid
177          * lots of malloc's here, but... not really a problem for now. */
178         BezTriple *origbezt_cpy = MEM_mallocN(sizeof(*origbezt), __func__);
179         *origbezt_cpy = *origbezt;
180         keyIndex = init_cvKeyIndex(origbezt_cpy, key_index, nu_index, pt_index, vertex_index);
181         BLI_ghash_insert(gh, bezt, keyIndex);
182         key_index += KEYELEM_FLOAT_LEN_BEZTRIPLE;
183         vertex_index += 3;
184         bezt++;
185         origbezt++;
186         pt_index++;
187       }
188     }
189     else {
190       a = orignu->pntsu * orignu->pntsv;
191       bp = nu->bp;
192       origbp = orignu->bp;
193       pt_index = 0;
194       while (a--) {
195         /* We cannot keep *any* reference to curve obdata,
196          * it might be replaced and freed while editcurve remain in use
197          * (in viewport render case e.g.). Note that we could use a pool to avoid
198          * lots of malloc's here, but... not really a problem for now. */
199         BPoint *origbp_cpy = MEM_mallocN(sizeof(*origbp_cpy), __func__);
200         *origbp_cpy = *origbp;
201         keyIndex = init_cvKeyIndex(origbp_cpy, key_index, nu_index, pt_index, vertex_index);
202         BLI_ghash_insert(gh, bp, keyIndex);
203         key_index += KEYELEM_FLOAT_LEN_BPOINT;
204         bp++;
205         origbp++;
206         pt_index++;
207         vertex_index++;
208       }
209     }
210
211     nu = nu->next;
212     orignu = orignu->next;
213     nu_index++;
214   }
215
216   editnurb->keyindex = gh;
217 }
218
219 static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, const void *cv)
220 {
221   return BLI_ghash_lookup(editnurb->keyindex, cv);
222 }
223
224 static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, const void *cv)
225 {
226   return BLI_ghash_popkey(editnurb->keyindex, cv, NULL);
227 }
228
229 static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, const BezTriple *bezt)
230 {
231   CVKeyIndex *index = getCVKeyIndex(editnurb, bezt);
232
233   if (!index) {
234     return NULL;
235   }
236
237   return (BezTriple *)index->orig_cv;
238 }
239
240 static BPoint *getKeyIndexOrig_bp(EditNurb *editnurb, BPoint *bp)
241 {
242   CVKeyIndex *index = getCVKeyIndex(editnurb, bp);
243
244   if (!index) {
245     return NULL;
246   }
247
248   return (BPoint *)index->orig_cv;
249 }
250
251 static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
252 {
253   CVKeyIndex *index = getCVKeyIndex(editnurb, cv);
254
255   if (!index) {
256     return -1;
257   }
258
259   return index->key_index;
260 }
261
262 static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
263 {
264   if (!editnurb->keyindex) {
265     return;
266   }
267
268   BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt);
269 }
270
271 static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
272 {
273   if (!editnurb->keyindex) {
274     return;
275   }
276
277   BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp);
278 }
279
280 static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
281 {
282   int a;
283
284   if (!editnurb->keyindex) {
285     return;
286   }
287
288   if (nu->bezt) {
289     const BezTriple *bezt = nu->bezt;
290     a = nu->pntsu;
291
292     while (a--) {
293       BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt);
294       bezt++;
295     }
296   }
297   else {
298     const BPoint *bp = nu->bp;
299     a = nu->pntsu * nu->pntsv;
300
301     while (a--) {
302       BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp);
303       bp++;
304     }
305   }
306 }
307
308 static void keyIndex_delNurbList(EditNurb *editnurb, ListBase *nubase)
309 {
310   Nurb *nu = nubase->first;
311
312   while (nu) {
313     keyIndex_delNurb(editnurb, nu);
314
315     nu = nu->next;
316   }
317 }
318
319 static void keyIndex_updateCV(EditNurb *editnurb, char *cv, char *newcv, int count, int size)
320 {
321   int i;
322   CVKeyIndex *index;
323
324   if (editnurb->keyindex == NULL) {
325     /* No shape keys - updating not needed */
326     return;
327   }
328
329   for (i = 0; i < count; i++) {
330     index = popCVKeyIndex(editnurb, cv);
331
332     if (index) {
333       BLI_ghash_insert(editnurb->keyindex, newcv, index);
334     }
335
336     newcv += size;
337     cv += size;
338   }
339 }
340
341 static void keyIndex_updateBezt(EditNurb *editnurb, BezTriple *bezt, BezTriple *newbezt, int count)
342 {
343   keyIndex_updateCV(editnurb, (char *)bezt, (char *)newbezt, count, sizeof(BezTriple));
344 }
345
346 static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp, BPoint *newbp, int count)
347 {
348   keyIndex_updateCV(editnurb, (char *)bp, (char *)newbp, count, sizeof(BPoint));
349 }
350
351 void ED_curve_keyindex_update_nurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
352 {
353   if (nu->bezt) {
354     keyIndex_updateBezt(editnurb, nu->bezt, newnu->bezt, newnu->pntsu);
355   }
356   else {
357     keyIndex_updateBP(editnurb, nu->bp, newnu->bp, newnu->pntsu * newnu->pntsv);
358   }
359 }
360
361 static void keyIndex_swap(EditNurb *editnurb, void *a, void *b)
362 {
363   CVKeyIndex *index1 = popCVKeyIndex(editnurb, a);
364   CVKeyIndex *index2 = popCVKeyIndex(editnurb, b);
365
366   if (index2) {
367     BLI_ghash_insert(editnurb->keyindex, a, index2);
368   }
369   if (index1) {
370     BLI_ghash_insert(editnurb->keyindex, b, index1);
371   }
372 }
373
374 static void keyIndex_switchDirection(EditNurb *editnurb, Nurb *nu)
375 {
376   int a;
377   CVKeyIndex *index1, *index2;
378
379   if (nu->bezt) {
380     BezTriple *bezt1, *bezt2;
381
382     a = nu->pntsu;
383
384     bezt1 = nu->bezt;
385     bezt2 = bezt1 + (a - 1);
386
387     if (a & 1) {
388       a++;
389     }
390
391     a /= 2;
392
393     while (a--) {
394       index1 = getCVKeyIndex(editnurb, bezt1);
395       index2 = getCVKeyIndex(editnurb, bezt2);
396
397       if (index1) {
398         index1->switched = !index1->switched;
399       }
400
401       if (bezt1 != bezt2) {
402         keyIndex_swap(editnurb, bezt1, bezt2);
403
404         if (index2) {
405           index2->switched = !index2->switched;
406         }
407       }
408
409       bezt1++;
410       bezt2--;
411     }
412   }
413   else {
414     BPoint *bp1, *bp2;
415
416     if (nu->pntsv == 1) {
417       a = nu->pntsu;
418       bp1 = nu->bp;
419       bp2 = bp1 + (a - 1);
420       a /= 2;
421       while (bp1 != bp2 && a > 0) {
422         index1 = getCVKeyIndex(editnurb, bp1);
423         index2 = getCVKeyIndex(editnurb, bp2);
424
425         if (index1) {
426           index1->switched = !index1->switched;
427         }
428
429         if (bp1 != bp2) {
430           if (index2) {
431             index2->switched = !index2->switched;
432           }
433
434           keyIndex_swap(editnurb, bp1, bp2);
435         }
436
437         a--;
438         bp1++;
439         bp2--;
440       }
441     }
442     else {
443       int b;
444
445       for (b = 0; b < nu->pntsv; b++) {
446
447         bp1 = &nu->bp[b * nu->pntsu];
448         a = nu->pntsu;
449         bp2 = bp1 + (a - 1);
450         a /= 2;
451
452         while (bp1 != bp2 && a > 0) {
453           index1 = getCVKeyIndex(editnurb, bp1);
454           index2 = getCVKeyIndex(editnurb, bp2);
455
456           if (index1) {
457             index1->switched = !index1->switched;
458           }
459
460           if (bp1 != bp2) {
461             if (index2) {
462               index2->switched = !index2->switched;
463             }
464
465             keyIndex_swap(editnurb, bp1, bp2);
466           }
467
468           a--;
469           bp1++;
470           bp2--;
471         }
472       }
473     }
474   }
475 }
476
477 static void switch_keys_direction(Curve *cu, Nurb *actnu)
478 {
479   EditNurb *editnurb = cu->editnurb;
480   ListBase *nubase = &editnurb->nurbs;
481   float *fp;
482   int a;
483
484   LISTBASE_FOREACH (KeyBlock *, currkey, &cu->key->block) {
485     fp = currkey->data;
486
487     LISTBASE_FOREACH (Nurb *, nu, nubase) {
488       if (nu->bezt) {
489         BezTriple *bezt = nu->bezt;
490         a = nu->pntsu;
491         if (nu == actnu) {
492           while (a--) {
493             if (getKeyIndexOrig_bezt(editnurb, bezt)) {
494               swap_v3_v3(fp, fp + 6);
495               *(fp + 9) = -*(fp + 9);
496               fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
497             }
498             bezt++;
499           }
500         }
501         else {
502           fp += a * KEYELEM_FLOAT_LEN_BEZTRIPLE;
503         }
504       }
505       else {
506         BPoint *bp = nu->bp;
507         a = nu->pntsu * nu->pntsv;
508         if (nu == actnu) {
509           while (a--) {
510             if (getKeyIndexOrig_bp(editnurb, bp)) {
511               *(fp + 3) = -*(fp + 3);
512               fp += KEYELEM_FLOAT_LEN_BPOINT;
513             }
514             bp++;
515           }
516         }
517         else {
518           fp += a * KEYELEM_FLOAT_LEN_BPOINT;
519         }
520       }
521     }
522   }
523 }
524
525 static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
526 {
527   EditNurb *editnurb = cu->editnurb;
528
529   if (!editnurb->keyindex) {
530     /* no shape keys - nothing to do */
531     return;
532   }
533
534   keyIndex_switchDirection(editnurb, nu);
535   if (cu->key) {
536     switch_keys_direction(cu, nu);
537   }
538 }
539
540 GHash *ED_curve_keyindex_hash_duplicate(GHash *keyindex)
541 {
542   GHash *gh;
543   GHashIterator gh_iter;
544
545   gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_len(keyindex));
546
547   GHASH_ITER (gh_iter, keyindex) {
548     void *cv = BLI_ghashIterator_getKey(&gh_iter);
549     CVKeyIndex *index = BLI_ghashIterator_getValue(&gh_iter);
550     CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
551
552     memcpy(newIndex, index, sizeof(CVKeyIndex));
553     newIndex->orig_cv = MEM_dupallocN(index->orig_cv);
554
555     BLI_ghash_insert(gh, cv, newIndex);
556   }
557
558   return gh;
559 }
560
561 static void key_to_bezt(float *key, BezTriple *basebezt, BezTriple *bezt)
562 {
563   memcpy(bezt, basebezt, sizeof(BezTriple));
564   memcpy(bezt->vec, key, sizeof(float[9]));
565   bezt->tilt = key[9];
566   bezt->radius = key[10];
567 }
568
569 static void bezt_to_key(BezTriple *bezt, float *key)
570 {
571   memcpy(key, bezt->vec, sizeof(float[9]));
572   key[9] = bezt->tilt;
573   key[10] = bezt->radius;
574 }
575
576 static void calc_keyHandles(ListBase *nurb, float *key)
577 {
578   int a;
579   float *fp = key;
580   BezTriple *bezt;
581
582   LISTBASE_FOREACH (Nurb *, nu, nurb) {
583     if (nu->bezt) {
584       BezTriple *prevp, *nextp;
585       BezTriple cur, prev, next;
586       float *startfp, *prevfp, *nextfp;
587
588       bezt = nu->bezt;
589       a = nu->pntsu;
590       startfp = fp;
591
592       if (nu->flagu & CU_NURB_CYCLIC) {
593         prevp = bezt + (a - 1);
594         prevfp = fp + (KEYELEM_FLOAT_LEN_BEZTRIPLE * (a - 1));
595       }
596       else {
597         prevp = NULL;
598         prevfp = NULL;
599       }
600
601       nextp = bezt + 1;
602       nextfp = fp + KEYELEM_FLOAT_LEN_BEZTRIPLE;
603
604       while (a--) {
605         key_to_bezt(fp, bezt, &cur);
606
607         if (nextp) {
608           key_to_bezt(nextfp, nextp, &next);
609         }
610         if (prevp) {
611           key_to_bezt(prevfp, prevp, &prev);
612         }
613
614         BKE_nurb_handle_calc(&cur, prevp ? &prev : NULL, nextp ? &next : NULL, 0, 0);
615         bezt_to_key(&cur, fp);
616
617         prevp = bezt;
618         prevfp = fp;
619         if (a == 1) {
620           if (nu->flagu & CU_NURB_CYCLIC) {
621             nextp = nu->bezt;
622             nextfp = startfp;
623           }
624           else {
625             nextp = NULL;
626             nextfp = NULL;
627           }
628         }
629         else {
630           nextp++;
631           nextfp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
632         }
633
634         bezt++;
635         fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
636       }
637     }
638     else {
639       a = nu->pntsu * nu->pntsv;
640       fp += a * KEYELEM_FLOAT_LEN_BPOINT;
641     }
642   }
643 }
644
645 static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
646 {
647   Curve *cu = (Curve *)obedit->data;
648
649   /* are there keys? */
650   if (cu->key) {
651     int a, i;
652     EditNurb *editnurb = cu->editnurb;
653     KeyBlock *currkey;
654     KeyBlock *actkey = BLI_findlink(&cu->key->block, editnurb->shapenr - 1);
655     BezTriple *bezt, *oldbezt;
656     BPoint *bp, *oldbp;
657     Nurb *newnu;
658     int totvert = BKE_keyblock_curve_element_count(&editnurb->nurbs);
659
660     float(*ofs)[3] = NULL;
661     float *oldkey, *newkey, *ofp;
662
663     /* editing the base key should update others */
664     if (cu->key->type == KEY_RELATIVE) {
665       if (BKE_keyblock_is_basis(cu->key, editnurb->shapenr - 1)) { /* active key is a base */
666         int totvec = 0;
667
668         /* Calculate needed memory to store offset */
669         LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
670
671           if (nu->bezt) {
672             /* Three vects to store handles and one for tilt. */
673             totvec += nu->pntsu * 4;
674           }
675           else {
676             totvec += 2 * nu->pntsu * nu->pntsv;
677           }
678         }
679
680         ofs = MEM_callocN(sizeof(float[3]) * totvec, "currkey->data");
681         i = 0;
682         LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
683           if (nu->bezt) {
684             bezt = nu->bezt;
685             a = nu->pntsu;
686             while (a--) {
687               oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
688
689               if (oldbezt) {
690                 int j;
691                 for (j = 0; j < 3; j++) {
692                   sub_v3_v3v3(ofs[i], bezt->vec[j], oldbezt->vec[j]);
693                   i++;
694                 }
695                 ofs[i][0] = bezt->tilt - oldbezt->tilt;
696                 ofs[i][1] = bezt->radius - oldbezt->radius;
697                 i++;
698               }
699               else {
700                 i += 4;
701               }
702               bezt++;
703             }
704           }
705           else {
706             bp = nu->bp;
707             a = nu->pntsu * nu->pntsv;
708             while (a--) {
709               oldbp = getKeyIndexOrig_bp(editnurb, bp);
710               if (oldbp) {
711                 sub_v3_v3v3(ofs[i], bp->vec, oldbp->vec);
712                 ofs[i + 1][0] = bp->tilt - oldbp->tilt;
713                 ofs[i + 1][1] = bp->radius - oldbp->radius;
714               }
715               i += 2;
716               bp++;
717             }
718           }
719         }
720       }
721     }
722
723     currkey = cu->key->block.first;
724     while (currkey) {
725       const bool apply_offset = (ofs && (currkey != actkey) &&
726                                  (editnurb->shapenr - 1 == currkey->relative));
727
728       float *fp = newkey = MEM_callocN(cu->key->elemsize * totvert, "currkey->data");
729       ofp = oldkey = currkey->data;
730
731       Nurb *nu = editnurb->nurbs.first;
732       /* We need to restore to original curve into newnurb, *not* editcurve's nurbs.
733        * Otherwise, in case we update obdata *without* leaving editmode (e.g. viewport render),
734        * we would invalidate editcurve. */
735       newnu = newnurbs->first;
736       i = 0;
737       while (nu) {
738         if (currkey == actkey) {
739           const bool restore = actkey != cu->key->refkey;
740
741           if (nu->bezt) {
742             bezt = nu->bezt;
743             a = nu->pntsu;
744             BezTriple *newbezt = newnu->bezt;
745             while (a--) {
746               int j;
747               oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
748
749               for (j = 0; j < 3; j++, i++) {
750                 copy_v3_v3(&fp[j * 3], bezt->vec[j]);
751
752                 if (restore && oldbezt) {
753                   copy_v3_v3(newbezt->vec[j], oldbezt->vec[j]);
754                 }
755               }
756               fp[9] = bezt->tilt;
757               fp[10] = bezt->radius;
758
759               if (restore && oldbezt) {
760                 newbezt->tilt = oldbezt->tilt;
761                 newbezt->radius = oldbezt->radius;
762               }
763
764               fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
765               i++;
766               bezt++;
767               newbezt++;
768             }
769           }
770           else {
771             bp = nu->bp;
772             a = nu->pntsu * nu->pntsv;
773             BPoint *newbp = newnu->bp;
774             while (a--) {
775               oldbp = getKeyIndexOrig_bp(editnurb, bp);
776
777               copy_v3_v3(fp, bp->vec);
778
779               fp[3] = bp->tilt;
780               fp[4] = bp->radius;
781
782               if (restore && oldbp) {
783                 copy_v3_v3(newbp->vec, oldbp->vec);
784                 newbp->tilt = oldbp->tilt;
785                 newbp->radius = oldbp->radius;
786               }
787
788               fp += KEYELEM_FLOAT_LEN_BPOINT;
789               bp++;
790               newbp++;
791               i += 2;
792             }
793           }
794         }
795         else {
796           int index;
797           const float *curofp;
798
799           if (oldkey) {
800             if (nu->bezt) {
801               bezt = nu->bezt;
802               a = nu->pntsu;
803
804               while (a--) {
805                 index = getKeyIndexOrig_keyIndex(editnurb, bezt);
806                 if (index >= 0) {
807                   int j;
808                   curofp = ofp + index;
809
810                   for (j = 0; j < 3; j++, i++) {
811                     copy_v3_v3(&fp[j * 3], &curofp[j * 3]);
812
813                     if (apply_offset) {
814                       add_v3_v3(&fp[j * 3], ofs[i]);
815                     }
816                   }
817                   fp[9] = curofp[9];
818                   fp[10] = curofp[10];
819
820                   if (apply_offset) {
821                     /* Apply tilt offsets. */
822                     add_v3_v3(fp + 9, ofs[i]);
823                     i++;
824                   }
825
826                   fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
827                 }
828                 else {
829                   int j;
830                   for (j = 0; j < 3; j++, i++) {
831                     copy_v3_v3(&fp[j * 3], bezt->vec[j]);
832                   }
833                   fp[9] = bezt->tilt;
834                   fp[10] = bezt->radius;
835
836                   fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
837                 }
838                 bezt++;
839               }
840             }
841             else {
842               bp = nu->bp;
843               a = nu->pntsu * nu->pntsv;
844               while (a--) {
845                 index = getKeyIndexOrig_keyIndex(editnurb, bp);
846
847                 if (index >= 0) {
848                   curofp = ofp + index;
849                   copy_v3_v3(fp, curofp);
850                   fp[3] = curofp[3];
851                   fp[4] = curofp[4];
852
853                   if (apply_offset) {
854                     add_v3_v3(fp, ofs[i]);
855                     add_v3_v3(&fp[3], ofs[i + 1]);
856                   }
857                 }
858                 else {
859                   copy_v3_v3(fp, bp->vec);
860                   fp[3] = bp->tilt;
861                   fp[4] = bp->radius;
862                 }
863
864                 fp += KEYELEM_FLOAT_LEN_BPOINT;
865                 bp++;
866                 i += 2;
867               }
868             }
869           }
870         }
871
872         nu = nu->next;
873         newnu = newnu->next;
874       }
875
876       if (apply_offset) {
877         /* handles could become malicious after offsets applying */
878         calc_keyHandles(&editnurb->nurbs, newkey);
879       }
880
881       currkey->totelem = totvert;
882       if (currkey->data) {
883         MEM_freeN(currkey->data);
884       }
885       currkey->data = newkey;
886
887       currkey = currkey->next;
888     }
889
890     if (ofs) {
891       MEM_freeN(ofs);
892     }
893   }
894 }
895
896 /** \} */
897
898 /* -------------------------------------------------------------------- */
899 /** \name Animation Data
900  * \{ */
901
902 static bool curve_is_animated(Curve *cu)
903 {
904   AnimData *ad = BKE_animdata_from_id(&cu->id);
905
906   return ad && (ad->action || ad->drivers.first);
907 }
908
909 static void fcurve_path_rename(AnimData *adt,
910                                const char *orig_rna_path,
911                                const char *rna_path,
912                                ListBase *orig_curves,
913                                ListBase *curves)
914 {
915   FCurve *nfcu;
916   int len = strlen(orig_rna_path);
917
918   LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, orig_curves) {
919     if (STREQLEN(fcu->rna_path, orig_rna_path, len)) {
920       char *spath, *suffix = fcu->rna_path + len;
921       nfcu = BKE_fcurve_copy(fcu);
922       spath = nfcu->rna_path;
923       nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
924
925       /* BKE_fcurve_copy() sets nfcu->grp to NULL. To maintain the groups, we need to keep the
926        * pointer. As a result, the group's 'channels' pointers will be wrong, which is fixed by
927        * calling `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
928       nfcu->grp = fcu->grp;
929       BLI_addtail(curves, nfcu);
930
931       if (fcu->grp) {
932         action_groups_remove_channel(adt->action, fcu);
933       }
934       else if ((adt->action) && (&adt->action->curves == orig_curves)) {
935         BLI_remlink(&adt->action->curves, fcu);
936       }
937       else {
938         BLI_remlink(&adt->drivers, fcu);
939       }
940
941       BKE_fcurve_free(fcu);
942
943       MEM_freeN(spath);
944     }
945   }
946 }
947
948 static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu)
949 {
950   if (orig_curves == &adt->drivers) {
951     BLI_remlink(&adt->drivers, fcu);
952   }
953   else {
954     action_groups_remove_channel(adt->action, fcu);
955   }
956
957   BKE_fcurve_free(fcu);
958 }
959
960 static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
961 {
962   int a, pt_index;
963   EditNurb *editnurb = cu->editnurb;
964   CVKeyIndex *keyIndex;
965   char rna_path[64], orig_rna_path[64];
966   AnimData *adt = BKE_animdata_from_id(&cu->id);
967   ListBase curves = {NULL, NULL};
968
969   int nu_index = 0;
970   LISTBASE_FOREACH_INDEX (Nurb *, nu, &editnurb->nurbs, nu_index) {
971     if (nu->bezt) {
972       BezTriple *bezt = nu->bezt;
973       a = nu->pntsu;
974       pt_index = 0;
975
976       while (a--) {
977         keyIndex = getCVKeyIndex(editnurb, bezt);
978         if (keyIndex) {
979           BLI_snprintf(
980               rna_path, sizeof(rna_path), "splines[%d].bezier_points[%d]", nu_index, pt_index);
981           BLI_snprintf(orig_rna_path,
982                        sizeof(orig_rna_path),
983                        "splines[%d].bezier_points[%d]",
984                        keyIndex->nu_index,
985                        keyIndex->pt_index);
986
987           if (keyIndex->switched) {
988             char handle_path[64], orig_handle_path[64];
989             BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_left", orig_rna_path);
990             BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_right", rna_path);
991             fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
992
993             BLI_snprintf(
994                 orig_handle_path, sizeof(orig_rna_path), "%s.handle_right", orig_rna_path);
995             BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_left", rna_path);
996             fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
997           }
998
999           fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1000
1001           keyIndex->nu_index = nu_index;
1002           keyIndex->pt_index = pt_index;
1003         }
1004
1005         bezt++;
1006         pt_index++;
1007       }
1008     }
1009     else {
1010       BPoint *bp = nu->bp;
1011       a = nu->pntsu * nu->pntsv;
1012       pt_index = 0;
1013
1014       while (a--) {
1015         keyIndex = getCVKeyIndex(editnurb, bp);
1016         if (keyIndex) {
1017           BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].points[%d]", nu_index, pt_index);
1018           BLI_snprintf(orig_rna_path,
1019                        sizeof(orig_rna_path),
1020                        "splines[%d].points[%d]",
1021                        keyIndex->nu_index,
1022                        keyIndex->pt_index);
1023           fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1024
1025           keyIndex->nu_index = nu_index;
1026           keyIndex->pt_index = pt_index;
1027         }
1028
1029         bp++;
1030         pt_index++;
1031       }
1032     }
1033   }
1034
1035   /* remove paths for removed control points
1036    * need this to make further step with copying non-cv related curves copying
1037    * not touching cv's f-curves */
1038   LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, orig_curves) {
1039     if (STREQLEN(fcu->rna_path, "splines", 7)) {
1040       const char *ch = strchr(fcu->rna_path, '.');
1041
1042       if (ch && (STREQLEN(ch, ".bezier_points", 14) || STREQLEN(ch, ".points", 7))) {
1043         fcurve_remove(adt, orig_curves, fcu);
1044       }
1045     }
1046   }
1047
1048   nu_index = 0;
1049   LISTBASE_FOREACH_INDEX (Nurb *, nu, &editnurb->nurbs, nu_index) {
1050     keyIndex = NULL;
1051     if (nu->pntsu) {
1052       if (nu->bezt) {
1053         keyIndex = getCVKeyIndex(editnurb, &nu->bezt[0]);
1054       }
1055       else {
1056         keyIndex = getCVKeyIndex(editnurb, &nu->bp[0]);
1057       }
1058     }
1059
1060     if (keyIndex) {
1061       BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d]", nu_index);
1062       BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d]", keyIndex->nu_index);
1063       fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1064     }
1065   }
1066
1067   /* the remainders in orig_curves can be copied back (like follow path) */
1068   /* (if it's not path to spline) */
1069   LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, orig_curves) {
1070     if (STREQLEN(fcu->rna_path, "splines", 7)) {
1071       fcurve_remove(adt, orig_curves, fcu);
1072     }
1073     else {
1074       BLI_addtail(&curves, fcu);
1075     }
1076   }
1077
1078   *orig_curves = curves;
1079   if (adt != NULL) {
1080     BKE_action_groups_reconstruct(adt->action);
1081   }
1082 }
1083
1084 /* return 0 if animation data wasn't changed, 1 otherwise */
1085 int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
1086 {
1087   AnimData *adt = BKE_animdata_from_id(&cu->id);
1088   EditNurb *editnurb = cu->editnurb;
1089
1090   if (!editnurb->keyindex) {
1091     return 0;
1092   }
1093
1094   if (!curve_is_animated(cu)) {
1095     return 0;
1096   }
1097
1098   if (adt->action != NULL) {
1099     curve_rename_fcurves(cu, &adt->action->curves);
1100     DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE);
1101   }
1102
1103   curve_rename_fcurves(cu, &adt->drivers);
1104   DEG_id_tag_update(&cu->id, ID_RECALC_COPY_ON_WRITE);
1105
1106   /* TODO(sergey): Only update if something actually changed. */
1107   DEG_relations_tag_update(bmain);
1108
1109   return 1;
1110 }
1111
1112 /** \} */
1113
1114 /* -------------------------------------------------------------------- */
1115 /** \name Edit Mode Conversion (Make & Load)
1116  * \{ */
1117
1118 static int *init_index_map(Object *obedit, int *r_old_totvert)
1119 {
1120   Curve *curve = (Curve *)obedit->data;
1121   EditNurb *editnurb = curve->editnurb;
1122   CVKeyIndex *keyIndex;
1123   int *old_to_new_map;
1124
1125   int old_totvert = 0;
1126   LISTBASE_FOREACH (Nurb *, nu, &curve->nurb) {
1127     if (nu->bezt) {
1128       old_totvert += nu->pntsu * 3;
1129     }
1130     else {
1131       old_totvert += nu->pntsu * nu->pntsv;
1132     }
1133   }
1134
1135   old_to_new_map = MEM_mallocN(old_totvert * sizeof(int), "curve old to new index map");
1136   for (int i = 0; i < old_totvert; i++) {
1137     old_to_new_map[i] = -1;
1138   }
1139
1140   int vertex_index = 0;
1141   LISTBASE_FOREACH (Nurb *, nu, &curve->nurb) {
1142     if (nu->bezt) {
1143       BezTriple *bezt = nu->bezt;
1144       int a = nu->pntsu;
1145
1146       while (a--) {
1147         keyIndex = getCVKeyIndex(editnurb, bezt);
1148         if (keyIndex && keyIndex->vertex_index + 2 < old_totvert) {
1149           if (keyIndex->switched) {
1150             old_to_new_map[keyIndex->vertex_index] = vertex_index + 2;
1151             old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
1152             old_to_new_map[keyIndex->vertex_index + 2] = vertex_index;
1153           }
1154           else {
1155             old_to_new_map[keyIndex->vertex_index] = vertex_index;
1156             old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
1157             old_to_new_map[keyIndex->vertex_index + 2] = vertex_index + 2;
1158           }
1159         }
1160         vertex_index += 3;
1161         bezt++;
1162       }
1163     }
1164     else {
1165       BPoint *bp = nu->bp;
1166       int a = nu->pntsu * nu->pntsv;
1167
1168       while (a--) {
1169         keyIndex = getCVKeyIndex(editnurb, bp);
1170         if (keyIndex) {
1171           old_to_new_map[keyIndex->vertex_index] = vertex_index;
1172         }
1173         vertex_index++;
1174         bp++;
1175       }
1176     }
1177   }
1178
1179   *r_old_totvert = old_totvert;
1180   return old_to_new_map;
1181 }
1182
1183 static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit)
1184 {
1185   Curve *curve = (Curve *)obedit->data;
1186   EditNurb *editnurb = curve->editnurb;
1187   int *old_to_new_map = NULL;
1188   int old_totvert;
1189
1190   if (editnurb->keyindex == NULL) {
1191     /* TODO(sergey): Happens when separating curves, this would lead to
1192      * the wrong indices in the hook modifier, address this together with
1193      * other indices issues.
1194      */
1195     return;
1196   }
1197
1198   LISTBASE_FOREACH (Object *, object, &bmain->objects) {
1199     int index;
1200     if ((object->parent) && (object->parent->data == curve) &&
1201         ELEM(object->partype, PARVERT1, PARVERT3)) {
1202       if (old_to_new_map == NULL) {
1203         old_to_new_map = init_index_map(obedit, &old_totvert);
1204       }
1205
1206       if (object->par1 < old_totvert) {
1207         index = old_to_new_map[object->par1];
1208         if (index != -1) {
1209           object->par1 = index;
1210         }
1211       }
1212       if (object->par2 < old_totvert) {
1213         index = old_to_new_map[object->par2];
1214         if (index != -1) {
1215           object->par2 = index;
1216         }
1217       }
1218       if (object->par3 < old_totvert) {
1219         index = old_to_new_map[object->par3];
1220         if (index != -1) {
1221           object->par3 = index;
1222         }
1223       }
1224     }
1225     if (object->data == curve) {
1226       LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
1227         if (md->type == eModifierType_Hook) {
1228           HookModifierData *hmd = (HookModifierData *)md;
1229           int i, j;
1230
1231           if (old_to_new_map == NULL) {
1232             old_to_new_map = init_index_map(obedit, &old_totvert);
1233           }
1234
1235           for (i = j = 0; i < hmd->totindex; i++) {
1236             if (hmd->indexar[i] < old_totvert) {
1237               index = old_to_new_map[hmd->indexar[i]];
1238               if (index != -1) {
1239                 hmd->indexar[j++] = index;
1240               }
1241             }
1242             else {
1243               j++;
1244             }
1245           }
1246
1247           hmd->totindex = j;
1248         }
1249       }
1250     }
1251   }
1252   if (old_to_new_map != NULL) {
1253     MEM_freeN(old_to_new_map);
1254   }
1255 }
1256
1257 /* load editNurb in object */
1258 void ED_curve_editnurb_load(Main *bmain, Object *obedit)
1259 {
1260   ListBase *editnurb = object_editcurve_get(obedit);
1261
1262   if (obedit == NULL) {
1263     return;
1264   }
1265
1266   if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1267     Curve *cu = obedit->data;
1268     ListBase newnurb = {NULL, NULL}, oldnurb = cu->nurb;
1269
1270     remap_hooks_and_vertex_parents(bmain, obedit);
1271
1272     LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1273       Nurb *newnu = BKE_nurb_duplicate(nu);
1274       BLI_addtail(&newnurb, newnu);
1275
1276       if (nu->type == CU_NURBS) {
1277         BKE_nurb_order_clamp_u(nu);
1278       }
1279     }
1280
1281     /* We have to pass also new copied nurbs, since we want to restore original curve
1282      * (without edited shapekey) on obdata, but *not* on editcurve itself
1283      * (ED_curve_editnurb_load call does not always implies freeing
1284      * of editcurve, e.g. when called to generate render data). */
1285     calc_shapeKeys(obedit, &newnurb);
1286
1287     cu->nurb = newnurb;
1288
1289     ED_curve_updateAnimPaths(bmain, obedit->data);
1290
1291     BKE_nurbList_free(&oldnurb);
1292   }
1293 }
1294
1295 /* make copy in cu->editnurb */
1296 void ED_curve_editnurb_make(Object *obedit)
1297 {
1298   Curve *cu = (Curve *)obedit->data;
1299   EditNurb *editnurb = cu->editnurb;
1300   KeyBlock *actkey;
1301
1302   if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1303     actkey = BKE_keyblock_from_object(obedit);
1304
1305     if (actkey) {
1306       // XXX strcpy(G.editModeTitleExtra, "(Key) ");
1307       /* TODO(campbell): undo_system: investigate why this was needed. */
1308 #if 0
1309       undo_editmode_clear();
1310 #endif
1311     }
1312
1313     if (editnurb) {
1314       BKE_nurbList_free(&editnurb->nurbs);
1315       BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
1316     }
1317     else {
1318       editnurb = MEM_callocN(sizeof(EditNurb), "editnurb");
1319       cu->editnurb = editnurb;
1320     }
1321
1322     LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
1323       Nurb *newnu = BKE_nurb_duplicate(nu);
1324       BKE_nurb_test_2d(newnu); /* after join, or any other creation of curve */
1325       BLI_addtail(&editnurb->nurbs, newnu);
1326     }
1327
1328     /* animation could be added in editmode even if there was no animdata in
1329      * object mode hence we always need CVs index be created */
1330     init_editNurb_keyIndex(editnurb, &cu->nurb);
1331
1332     if (actkey) {
1333       editnurb->shapenr = obedit->shapenr;
1334       /* Apply shapekey to new nurbs of editnurb, not those of original curve
1335        * (and *after* we generated keyIndex), else we do not have valid 'original' data
1336        * to properly restore curve when leaving editmode. */
1337       BKE_keyblock_convert_to_curve(actkey, cu, &editnurb->nurbs);
1338     }
1339   }
1340 }
1341
1342 void ED_curve_editnurb_free(Object *obedit)
1343 {
1344   Curve *cu = obedit->data;
1345
1346   BKE_curve_editNurb_free(cu);
1347 }
1348
1349 /** \} */
1350
1351 /* -------------------------------------------------------------------- */
1352 /** \name Separate Operator
1353  * \{ */
1354
1355 static int separate_exec(bContext *C, wmOperator *op)
1356 {
1357   Main *bmain = CTX_data_main(C);
1358   Scene *scene = CTX_data_scene(C);
1359   ViewLayer *view_layer = CTX_data_view_layer(C);
1360   View3D *v3d = CTX_wm_view3d(C);
1361
1362   struct {
1363     int changed;
1364     int unselected;
1365     int error_vertex_keys;
1366     int error_generic;
1367   } status = {0};
1368
1369   WM_cursor_wait(1);
1370
1371   uint bases_len = 0;
1372   Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
1373       view_layer, CTX_wm_view3d(C), &bases_len);
1374   for (uint b_index = 0; b_index < bases_len; b_index++) {
1375     Base *oldbase = bases[b_index];
1376     Base *newbase;
1377     Object *oldob, *newob;
1378     Curve *oldcu, *newcu;
1379     EditNurb *newedit;
1380     ListBase newnurb = {NULL, NULL};
1381
1382     oldob = oldbase->object;
1383     oldcu = oldob->data;
1384
1385     if (oldcu->key) {
1386       status.error_vertex_keys++;
1387       continue;
1388     }
1389
1390     if (!ED_curve_select_check(v3d, oldcu->editnurb)) {
1391       status.unselected++;
1392       continue;
1393     }
1394
1395     /* 1. Duplicate geometry and check for valid selection for separate. */
1396     adduplicateflagNurb(oldob, v3d, &newnurb, SELECT, true);
1397
1398     if (BLI_listbase_is_empty(&newnurb)) {
1399       status.error_generic++;
1400       continue;
1401     }
1402
1403     /* 2. Duplicate the object and data. */
1404
1405     /* Take into account user preferences for duplicating actions. */
1406     const eDupli_ID_Flags dupflag = (U.dupflag & USER_DUP_ACT);
1407
1408     newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, dupflag);
1409     DEG_relations_tag_update(bmain);
1410
1411     newob = newbase->object;
1412     newcu = newob->data = BKE_id_copy(bmain, &oldcu->id);
1413     newcu->editnurb = NULL;
1414     id_us_min(&oldcu->id); /* Because new curve is a copy: reduce user count. */
1415
1416     /* 3. Put new object in editmode, clear it and set separated nurbs. */
1417     ED_curve_editnurb_make(newob);
1418     newedit = newcu->editnurb;
1419     BKE_nurbList_free(&newedit->nurbs);
1420     BKE_curve_editNurb_keyIndex_free(&newedit->keyindex);
1421     BLI_movelisttolist(&newedit->nurbs, &newnurb);
1422
1423     /* 4. Put old object out of editmode and delete separated geometry. */
1424     ED_curve_editnurb_load(bmain, newob);
1425     ED_curve_editnurb_free(newob);
1426     curve_delete_segments(oldob, v3d, true);
1427
1428     DEG_id_tag_update(&oldob->id, ID_RECALC_GEOMETRY); /* This is the original one. */
1429     DEG_id_tag_update(&newob->id, ID_RECALC_GEOMETRY); /* This is the separated one. */
1430
1431     WM_event_add_notifier(C, NC_GEOM | ND_DATA, oldob->data);
1432     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob);
1433     status.changed++;
1434   }
1435   MEM_freeN(bases);
1436   WM_cursor_wait(0);
1437
1438   if (status.unselected == bases_len) {
1439     BKE_report(op->reports, RPT_ERROR, "No point was selected");
1440     return OPERATOR_CANCELLED;
1441   }
1442
1443   const int tot_errors = status.error_vertex_keys + status.error_generic;
1444   if (tot_errors > 0) {
1445
1446     /* Some curves changed, but some curves failed: don't explain why it failed. */
1447     if (status.changed) {
1448       BKE_reportf(op->reports,
1449                   RPT_INFO,
1450                   tot_errors == 1 ? "%d curve could not be separated" :
1451                                     "%d curves could not be separated",
1452                   tot_errors);
1453       return OPERATOR_FINISHED;
1454     }
1455
1456     /* All curves failed: If there is more than one error give a generic error report. */
1457     if (((status.error_vertex_keys ? 1 : 0) + (status.error_generic ? 1 : 0)) > 1) {
1458       BKE_report(op->reports,
1459                  RPT_ERROR,
1460                  tot_errors == 1 ? "Could not separate selected curves" :
1461                                    "Could not separate selected curve");
1462     }
1463
1464     /* All curves failed due to the same error. */
1465     if (status.error_vertex_keys) {
1466       BKE_report(op->reports, RPT_ERROR, "Cannot separate curves with vertex keys");
1467     }
1468     else {
1469       BLI_assert(status.error_generic);
1470       BKE_report(op->reports, RPT_ERROR, "Cannot separate current selection");
1471     }
1472     return OPERATOR_CANCELLED;
1473   }
1474
1475   ED_outliner_select_sync_from_object_tag(C);
1476
1477   return OPERATOR_FINISHED;
1478 }
1479
1480 void CURVE_OT_separate(wmOperatorType *ot)
1481 {
1482   /* identifiers */
1483   ot->name = "Separate";
1484   ot->idname = "CURVE_OT_separate";
1485   ot->description = "Separate selected points from connected unselected points into a new object";
1486
1487   /* api callbacks */
1488   ot->invoke = WM_operator_confirm;
1489   ot->exec = separate_exec;
1490   ot->poll = ED_operator_editsurfcurve;
1491
1492   /* flags */
1493   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1494 }
1495
1496 /** \} */
1497
1498 /* -------------------------------------------------------------------- */
1499 /** \name Split Operator
1500  * \{ */
1501
1502 static int curve_split_exec(bContext *C, wmOperator *op)
1503 {
1504   Main *bmain = CTX_data_main(C);
1505   ViewLayer *view_layer = CTX_data_view_layer(C);
1506   View3D *v3d = CTX_wm_view3d(C);
1507   int ok = -1;
1508
1509   uint objects_len;
1510   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
1511       view_layer, CTX_wm_view3d(C), &objects_len);
1512   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1513     Object *obedit = objects[ob_index];
1514     Curve *cu = obedit->data;
1515
1516     if (!ED_curve_select_check(v3d, cu->editnurb)) {
1517       continue;
1518     }
1519
1520     ListBase newnurb = {NULL, NULL};
1521
1522     adduplicateflagNurb(obedit, v3d, &newnurb, SELECT, true);
1523
1524     if (BLI_listbase_is_empty(&newnurb)) {
1525       ok = MAX2(ok, 0);
1526       continue;
1527     }
1528
1529     ListBase *editnurb = object_editcurve_get(obedit);
1530     const int len_orig = BLI_listbase_count(editnurb);
1531
1532     curve_delete_segments(obedit, v3d, true);
1533     cu->actnu -= len_orig - BLI_listbase_count(editnurb);
1534     BLI_movelisttolist(editnurb, &newnurb);
1535
1536     if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
1537       WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
1538     }
1539
1540     ok = 1;
1541     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1542     DEG_id_tag_update(obedit->data, 0);
1543   }
1544   MEM_freeN(objects);
1545
1546   if (ok == 0) {
1547     BKE_report(op->reports, RPT_ERROR, "Cannot split current selection");
1548     return OPERATOR_CANCELLED;
1549   }
1550   return OPERATOR_FINISHED;
1551 }
1552
1553 void CURVE_OT_split(wmOperatorType *ot)
1554 {
1555   /* identifiers */
1556   ot->name = "Split";
1557   ot->idname = "CURVE_OT_split";
1558   ot->description = "Split off selected points from connected unselected points";
1559
1560   /* api callbacks */
1561   ot->exec = curve_split_exec;
1562   ot->poll = ED_operator_editsurfcurve;
1563
1564   /* flags */
1565   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1566 }
1567
1568 /** \} */
1569
1570 /* -------------------------------------------------------------------- */
1571 /** \name Flag Utility Functions
1572  * \{ */
1573
1574 static bool isNurbselUV(const Nurb *nu, uint8_t flag, int *r_u, int *r_v)
1575 {
1576   /* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv
1577    * return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu
1578    */
1579   BPoint *bp;
1580   int a, b, sel;
1581
1582   *r_u = *r_v = -1;
1583
1584   bp = nu->bp;
1585   for (b = 0; b < nu->pntsv; b++) {
1586     sel = 0;
1587     for (a = 0; a < nu->pntsu; a++, bp++) {
1588       if (bp->f1 & flag) {
1589         sel++;
1590       }
1591     }
1592     if (sel == nu->pntsu) {
1593       if (*r_u == -1) {
1594         *r_u = b;
1595       }
1596       else {
1597         return 0;
1598       }
1599     }
1600     else if (sel > 1) {
1601       return 0; /* because sel == 1 is still ok */
1602     }
1603   }
1604
1605   for (a = 0; a < nu->pntsu; a++) {
1606     sel = 0;
1607     bp = &nu->bp[a];
1608     for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1609       if (bp->f1 & flag) {
1610         sel++;
1611       }
1612     }
1613     if (sel == nu->pntsv) {
1614       if (*r_v == -1) {
1615         *r_v = a;
1616       }
1617       else {
1618         return 0;
1619       }
1620     }
1621     else if (sel > 1) {
1622       return 0;
1623     }
1624   }
1625
1626   if (*r_u == -1 && *r_v > -1) {
1627     return 1;
1628   }
1629   if (*r_v == -1 && *r_u > -1) {
1630     return 1;
1631   }
1632   return 0;
1633 }
1634
1635 /* return true if U direction is selected and number of selected columns v */
1636 static bool isNurbselU(Nurb *nu, int *v, int flag)
1637 {
1638   BPoint *bp;
1639   int a, b, sel;
1640
1641   *v = 0;
1642
1643   for (b = 0, bp = nu->bp; b < nu->pntsv; b++) {
1644     sel = 0;
1645     for (a = 0; a < nu->pntsu; a++, bp++) {
1646       if (bp->f1 & flag) {
1647         sel++;
1648       }
1649     }
1650     if (sel == nu->pntsu) {
1651       (*v)++;
1652     }
1653     else if (sel >= 1) {
1654       *v = 0;
1655       return 0;
1656     }
1657   }
1658
1659   return 1;
1660 }
1661
1662 /* return true if V direction is selected and number of selected rows u */
1663 static bool isNurbselV(Nurb *nu, int *u, int flag)
1664 {
1665   BPoint *bp;
1666   int a, b, sel;
1667
1668   *u = 0;
1669
1670   for (a = 0; a < nu->pntsu; a++) {
1671     bp = &nu->bp[a];
1672     sel = 0;
1673     for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1674       if (bp->f1 & flag) {
1675         sel++;
1676       }
1677     }
1678     if (sel == nu->pntsv) {
1679       (*u)++;
1680     }
1681     else if (sel >= 1) {
1682       *u = 0;
1683       return 0;
1684     }
1685   }
1686
1687   return 1;
1688 }
1689
1690 static void rotateflagNurb(ListBase *editnurb,
1691                            short flag,
1692                            const float cent[3],
1693                            const float rotmat[3][3])
1694 {
1695   /* all verts with (flag & 'flag') rotate */
1696   BPoint *bp;
1697   int a;
1698
1699   LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1700     if (nu->type == CU_NURBS) {
1701       bp = nu->bp;
1702       a = nu->pntsu * nu->pntsv;
1703
1704       while (a--) {
1705         if (bp->f1 & flag) {
1706           sub_v3_v3(bp->vec, cent);
1707           mul_m3_v3(rotmat, bp->vec);
1708           add_v3_v3(bp->vec, cent);
1709         }
1710         bp++;
1711       }
1712     }
1713   }
1714 }
1715
1716 void ed_editnurb_translate_flag(ListBase *editnurb, uint8_t flag, const float vec[3])
1717 {
1718   /* all verts with ('flag' & flag) translate */
1719   BezTriple *bezt;
1720   BPoint *bp;
1721   int a;
1722
1723   LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1724     if (nu->type == CU_BEZIER) {
1725       a = nu->pntsu;
1726       bezt = nu->bezt;
1727       while (a--) {
1728         if (bezt->f1 & flag) {
1729           add_v3_v3(bezt->vec[0], vec);
1730         }
1731         if (bezt->f2 & flag) {
1732           add_v3_v3(bezt->vec[1], vec);
1733         }
1734         if (bezt->f3 & flag) {
1735           add_v3_v3(bezt->vec[2], vec);
1736         }
1737         bezt++;
1738       }
1739     }
1740     else {
1741       a = nu->pntsu * nu->pntsv;
1742       bp = nu->bp;
1743       while (a--) {
1744         if (bp->f1 & flag) {
1745           add_v3_v3(bp->vec, vec);
1746         }
1747         bp++;
1748       }
1749     }
1750
1751     BKE_nurb_test_2d(nu);
1752   }
1753 }
1754
1755 static void weightflagNurb(ListBase *editnurb, short flag, float w)
1756 {
1757   BPoint *bp;
1758   int a;
1759
1760   LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1761     if (nu->type == CU_NURBS) {
1762       a = nu->pntsu * nu->pntsv;
1763       bp = nu->bp;
1764       while (a--) {
1765         if (bp->f1 & flag) {
1766           /* a mode used to exist for replace/multiple but is was unused */
1767           bp->vec[3] *= w;
1768         }
1769         bp++;
1770       }
1771     }
1772   }
1773 }
1774
1775 static void ed_surf_delete_selected(Object *obedit)
1776 {
1777   Curve *cu = obedit->data;
1778   ListBase *editnurb = object_editcurve_get(obedit);
1779   BPoint *bp, *bpn, *newbp;
1780   int a, b, newu, newv;
1781
1782   BLI_assert(obedit->type == OB_SURF);
1783
1784   LISTBASE_FOREACH_MUTABLE (Nurb *, nu, editnurb) {
1785     /* is entire nurb selected */
1786     bp = nu->bp;
1787     a = nu->pntsu * nu->pntsv;
1788     while (a) {
1789       a--;
1790       if (bp->f1 & SELECT) {
1791         /* pass */
1792       }
1793       else {
1794         break;
1795       }
1796       bp++;
1797     }
1798     if (a == 0) {
1799       BLI_remlink(editnurb, nu);
1800       keyIndex_delNurb(cu->editnurb, nu);
1801       BKE_nurb_free(nu);
1802       nu = NULL;
1803     }
1804     else {
1805       if (isNurbselU(nu, &newv, SELECT)) {
1806         /* U direction selected */
1807         newv = nu->pntsv - newv;
1808         if (newv != nu->pntsv) {
1809           /* delete */
1810           bp = nu->bp;
1811           bpn = newbp = (BPoint *)MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
1812           for (b = 0; b < nu->pntsv; b++) {
1813             if ((bp->f1 & SELECT) == 0) {
1814               memcpy(bpn, bp, nu->pntsu * sizeof(BPoint));
1815               keyIndex_updateBP(cu->editnurb, bp, bpn, nu->pntsu);
1816               bpn += nu->pntsu;
1817             }
1818             else {
1819               keyIndex_delBP(cu->editnurb, bp);
1820             }
1821             bp += nu->pntsu;
1822           }
1823           nu->pntsv = newv;
1824           MEM_freeN(nu->bp);
1825           nu->bp = newbp;
1826           BKE_nurb_order_clamp_v(nu);
1827
1828           BKE_nurb_knot_calc_v(nu);
1829         }
1830       }
1831       else if (isNurbselV(nu, &newu, SELECT)) {
1832         /* V direction selected */
1833         newu = nu->pntsu - newu;
1834         if (newu != nu->pntsu) {
1835           /* delete */
1836           bp = nu->bp;
1837           bpn = newbp = (BPoint *)MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
1838           for (b = 0; b < nu->pntsv; b++) {
1839             for (a = 0; a < nu->pntsu; a++, bp++) {
1840               if ((bp->f1 & SELECT) == 0) {
1841                 *bpn = *bp;
1842                 keyIndex_updateBP(cu->editnurb, bp, bpn, 1);
1843                 bpn++;
1844               }
1845               else {
1846                 keyIndex_delBP(cu->editnurb, bp);
1847               }
1848             }
1849           }
1850           MEM_freeN(nu->bp);
1851           nu->bp = newbp;
1852           if (newu == 1 && nu->pntsv > 1) { /* make a U spline */
1853             nu->pntsu = nu->pntsv;
1854             nu->pntsv = 1;
1855             SWAP(short, nu->orderu, nu->orderv);
1856             BKE_nurb_order_clamp_u(nu);
1857             if (nu->knotsv) {
1858               MEM_freeN(nu->knotsv);
1859             }
1860             nu->knotsv = NULL;
1861           }
1862           else {
1863             nu->pntsu = newu;
1864             BKE_nurb_order_clamp_u(nu);
1865           }
1866           BKE_nurb_knot_calc_u(nu);
1867         }
1868       }
1869     }
1870   }
1871 }
1872
1873 static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
1874 {
1875   Curve *cu = obedit->data;
1876   EditNurb *editnurb = cu->editnurb;
1877   ListBase *nubase = &editnurb->nurbs;
1878   BezTriple *bezt, *bezt1;
1879   BPoint *bp, *bp1;
1880   int a, type, nuindex = 0;
1881
1882   /* first loop, can we remove entire pieces? */
1883   LISTBASE_FOREACH_MUTABLE (Nurb *, nu, nubase) {
1884     if (nu->type == CU_BEZIER) {
1885       bezt = nu->bezt;
1886       a = nu->pntsu;
1887       if (a) {
1888         while (a) {
1889           if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
1890             /* pass */
1891           }
1892           else {
1893             break;
1894           }
1895           a--;
1896           bezt++;
1897         }
1898         if (a == 0) {
1899           if (cu->actnu == nuindex) {
1900             cu->actnu = CU_ACT_NONE;
1901           }
1902
1903           BLI_remlink(nubase, nu);
1904           keyIndex_delNurb(editnurb, nu);
1905           BKE_nurb_free(nu);
1906           nu = NULL;
1907         }
1908       }
1909     }
1910     else {
1911       bp = nu->bp;
1912       a = nu->pntsu * nu->pntsv;
1913       if (a) {
1914         while (a) {
1915           if (bp->f1 & SELECT) {
1916             /* pass */
1917           }
1918           else {
1919             break;
1920           }
1921           a--;
1922           bp++;
1923         }
1924         if (a == 0) {
1925           if (cu->actnu == nuindex) {
1926             cu->actnu = CU_ACT_NONE;
1927           }
1928
1929           BLI_remlink(nubase, nu);
1930           keyIndex_delNurb(editnurb, nu);
1931           BKE_nurb_free(nu);
1932           nu = NULL;
1933         }
1934       }
1935     }
1936
1937     /* Never allow the order to exceed the number of points
1938      * - note, this is ok but changes unselected nurbs, disable for now */
1939 #if 0
1940     if ((nu != NULL) && (nu->type == CU_NURBS)) {
1941       clamp_nurb_order_u(nu);
1942     }
1943 #endif
1944     nuindex++;
1945   }
1946   /* 2nd loop, delete small pieces: just for curves */
1947   LISTBASE_FOREACH_MUTABLE (Nurb *, nu, nubase) {
1948     type = 0;
1949     if (nu->type == CU_BEZIER) {
1950       bezt = nu->bezt;
1951       for (a = 0; a < nu->pntsu; a++) {
1952         if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
1953           memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple));
1954           keyIndex_delBezt(editnurb, bezt);
1955           keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1);
1956           nu->pntsu--;
1957           a--;
1958           type = 1;
1959         }
1960         else {
1961           bezt++;
1962         }
1963       }
1964       if (type) {
1965         bezt1 = (BezTriple *)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb");
1966         memcpy(bezt1, nu->bezt, (nu->pntsu) * sizeof(BezTriple));
1967         keyIndex_updateBezt(editnurb, nu->bezt, bezt1, nu->pntsu);
1968         MEM_freeN(nu->bezt);
1969         nu->bezt = bezt1;
1970         BKE_nurb_handles_calc(nu);
1971       }
1972     }
1973     else if (nu->pntsv == 1) {
1974       bp = nu->bp;
1975
1976       for (a = 0; a < nu->pntsu; a++) {
1977         if (bp->f1 & SELECT) {
1978           memmove(bp, bp + 1, (nu->pntsu - a - 1) * sizeof(BPoint));
1979           keyIndex_delBP(editnurb, bp);
1980           keyIndex_updateBP(editnurb, bp + 1, bp, nu->pntsu - a - 1);
1981           nu->pntsu--;
1982           a--;
1983           type = 1;
1984         }
1985         else {
1986           bp++;
1987         }
1988       }
1989       if (type) {
1990         bp1 = (BPoint *)MEM_mallocN(nu->pntsu * sizeof(BPoint), "delNurb2");
1991         memcpy(bp1, nu->bp, (nu->pntsu) * sizeof(BPoint));
1992         keyIndex_updateBP(editnurb, nu->bp, bp1, nu->pntsu);
1993         MEM_freeN(nu->bp);
1994         nu->bp = bp1;
1995
1996         /* Never allow the order to exceed the number of points
1997          * - note, this is ok but changes unselected nurbs, disable for now */
1998 #if 0
1999         if (nu->type == CU_NURBS) {
2000           clamp_nurb_order_u(nu);
2001         }
2002 #endif
2003       }
2004       BKE_nurb_order_clamp_u(nu);
2005       BKE_nurb_knot_calc_u(nu);
2006     }
2007   }
2008 }
2009
2010 /* only for OB_SURF */
2011 bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
2012 {
2013   BPoint *bp, *bpn, *newbp;
2014   int a, u, v, len;
2015   bool ok = false;
2016
2017   LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
2018     if (nu->pntsv == 1) {
2019       bp = nu->bp;
2020       a = nu->pntsu;
2021       while (a) {
2022         if (bp->f1 & flag) {
2023           /* pass */
2024         }
2025         else {
2026           break;
2027         }
2028         bp++;
2029         a--;
2030       }
2031       if (a == 0) {
2032         ok = true;
2033         newbp = (BPoint *)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
2034         ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
2035         bp = newbp + nu->pntsu;
2036         ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
2037         MEM_freeN(nu->bp);
2038         nu->bp = newbp;
2039         a = nu->pntsu;
2040         while (a--) {
2041           select_bpoint(bp, SELECT, flag, HIDDEN);
2042           select_bpoint(newbp, DESELECT, flag, HIDDEN);
2043           bp++;
2044           newbp++;
2045         }
2046
2047         nu->pntsv = 2;
2048         nu->orderv = 2;
2049         BKE_nurb_knot_calc_v(nu);
2050       }
2051     }
2052     else {
2053       /* which row or column is selected */
2054
2055       if (isNurbselUV(nu, flag, &u, &v)) {
2056
2057         /* deselect all */
2058         bp = nu->bp;
2059         a = nu->pntsu * nu->pntsv;
2060         while (a--) {
2061           select_bpoint(bp, DESELECT, flag, HIDDEN);
2062           bp++;
2063         }
2064
2065         if (u == 0 || u == nu->pntsv - 1) { /* row in u-direction selected */
2066           ok = true;
2067           newbp = (BPoint *)MEM_mallocN(nu->pntsu * (nu->pntsv + 1) * sizeof(BPoint),
2068                                         "extrudeNurb1");
2069           if (u == 0) {
2070             len = nu->pntsv * nu->pntsu;
2071             ED_curve_bpcpy(editnurb, newbp + nu->pntsu, nu->bp, len);
2072             ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
2073             bp = newbp;
2074           }
2075           else {
2076             len = nu->pntsv * nu->pntsu;
2077             ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
2078             ED_curve_bpcpy(editnurb, newbp + len, &nu->bp[len - nu->pntsu], nu->pntsu);
2079             bp = newbp + len;
2080           }
2081
2082           a = nu->pntsu;
2083           while (a--) {
2084             select_bpoint(bp, SELECT, flag, HIDDEN);
2085             bp++;
2086           }
2087
2088           MEM_freeN(nu->bp);
2089           nu->bp = newbp;
2090           nu->pntsv++;
2091           BKE_nurb_knot_calc_v(nu);
2092         }
2093         else if (v == 0 || v == nu->pntsu - 1) { /* column in v-direction selected */
2094           ok = true;
2095           bpn = newbp = (BPoint *)MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint),
2096                                               "extrudeNurb1");
2097           bp = nu->bp;
2098
2099           for (a = 0; a < nu->pntsv; a++) {
2100             if (v == 0) {
2101               *bpn = *bp;
2102               bpn->f1 |= flag;
2103               bpn++;
2104             }
2105             ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
2106             bp += nu->pntsu;
2107             bpn += nu->pntsu;
2108             if (v == nu->pntsu - 1) {
2109               *bpn = *(bp - 1);
2110               bpn->f1 |= flag;
2111               bpn++;
2112             }
2113           }
2114
2115           MEM_freeN(nu->bp);
2116           nu->bp = newbp;
2117           nu->pntsu++;
2118           BKE_nurb_knot_calc_u(nu);
2119         }
2120       }
2121     }
2122   }
2123
2124   return ok;
2125 }
2126
2127 static void calc_duplicate_actnurb(const ListBase *editnurb, const ListBase *newnurb, Curve *cu)
2128 {
2129   cu->actnu = BLI_listbase_count(editnurb) + BLI_listbase_count(newnurb);
2130 }
2131
2132 static bool calc_duplicate_actvert(
2133     const ListBase *editnurb, const ListBase *newnurb, Curve *cu, int start, int end, int vert)
2134 {
2135   if (cu->actvert == -1) {
2136     calc_duplicate_actnurb(editnurb, newnurb, cu);
2137     return true;
2138   }
2139
2140   if ((start <= cu->actvert) && (end > cu->actvert)) {
2141     calc_duplicate_actnurb(editnurb, newnurb, cu);
2142     cu->actvert = vert;
2143     return true;
2144   }
2145   return false;
2146 }
2147
2148 static void adduplicateflagNurb(
2149     Object *obedit, View3D *v3d, ListBase *newnurb, const uint8_t flag, const bool split)
2150 {
2151   ListBase *editnurb = object_editcurve_get(obedit);
2152   Nurb *newnu;
2153   BezTriple *bezt, *bezt1;
2154   BPoint *bp, *bp1, *bp2, *bp3;
2155   Curve *cu = (Curve *)obedit->data;
2156   int a, b, c, starta, enda, diffa, cyclicu, cyclicv, newu, newv;
2157   char *usel;
2158
2159   int i = 0;
2160   LISTBASE_FOREACH_INDEX (Nurb *, nu, editnurb, i) {
2161     cyclicu = cyclicv = 0;
2162     if (nu->type == CU_BEZIER) {
2163       for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
2164         enda = -1;
2165         starta = a;
2166         while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) {
2167           if (!split) {
2168             select_beztriple(bezt, DESELECT, flag, HIDDEN);
2169           }
2170           enda = a;
2171           if (a >= nu->pntsu - 1) {
2172             break;
2173           }
2174           a++;
2175           bezt++;
2176         }
2177         if (enda >= starta) {
2178           newu = diffa = enda - starta + 1; /* set newu and diffa, may use both */
2179
2180           if (starta == 0 && newu != nu->pntsu && (nu->flagu & CU_NURB_CYCLIC)) {
2181             cyclicu = newu;
2182           }
2183           else {
2184             if (enda == nu->pntsu - 1) {
2185               newu += cyclicu;
2186             }
2187             if (i == cu->actnu) {
2188               calc_duplicate_actvert(
2189                   editnurb, newnurb, cu, starta, starta + diffa, cu->actvert - starta);
2190             }
2191
2192             newnu = BKE_nurb_copy(nu, newu, 1);
2193             memcpy(newnu->bezt, &nu->bezt[starta], diffa * sizeof(BezTriple));
2194             if (newu != diffa) {
2195               memcpy(&newnu->bezt[diffa], nu->bezt, cyclicu * sizeof(BezTriple));
2196               if (i == cu->actnu) {
2197                 calc_duplicate_actvert(
2198                     editnurb, newnurb, cu, 0, cyclicu, newu - cyclicu + cu->actvert);
2199               }
2200               cyclicu = 0;
2201             }
2202
2203             if (newu != nu->pntsu) {
2204               newnu->flagu &= ~CU_NURB_CYCLIC;
2205             }
2206
2207             for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
2208               select_beztriple(bezt1, SELECT, flag, HIDDEN);
2209             }
2210
2211             BLI_addtail(newnurb, newnu);
2212           }
2213         }
2214       }
2215
2216       if (cyclicu != 0) {
2217         if (i == cu->actnu) {
2218           calc_duplicate_actvert(editnurb, newnurb, cu, 0, cyclicu, cu->actvert);
2219         }
2220
2221         newnu = BKE_nurb_copy(nu, cyclicu, 1);
2222         memcpy(newnu->bezt, nu->bezt, cyclicu * sizeof(BezTriple));
2223         newnu->flagu &= ~CU_NURB_CYCLIC;
2224
2225         for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
2226           select_beztriple(bezt1, SELECT, flag, HIDDEN);
2227         }
2228
2229         BLI_addtail(newnurb, newnu);
2230       }
2231     }
2232     else if (nu->pntsv == 1) { /* because UV Nurb has a different method for dupli */
2233       for (a = 0, bp = nu->bp; a < nu->pntsu; a++, bp++) {
2234         enda = -1;
2235         starta = a;
2236         while (bp->f1 & flag) {
2237           if (!split) {
2238             select_bpoint(bp, DESELECT, flag, HIDDEN);
2239           }
2240           enda = a;
2241           if (a >= nu->pntsu - 1) {
2242             break;
2243           }
2244           a++;
2245           bp++;
2246         }
2247         if (enda >= starta) {
2248           newu = diffa = enda - starta + 1; /* set newu and diffa, may use both */
2249
2250           if (starta == 0 && newu != nu->pntsu && (nu->flagu & CU_NURB_CYCLIC)) {
2251             cyclicu = newu;
2252           }
2253           else {
2254             if (enda == nu->pntsu - 1) {
2255               newu += cyclicu;
2256             }
2257             if (i == cu->actnu) {
2258               calc_duplicate_actvert(
2259                   editnurb, newnurb, cu, starta, starta + diffa, cu->actvert - starta);
2260             }
2261
2262             newnu = BKE_nurb_copy(nu, newu, 1);
2263             memcpy(newnu->bp, &nu->bp[starta], diffa * sizeof(BPoint));
2264             if (newu != diffa) {
2265               memcpy(&newnu->bp[diffa], nu->bp, cyclicu * sizeof(BPoint));
2266               if (i == cu->actnu) {
2267                 calc_duplicate_actvert(
2268                     editnurb, newnurb, cu, 0, cyclicu, newu - cyclicu + cu->actvert);
2269               }
2270               cyclicu = 0;
2271             }
2272
2273             if (newu != nu->pntsu) {
2274               newnu->flagu &= ~CU_NURB_CYCLIC;
2275             }
2276
2277             for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
2278               select_bpoint(bp1, SELECT, flag, HIDDEN);
2279             }
2280
2281             BLI_addtail(newnurb, newnu);
2282           }
2283         }
2284       }
2285
2286       if (cyclicu != 0) {
2287         if (i == cu->actnu) {
2288           calc_duplicate_actvert(editnurb, newnurb, cu, 0, cyclicu, cu->actvert);
2289         }
2290
2291         newnu = BKE_nurb_copy(nu, cyclicu, 1);
2292         memcpy(newnu->bp, nu->bp, cyclicu * sizeof(BPoint));
2293         newnu->flagu &= ~CU_NURB_CYCLIC;
2294
2295         for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
2296           select_bpoint(bp1, SELECT, flag, HIDDEN);
2297         }
2298
2299         BLI_addtail(newnurb, newnu);
2300       }
2301     }
2302     else {
2303       if (ED_curve_nurb_select_check(v3d, nu)) {
2304         /* A rectangular area in nurb has to be selected and if splitting
2305          * must be in U or V direction. */
2306         usel = MEM_callocN(nu->pntsu, "adduplicateN3");
2307         bp = nu->bp;
2308         for (a = 0; a < nu->pntsv; a++) {
2309           for (b = 0; b < nu->pntsu; b++, bp++) {
2310             if (bp->f1 & flag) {
2311               usel[b]++;
2312             }
2313           }
2314         }
2315         newu = 0;
2316         newv = 0;
2317         for (a = 0; a < nu->pntsu; a++) {
2318           if (usel[a]) {
2319             if (newv == 0 || usel[a] == newv) {
2320               newv = usel[a];
2321               newu++;
2322             }
2323             else {
2324               newv = 0;
2325               break;
2326             }
2327           }
2328         }
2329         MEM_freeN(usel);
2330
2331         if ((newu == 0 || newv == 0) ||
2332             (split && !isNurbselU(nu, &newv, SELECT) && !isNurbselV(nu, &newu, SELECT))) {
2333           if (G.debug & G_DEBUG) {
2334             printf("Can't duplicate Nurb\n");
2335           }
2336         }
2337         else {
2338           for (a = 0, bp1 = nu->bp; a < nu->pntsu * nu->pntsv; a++, bp1++) {
2339             newv = newu = 0;
2340
2341             if ((bp1->f1 & flag) && !(bp1->f1 & SURF_SEEN)) {
2342               /* point selected, now loop over points in U and V directions */
2343               for (b = a % nu->pntsu, bp2 = bp1; b < nu->pntsu; b++, bp2++) {
2344                 if (bp2->f1 & flag) {
2345                   newu++;
2346                   for (c = a / nu->pntsu, bp3 = bp2; c < nu->pntsv; c++, bp3 += nu->pntsu) {
2347                     if (bp3->f1 & flag) {
2348                       /* flag as seen so skipped on future iterations */
2349                       bp3->f1 |= SURF_SEEN;
2350                       if (newu == 1) {
2351                         newv++;
2352                       }
2353                     }
2354                     else {
2355                       break;
2356                     }
2357                   }
2358                 }
2359                 else {
2360                   break;
2361                 }
2362               }
2363             }
2364
2365             if ((newu + newv) > 2) {
2366               /* ignore single points */
2367               if (a == 0) {
2368                 /* check if need to save cyclic selection and continue if so */
2369                 if (newu == nu->pntsu && (nu->flagv & CU_NURB_CYCLIC)) {
2370                   cyclicv = newv;
2371                 }
2372                 if (newv == nu->pntsv && (nu->flagu & CU_NURB_CYCLIC)) {
2373                   cyclicu = newu;
2374                 }
2375                 if (cyclicu != 0 || cyclicv != 0) {
2376                   continue;
2377                 }
2378               }
2379
2380               if (a + newu == nu->pntsu && cyclicu != 0) {
2381                 /* cyclic in U direction */
2382                 newnu = BKE_nurb_copy(nu, newu + cyclicu, newv);
2383                 for (b = 0; b < newv; b++) {
2384                   memcpy(&newnu->bp[b * newnu->pntsu],
2385                          &nu->bp[b * nu->pntsu + a],
2386                          newu * sizeof(BPoint));
2387                   memcpy(&newnu->bp[b * newnu->pntsu + newu],
2388                          &nu->bp[b * nu->pntsu],
2389                          cyclicu * sizeof(BPoint));
2390                 }
2391
2392                 if (cu->actnu == i) {
2393                   if (cu->actvert == -1) {
2394                     calc_duplicate_actnurb(editnurb, newnurb, cu);
2395                   }
2396                   else {
2397                     for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2398                       starta = b * nu->pntsu + a;
2399                       if (calc_duplicate_actvert(editnurb,
2400                                                  newnurb,
2401                                                  cu,
2402                                                  cu->actvert,
2403                                                  starta,
2404                                                  cu->actvert % nu->pntsu + newu +
2405                                                      b * newnu->pntsu)) {
2406                         /* actvert in cyclicu selection */
2407                         break;
2408                       }
2409                       if (calc_duplicate_actvert(editnurb,
2410                                                  newnurb,
2411                                                  cu,
2412                                                  starta,
2413                                                  starta + newu,
2414                                                  cu->actvert - starta + b * newnu->pntsu)) {
2415                         /* actvert in 'current' iteration selection */
2416                         break;
2417                       }
2418                     }
2419                   }
2420                 }
2421                 cyclicu = cyclicv = 0;
2422               }
2423               else if ((a / nu->pntsu) + newv == nu->pntsv && cyclicv != 0) {
2424                 /* cyclic in V direction */
2425                 newnu = BKE_nurb_copy(nu, newu, newv + cyclicv);
2426                 memcpy(newnu->bp, &nu->bp[a], newu * newv * sizeof(BPoint));
2427                 memcpy(&newnu->bp[newu * newv], nu->bp, newu * cyclicv * sizeof(BPoint));
2428
2429                 /* check for actvert in cylicv selection */
2430                 if (cu->actnu == i) {
2431                   calc_duplicate_actvert(
2432                       editnurb, newnurb, cu, cu->actvert, a, (newu * newv) + cu->actvert);
2433                 }
2434                 cyclicu = cyclicv = 0;
2435               }
2436               else {
2437                 newnu = BKE_nurb_copy(nu, newu, newv);
2438                 for (b = 0; b < newv; b++) {
2439                   memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint));
2440                 }
2441               }
2442
2443               /* general case if not handled by cyclicu or cyclicv */
2444               if (cu->actnu == i) {
2445                 if (cu->actvert == -1) {
2446                   calc_duplicate_actnurb(editnurb, newnurb, cu);
2447                 }
2448                 else {
2449                   for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2450                     starta = b * nu->pntsu + a;
2451                     if (calc_duplicate_actvert(editnurb,
2452                                                newnurb,
2453                                                cu,
2454                                                starta,
2455                                                starta + newu,
2456                                                cu->actvert - (a / nu->pntsu * nu->pntsu + diffa +
2457                                                               (starta % nu->pntsu)))) {
2458                       break;
2459                     }
2460                   }
2461                 }
2462               }
2463               BLI_addtail(newnurb, newnu);
2464
2465               if (newu != nu->pntsu) {
2466                 newnu->flagu &= ~CU_NURB_CYCLIC;
2467               }
2468               if (newv != nu->pntsv) {
2469                 newnu->flagv &= ~CU_NURB_CYCLIC;
2470               }
2471             }
2472           }
2473
2474           if (cyclicu != 0 || cyclicv != 0) {
2475             /* copy start of a cyclic surface, or copying all selected points */
2476             newu = cyclicu == 0 ? nu->pntsu : cyclicu;
2477             newv = cyclicv == 0 ? nu->pntsv : cyclicv;
2478
2479             newnu = BKE_nurb_copy(nu, newu, newv);
2480             for (b = 0; b < newv; b++) {
2481               memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu], newu * sizeof(BPoint));
2482             }
2483
2484             /* check for actvert in the unused cyclicuv selection */
2485             if (cu->actnu == i) {
2486               if (cu->actvert == -1) {
2487                 calc_duplicate_actnurb(editnurb, newnurb, cu);
2488               }
2489               else {
2490                 for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2491                   starta = b * nu->pntsu;
2492                   if (calc_duplicate_actvert(editnurb,
2493                                              newnurb,
2494                                              cu,
2495                                              starta,
2496                                              starta + newu,
2497                                              cu->actvert - (diffa + (starta % nu->pntsu)))) {
2498                     break;
2499                   }
2500                 }
2501               }
2502             }
2503             BLI_addtail(newnurb, newnu);
2504
2505             if (newu != nu->pntsu) {
2506               newnu->flagu &= ~CU_NURB_CYCLIC;
2507             }
2508             if (newv != nu->pntsv) {
2509               newnu->flagv &= ~CU_NURB_CYCLIC;
2510             }
2511           }
2512
2513           for (b = 0, bp1 = nu->bp; b < nu->pntsu * nu->pntsv; b++, bp1++) {
2514             bp1->f1 &= ~SURF_SEEN;
2515             if (!split) {
2516               select_bpoint(bp1, DESELECT, flag, HIDDEN);
2517             }
2518           }
2519         }
2520       }
2521     }
2522   }
2523
2524   if (BLI_listbase_is_empty(newnurb) == false) {
2525     LISTBASE_FOREACH (Nurb *, nu, newnurb) {
2526       if (nu->type == CU_BEZIER) {
2527         if (split) {
2528           /* recalc first and last */
2529           BKE_nurb_handle_calc_simple(nu, &nu->bezt[0]);
2530           BKE_nurb_handle_calc_simple(nu, &nu->bezt[nu->pntsu - 1]);
2531         }
2532       }
2533       else {
2534         /* knots done after duplicate as pntsu may change */
2535         BKE_nurb_order_clamp_u(nu);
2536         BKE_nurb_knot_calc_u(nu);
2537
2538         if (obedit->type == OB_SURF) {
2539           for (a = 0, bp = nu->bp; a < nu->pntsu * nu->pntsv; a++, bp++) {
2540             bp->f1 &= ~SURF_SEEN;
2541           }
2542
2543           BKE_nurb_order_clamp_v(nu);
2544           BKE_nurb_knot_calc_v(nu);
2545         }
2546       }
2547     }
2548   }
2549 }
2550
2551 /** \} */
2552
2553 /* -------------------------------------------------------------------- */
2554 /** \name Switch Direction Operator
2555  * \{ */
2556
2557 static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
2558 {
2559   Main *bmain = CTX_data_main(C);
2560   ViewLayer *view_layer = CTX_data_view_layer(C);
2561   View3D *v3d = CTX_wm_view3d(C);
2562
2563   uint objects_len;
2564   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
2565       view_layer, CTX_wm_view3d(C), &objects_len);
2566   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2567     Object *obedit = objects[ob_index];
2568     Curve *cu = obedit->data;
2569
2570     if (!ED_curve_select_check(v3d, cu->editnurb)) {
2571       continue;
2572     }
2573
2574     EditNurb *editnurb = cu->editnurb;
2575
2576     int i = 0;
2577     LISTBASE_FOREACH_INDEX (Nurb *, nu, &editnurb->nurbs, i) {
2578       if (ED_curve_nurb_select_check(v3d, nu)) {
2579         BKE_nurb_direction_switch(nu);
2580         keyData_switchDirectionNurb(cu, nu);
2581         if ((i == cu->actnu) && (cu->actvert != CU_ACT_NONE)) {
2582           cu->actvert = (nu->pntsu - 1) - cu->actvert;
2583         }
2584       }
2585     }
2586
2587     if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
2588       WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
2589     }
2590
2591     DEG_id_tag_update(obedit->data, 0);
2592     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2593   }
2594   MEM_freeN(objects);
2595   return OPERATOR_FINISHED;
2596 }
2597
2598 void CURVE_OT_switch_direction(wmOperatorType *ot)
2599 {
2600   /* identifiers */
2601   ot->name = "Switch Direction";
2602   ot->description = "Switch direction of selected splines";
2603   ot->idname = "CURVE_OT_switch_direction";
2604
2605   /* api callbacks */
2606   ot->exec = switch_direction_exec;
2607   ot->poll = ED_operator_editsurfcurve;
2608
2609   /* flags */
2610   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2611 }
2612
2613 /** \} */
2614
2615 /* -------------------------------------------------------------------- */
2616 /** \name Set Weight Operator
2617  * \{ */
2618
2619 static int set_goal_weight_exec(bContext *C, wmOperator *op)
2620 {
2621   ViewLayer *view_layer = CTX_data_view_layer(C);
2622   uint objects_len;
2623   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
2624       view_layer, CTX_wm_view3d(C), &objects_len);
2625
2626   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2627     Object *obedit = objects[ob_index];
2628     ListBase *editnurb = object_editcurve_get(obedit);
2629     BezTriple *bezt;
2630     BPoint *bp;
2631     float weight = RNA_float_get(op->ptr, "weight");
2632     int a;
2633
2634     LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2635       if (nu->bezt) {
2636         for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2637           if (bezt->f2 & SELECT) {
2638             bezt->weight = weight;
2639           }
2640         }
2641       }
2642       else if (nu->bp) {
2643         for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2644           if (bp->f1 & SELECT) {
2645             bp->weight = weight;
2646           }
2647         }
2648       }
2649     }
2650
2651     DEG_id_tag_update(obedit->data, 0);
2652     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2653   }
2654
2655   MEM_freeN(objects);
2656
2657   return OPERATOR_FINISHED;
2658 }
2659
2660 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
2661 {
2662   /* identifiers */
2663   ot->name = "Set Goal Weight";
2664   ot->description = "Set softbody goal weight for selected points";
2665   ot->idname = "CURVE_OT_spline_weight_set";
2666
2667   /* api callbacks */
2668   ot->exec = set_goal_weight_exec;
2669   ot->invoke = WM_operator_props_popup;
2670   ot->poll = ED_operator_editsurfcurve;
2671
2672   /* flags */
2673   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2674
2675   /* properties */
2676   RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
2677 }
2678
2679 /** \} */
2680
2681 /* -------------------------------------------------------------------- */
2682 /** \name Set Radius Operator
2683  * \{ */
2684
2685 static int set_radius_exec(bContext *C, wmOperator *op)
2686 {
2687   ViewLayer *view_layer = CTX_data_view_layer(C);
2688   uint objects_len;
2689   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
2690       view_layer, CTX_wm_view3d(C), &objects_len);
2691
2692   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2693     Object *obedit = objects[ob_index];
2694     ListBase *editnurb = object_editcurve_get(obedit);
2695     BezTriple *bezt;
2696     BPoint *bp;
2697     float radius = RNA_float_get(op->ptr, "radius");
2698     int a;
2699
2700     LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2701       if (nu->bezt) {
2702         for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2703           if (bezt->f2 & SELECT) {
2704             bezt->radius = radius;
2705           }
2706         }
2707       }
2708       else if (nu->bp) {
2709         for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2710           if (bp->f1 & SELECT) {
2711             bp->radius = radius;
2712           }
2713         }
2714       }
2715     }
2716
2717     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2718     DEG_id_tag_update(obedit->data, 0);
2719   }
2720
2721   MEM_freeN(objects);
2722
2723   return OPERATOR_FINISHED;
2724 }
2725
2726 void CURVE_OT_radius_set(wmOperatorType *ot)
2727 {
2728   /* identifiers */
2729   ot->name = "Set Curve Radius";
2730   ot->description = "Set per-point radius which is used for bevel tapering";
2731   ot->idname = "CURVE_OT_radius_set";
2732
2733   /* api callbacks */
2734   ot->exec = set_radius_exec;
2735   ot->invoke = WM_operator_props_popup;
2736   ot->poll = ED_operator_editsurfcurve;
2737
2738   /* flags */
2739   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2740
2741   /* properties */
2742   RNA_def_float(
2743       ot->srna, "radius", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.0001f, 10.0f);
2744 }
2745
2746 /** \} */
2747
2748 /* -------------------------------------------------------------------- */
2749 /** \name Smooth Vertices Operator
2750  * \{ */
2751
2752 static void smooth_single_bezt(BezTriple *bezt,
2753                                const BezTriple *bezt_orig_prev,
2754                                const BezTriple *bezt_orig_next,
2755                                float factor)
2756 {
2757   BLI_assert(IN_RANGE_INCL(factor, 0.0f, 1.0f));
2758
2759   for (int i = 0; i < 3; i++) {
2760     /* get single dimension pos of the mid handle */
2761     float val_old = bezt->vec[1][i];
2762
2763     /* get the weights of the previous/next mid handles and calc offset */
2764     float val_new = (bezt_orig_prev->vec[1][i] * 0.5f) + (bezt_orig_next->vec[1][i] * 0.5f);
2765     float offset = (val_old * (1.0f - factor)) + (val_new * factor) - val_old;
2766
2767     /* offset midpoint and 2 handles */
2768     bezt->vec[1][i] += offset;
2769     bezt->vec[0][i] += offset;
2770     bezt->vec[2][i] += offset;
2771   }
2772 }
2773
2774 /**
2775  * Same as #smooth_single_bezt(), keep in sync.
2776  */
2777 static void smooth_single_bp(BPoint *bp,
2778                              const BPoint *bp_orig_prev,
2779                              const BPoint *bp_orig_next,
2780                              float factor)
2781 {
2782   BLI_assert(IN_RANGE_INCL(factor, 0.0f, 1.0f));
2783
2784   for (int i = 0; i < 3; i++) {
2785     float val_old, val_new, offset;
2786
2787     val_old = bp->vec[i];
2788     val_new = (bp_orig_prev->vec[i] * 0.5f) + (bp_orig_next->vec[i] * 0.5f);
2789     offset = (val_old * (1.0f - factor)) + (val_new * factor) - val_old;
2790
2791     bp->vec[i] += offset;
2792   }
2793 }
2794
2795 static int smooth_exec(bContext *C, wmOperator *UNUSED(op))
2796 {
2797   const float factor = 1.0f / 6.0f;
2798   ViewLayer *view_layer = CTX_data_view_layer(C);
2799   uint objects_len;
2800   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
2801       view_layer, CTX_wm_view3d(C), &objects_len);
2802
2803   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2804     Object *obedit = objects[ob_index];
2805     ListBase *editnurb = object_editcurve_get(obedit);
2806
2807     int a, a_end;
2808     bool changed = false;
2809
2810     LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2811       if (nu->bezt) {
2812         /* duplicate the curve to use in weight calculation */
2813         const BezTriple *bezt_orig = MEM_dupallocN(nu->bezt);
2814         BezTriple *bezt;
2815         changed = false;
2816
2817         /* check whether its cyclic or not, and set initial & final conditions */
2818         if (nu->flagu & CU_NURB_CYCLIC) {
2819           a = 0;
2820           a_end = nu->pntsu;
2821         }
2822         else {
2823           a = 1;
2824           a_end = nu->pntsu - 1;
2825         }
2826
2827         /* for all the curve points */
2828         for (; a < a_end; a++) {
2829           /* respect selection */
2830           bezt = &nu->bezt[a];
2831           if (bezt->f2 & SELECT) {
2832             const BezTriple *bezt_orig_prev, *bezt_orig_next;
2833
2834             bezt_orig_prev = &bezt_orig[mod_i(a - 1, nu->pntsu)];
2835             bezt_orig_next = &bezt_orig[mod_i(a + 1, nu->pntsu)];
2836
2837             smooth_single_bezt(bezt, bezt_orig_prev, bezt_orig_next, factor);
2838
2839             changed = true;
2840           }
2841         }
2842         MEM_freeN((void *)bezt_orig);
2843         if (changed) {
2844           BKE_nurb_handles_calc(nu);
2845         }
2846       }
2847       else if (nu->bp) {
2848         /* Same as above, keep these the same! */
2849         const BPoint *bp_orig = MEM_dupallocN(nu->bp);
2850         BPoint *bp;
2851
2852         if (nu->flagu & CU_NURB_CYCLIC) {
2853           a = 0;
2854           a_end = nu->pntsu;
2855         }
2856         else {
2857           a = 1;
2858           a_end = nu->pntsu - 1;
2859         }
2860
2861         for (; a < a_end; a++) {
2862           bp = &nu->bp[a];
2863           if (bp->f1 & SELECT) {
2864             const BPoint *bp_orig_prev, *bp_orig_next;
2865
2866             bp_orig_prev = &bp_orig[mod_i(a - 1, nu->pntsu)];
2867             bp_orig_next = &bp_orig[mod_i(a + 1, nu->pntsu)];
2868
2869             smooth_single_bp(bp, bp_orig_prev, bp_orig_next, factor);
2870           }
2871         }
2872         MEM_freeN((void *)bp_orig);
2873       }
2874     }
2875
2876     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2877     DEG_id_tag_update(obedit->data, 0);
2878   }
2879
2880   MEM_freeN(objects);
2881
2882   return OPERATOR_FINISHED;
2883 }
2884
2885 void CURVE_OT_smooth(wmOperatorType *ot)
2886 {
2887   /* identifiers */
2888   ot->name = "Smooth";
2889   ot->description = "Flatten angles of selected points";
2890   ot->idname = "CURVE_OT_smooth";
2891
2892   /* api callbacks */
2893   ot->exec = smooth_exec;
2894   ot->poll = ED_operator_editsurfcurve;
2895
2896   /* flags */
2897   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2898 }
2899
2900 /** \} */
2901
2902 /* -------------------------------------------------------------------- */
2903 /** \name Smooth Operator (Radius/Weight/Tilt) Utilities
2904  *
2905  * To do:
2906  * - Make smoothing distance based.
2907  * - Support cyclic curves.
2908  * \{ */
2909
2910 static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, const int bp_offset)
2911 {
2912   BezTriple *bezt;
2913   BPoint *bp;
2914   int a;
2915
2916   /* use for smoothing */
2917   int last_sel;
2918   int start_sel, end_sel; /* selection indices, inclusive */
2919   float start_rad, end_rad, fac, range;
2920
2921   LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2922     if (nu->bezt) {
2923 #define BEZT_VALUE(bezt) (*((float *)((char *)(bezt) + bezt_offsetof)))
2924
2925       for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
2926         /* loop over selection segments of a curve, smooth each */
2927
2928         /* Start BezTriple code,
2929          * this is duplicated below for points, make sure these functions stay in sync */
2930         start_sel = -1;
2931         for (bezt = &nu->bezt[last_sel], a = last_sel; a < nu->pntsu; a++, bezt++) {
2932           if (bezt->f2 & SELECT) {
2933             start_sel = a;
2934             break;
2935           }
2936         }
2937         /* in case there are no other selected verts */
2938         end_sel = start_sel;
2939         for (bezt = &nu->bezt[start_sel + 1], a = start_sel + 1; a < nu->pntsu; a++, bezt++) {
2940           if ((bezt->f2 & SELECT) == 0) {
2941             break;
2942           }
2943           end_sel = a;
2944         }
2945
2946         if (start_sel == -1) {
2947           last_sel = nu->pntsu; /* next... */
2948         }
2949         else {
2950           last_sel = end_sel; /* before we modify it */
2951
2952           /* now blend between start and end sel */
2953           start_rad = end_rad = FLT_MAX;
2954
2955           if (start_sel == end_sel) {
2956             /* simple, only 1 point selected */
2957             if (start_sel > 0) {
2958               start_rad = BEZT_VALUE(&nu->bezt[start_sel - 1]);
2959             }
2960             if (end_sel != -1 && end_sel < nu->pntsu) {
2961               end_rad = BEZT_VALUE(&nu->bezt[start_sel + 1]);
2962             }
2963
2964             if (start_rad != FLT_MAX && end_rad >= FLT_MAX) {
2965               BEZT_VALUE(&nu->bezt[start_sel]) = (start_rad + end_rad) / 2.0f;
2966             }
2967             else if (start_rad != FLT_MAX) {
2968               BEZT_VALUE(&nu->bezt[start_sel]) = start_rad;
2969             }
2970             else if (end_rad != FLT_MAX) {
2971               BEZT_VALUE(&nu->bezt[start_sel]) = end_rad;
2972             }
2973           }
2974           else {
2975             /* if endpoints selected, then use them */
2976             if (start_sel == 0) {
2977               start_rad = BEZT_VALUE(&nu->bezt[start_sel]);
2978               start_sel++; /* we don't want to edit the selected endpoint */
2979             }
2980             else {
2981               start_rad = BEZT_VALUE(&nu->bezt[start_sel - 1]);
2982             }
2983             if (end_sel == nu->pntsu - 1) {
2984               end_rad = BEZT_VALUE(&nu->bezt[end_sel]);
2985               end_sel--; /* we don't want to edit the selected endpoint */
2986             }
2987             else {
2988               end_rad = BEZT_VALUE(&nu->bezt[end_sel + 1]);
2989             }
2990
2991             /* Now Blend between the points */
2992             range = (float)(end_sel - start_sel) + 2.0f;
2993             for (bezt = &nu->bezt[start_sel], a = start_sel; a <= end_sel; a++, bezt++) {
2994               fac = (float)(1 + a - start_sel) / range;
2995               BEZT_VALUE(bezt) = start_rad * (1.0f - fac) + end_rad * fac;
2996             }
2997           }
2998         }
2999       }
3000 #undef BEZT_VALUE
3001     }
3002     else if (nu->bp) {
3003 #define BP_VALUE(bp) (*((float *)((char *)(bp) + bp_offset)))
3004
3005       /* Same as above, keep these the same! */
3006       for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
3007         /* loop over selection segments of a curve, smooth each */
3008
3009         /* Start BezTriple code,
3010          * this is duplicated below for points, make sure these functions stay in sync */
3011         start_sel = -1;
3012         for (bp = &nu->bp[last_sel], a = last_sel; a < nu->pntsu; a++, bp++) {
3013           if (bp->f1 & SELECT) {
3014             start_sel = a;
3015             break;
3016           }
3017         }
3018         /* in case there are no other selected verts */
3019         end_sel = start_sel;
3020         for (bp = &nu->bp[start_sel + 1], a = start_sel + 1; a < nu->pntsu; a++, bp++) {
3021           if ((bp->f1 & SELECT) == 0) {
3022             break;
3023           }
3024           end_sel = a;
3025         }
3026
3027         if (start_sel == -1) {
3028           last_sel = nu->pntsu; /* next... */
3029         }
3030         else {
3031           last_sel = end_sel; /* before we modify it */
3032
3033           /* now blend between start and end sel */
3034           start_rad = end_rad = FLT_MAX;
3035
3036           if (start_sel == end_sel) {
3037             /* simple, only 1 point selected */
3038             if (start_sel > 0) {
3039               start_rad = BP_VALUE(&nu->bp[start_sel - 1]);
3040             }
3041             if (end_sel != -1 && end_sel < nu->pntsu) {
3042               end_rad = BP_VALUE(&nu->bp[start_sel + 1]);
3043             }
3044
3045             if (start_rad != FLT_MAX && end_rad != FLT_MAX) {
3046               BP_VALUE(&nu->bp[start_sel]) = (start_rad + end_rad) / 2;
3047             }
3048             else if (start_rad != FLT_MAX) {
3049               BP_VALUE(&nu->bp[start_sel]) = start_rad;
3050             }
3051             else if (end_rad != FLT_MAX) {
3052               BP_VALUE(&nu->bp[start_sel]) = end_rad;
3053             }
3054           }
3055           else {
3056             /* if endpoints selected, then use them */
3057             if (start_sel == 0) {
3058               start_rad = BP_VALUE(&nu->bp[start_sel]);
3059               start_sel++; /* we don't want to edit the selected endpoint */
3060             }
3061             else {
3062               start_rad = BP_VALUE(&nu->bp[start_sel - 1]);
3063             }
3064             if (end_sel == nu->pntsu - 1) {
3065               end_rad = BP_VALUE(&nu->bp[end_sel]);
3066               end_sel--; /* we don't want to edit the selected endpoint */
3067             }
3068             else {
3069               end_rad = BP_VALUE(&nu->bp[end_sel + 1]);
3070             }
3071
3072             /* Now Blend between the points */
3073             range = (float)(end_sel - start_sel) + 2.0f;
3074             for (bp = &nu->bp[start_sel], a = start_sel; a <= end_sel; a++, bp++) {
3075               fac = (float)(1 + a - start_sel) / range;
3076               BP_VALUE(bp) = start_rad * (1.0f - fac) + end_rad * fac;
3077             }
3078           }
3079         }
3080       }
3081 #undef BP_VALUE
3082     }
3083   }
3084 }
3085
3086 /** \} */
3087
3088 /* -------------------------------------------------------------------- */
3089 /** \name Smooth Weight Operator
3090  * \{ */
3091
3092 static int curve_smooth_weight_exec(bContext *C, wmOperator *UNUSED(op))
3093 {
3094   ViewLayer *view_layer = CTX_data_view_layer(C);
3095   uint objects_len;
3096   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3097       view_layer, CTX_wm_view3d(C), &objects_len);
3098
3099   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3100     Object *obedit = objects[ob_index];
3101     ListBase *editnurb = object_editcurve_get(obedit);
3102
3103     curve_smooth_value(editnurb, offsetof(BezTriple, weight), offsetof(BPoint, weight));
3104
3105     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
3106     DEG_id_tag_update(obedit->data, 0);
3107   }
3108
3109   MEM_freeN(objects);
3110
3111   return OPERATOR_FINISHED;
3112 }
3113
3114 void CURVE_OT_smooth_weight(wmOperatorType *ot)
3115 {
3116   /* identifiers */
3117   ot->name = "Smooth Curve Weight";
3118   ot->description = "Interpolate weight of selected points";
3119   ot->idname = "CURVE_OT_smooth_weight";
3120
3121   /* api clastbacks */
3122   ot->exec = curve_smooth_weight_exec;
3123   ot->poll = ED_operator_editsurfcurve;
3124
3125   /* flags */
3126   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3127 }
3128
3129 /** \} */
3130
3131 /* -------------------------------------------------------------------- */
3132 /** \name Smooth Radius Operator
3133  * \{ */
3134
3135 static int curve_smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
3136 {
3137   ViewLayer *view_layer = CTX_data_view_layer(C);
3138   uint objects_len;
3139   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3140       view_layer, CTX_wm_view3d(C), &objects_len);
3141
3142   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3143     Object *obedit = objects[ob_index];
3144     ListBase *editnurb = object_editcurve_get(obedit);
3145
3146     curve_smooth_value(editnurb, offsetof(BezTriple, radius), offsetof(BPoint, radius));
3147
3148     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
3149     DEG_id_tag_update(obedit->data, 0);
3150   }
3151
3152   MEM_freeN(objects);
3153
3154   return OPERATOR_FINISHED;
3155 }
3156
3157 void CURVE_OT_smooth_radius(wmOperatorType *ot)
3158 {
3159   /* identifiers */
3160   ot->name = "Smooth Curve Radius";
3161   ot->description = "Interpolate radii of selected points";
3162   ot->idname = "CURVE_OT_smooth_radius";
3163
3164   /* api clastbacks */
3165   ot->exec = curve_smooth_radius_exec;
3166   ot->poll = ED_operator_editsurfcurve;
3167
3168   /* flags */
3169   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3170 }
3171
3172 /** \} */
3173
3174 /* -------------------------------------------------------------------- */
3175 /** \name Smooth Tilt Operator
3176  * \{ */
3177
3178 static int curve_smooth_tilt_exec(bContext *C, wmOperator *UNUSED(op))
3179 {
3180   ViewLayer *view_layer = CTX_data_view_layer(C);
3181   uint objects_len;
3182   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3183       view_layer, CTX_wm_view3d(C), &objects_len);
3184
3185   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3186     Object *obedit = objects[ob_index];
3187     ListBase *editnurb = object_editcurve_get(obedit);
3188
3189     curve_smooth_value(editnurb, offsetof(BezTriple, tilt), offsetof(BPoint, tilt));
3190
3191     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
3192     DEG_id_tag_update(obedit->data, 0);
3193   }
3194
3195   MEM_freeN(objects);
3196
3197   return OPERATOR_FINISHED;
3198 }
3199
3200 void CURVE_OT_smooth_tilt(wmOperatorType *ot)
3201 {
3202   /* identifiers */
3203   ot->name = "Smooth Curve Tilt";
3204   ot->description = "Interpolate tilt of selected points";
3205   ot->idname = "CURVE_OT_smooth_tilt";
3206
3207   /* api clastbacks */
3208   ot->exec = curve_smooth_tilt_exec;
3209   ot->poll = ED_operator_editsurfcurve;
3210
3211   /* flags */
3212   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3213 }
3214
3215 /** \} */
3216
3217 /* -------------------------------------------------------------------- */
3218 /** \name Hide Operator
3219  * \{ */
3220
3221 static int hide_exec(bContext *C, wmOperator *op)
3222 {
3223   ViewLayer *view_layer = CTX_data_view_layer(C);
3224   View3D *v3d = CTX_wm_view3d(C);
3225
3226   const bool invert = RNA_boolean_get(op->ptr, "unselected");
3227
3228   uint objects_len;
3229   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3230       view_layer, CTX_wm_view3d(C), &objects_len);
3231   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3232     Object *obedit = objects[ob_index];
3233     Curve *cu = obedit->data;
3234
3235     if (!(invert || ED_curve_select_check(v3d, cu->editnurb))) {
3236       continue;
3237     }
3238
3239     ListBase *editnurb = object_editcurve_get(obedit);
3240     BPoint *bp;
3241     BezTriple *bezt;
3242     int a, sel;
3243
3244     LISTBASE_FOREACH (Nurb *, nu, editnurb) {
3245       if (nu->type == CU_BEZIER) {
3246         bezt = nu->bezt;
3247         a = nu->pntsu;
3248         sel = 0;
3249         while (a--) {
3250           if (invert == 0 && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
3251             select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
3252             bezt->hide = 1;
3253           }
3254           else if (invert && !BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
3255             select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
3256             bezt->hide = 1;
3257           }
3258           if (bezt->hide) {
3259             sel++;
3260           }
3261           bezt++;
3262         }
3263         if (sel == nu->pntsu) {
3264           nu->hide = 1;
3265         }
3266       }
3267       else {
3268         bp = nu->bp;
3269         a = nu->pntsu * nu->pntsv;
3270         sel = 0;
3271         while (a--) {
3272           if (invert == 0 && (bp->f1 & SELECT)) {
3273             select_bpoint(bp, DESELECT, SELECT, HIDDEN);
3274             bp->hide = 1;
3275           }
3276           else if (invert && (bp->f1 & SELECT) == 0) {
3277             select_bpoint(bp, DESELECT, SELECT, HIDDEN);
3278             bp->hide = 1;
3279           }
3280           if (bp->hide) {
3281             sel++;
3282           }
3283           bp++;
3284         }
3285         if (sel == nu->pntsu * nu->pntsv) {
3286           nu->hide = 1;
3287         }
3288       }
3289     }
3290
3291     DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
3292     WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3293     BKE_curve_nurb_vert_active_validate(obedit->data);
3294   }
3295   MEM_freeN(objects);
3296   return OPERATOR_FINISHED;
3297 }
3298
3299 void CURVE_OT_hide(wmOperatorType *ot)
3300 {
3301   /* identifiers */
3302   ot->name = "Hide Selected";
3303   ot->idname = "CURVE_OT_hide";
3304   ot->description = "Hide (un)selected control points";
3305
3306   /* api callbacks */
3307   ot->exec = hide_exec;
3308   ot->poll = ED_operator_editsurfcurve;
3309
3310   /* flags */
3311   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3312
3313   /* props */
3314   RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
3315 }
3316
3317 /** \} */
3318
3319 /* -------------------------------------------------------------------- */
3320 /** \name Reveal Operator
3321  * \{ */
3322
3323 static int reveal_exec(bContext *C, wmOperator *op)
3324 {
3325   ViewLayer *view_layer = CTX_data_view_layer(C);
3326   const bool select = RNA_boolean_get(op->ptr, "select");
3327   bool changed_multi = false;
3328
3329   uint objects_len;
3330   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3331       view_layer, CTX_wm_view3d(C), &objects_len);
3332   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3333     Object *obedit = objects[ob_index];
3334     ListBase *editnurb = object_editcurve_get(obedit);
3335     BPoint *bp;
3336     BezTriple *bezt;
3337     int a;
3338     bool changed = false;
3339
3340     LISTBASE_FOREACH (Nurb *, nu, editnurb) {
3341       nu->hide = 0;
3342       if (nu->type == CU_BEZIER) {
3343         bezt = nu->bezt;
3344         a = nu->pntsu;
3345         while (a--) {
3346           if (bezt->hide) {
3347             select_beztriple(bezt, select, SELECT, HIDDEN);
3348             bezt->hide = 0;
3349             changed = true;
3350           }
3351           bezt++;
3352         }
3353       }
3354       else {
3355         bp = nu->bp;
3356         a = nu->pntsu * nu->pntsv;
3357         while (a--) {
3358           if (bp->hide) {
3359             select_bpoint(bp, select, SELECT, HIDDEN);
3360             bp->hide = 0;
3361             changed = true;
3362           }
3363           bp++;
3364         }
3365       }
3366     }
3367
3368     if (changed) {
3369       DEG_id_tag_update(obedit->data,
3370                         ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT | ID_RECALC_GEOMETRY);
3371       WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3372       changed_multi = true;
3373     }
3374   }
3375   MEM_freeN(objects);
3376   return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3377 }
3378
3379 void CURVE_OT_reveal(wmOperatorType *ot)
3380 {
3381   /* identifiers */
3382   ot->name = "Reveal Hidden";
3383   ot->idname = "CURVE_OT_reveal";
3384   ot->description = "Reveal hidden control points";
3385
3386   /* api callbacks */
3387   ot->exec = reveal_exec;
3388   ot->poll = ED_operator_editsurfcurve;
3389
3390   /* flags */
3391   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3392
3393   RNA_def_boolean(ot->srna, "select", true, "Select", "");
3394 }
3395
3396 /** \} */
3397
3398 /* -------------------------------------------------------------------- */
3399 /** \name Subdivide Operator
3400  * \{ */
3401
3402 /**
3403  * Divide the line segments associated with the currently selected
3404  * curve nodes (Bezier or NURB). If there are no valid segment
3405  * selections within the current selection, nothing happens.
3406  */
3407 static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts)
3408 {
3409   Curve *cu = obedit->data;
3410   EditNurb *editnurb = cu->editnurb;
3411   BezTriple *bezt, *beztnew, *beztn;
3412   BPoint *bp, *prevbp, *bpnew, *bpn;
3413   float vec[15];
3414   int a, b, sel, amount, *usel, *vsel;
3415   float factor;
3416
3417   // printf("*** subdivideNurb: entering subdivide\n");
3418
3419   LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
3420     amount = 0;
3421     if (nu->type == CU_BEZIER) {
3422       BezTriple *nextbezt;
3423
3424       /*
3425        * Insert a point into a 2D Bezier curve.
3426        * Endpoints are preserved. Otherwise, all selected and inserted points are
3427        * newly created. Old points are discarded.
3428        */
3429       /* count */
3430       a = nu->pntsu;
3431       bezt = nu->bezt;
3432       while (a--) {
3433         nextbezt = BKE_nurb_bezt_get_next(nu, bezt);
3434         if (nextbezt == NULL) {
3435           break;
3436         }
3437
3438         if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) &&
3439             BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nextbezt)) {
3440           amount += number_cuts;
3441         }
3442         bezt++;
3443       }
3444
3445       if (amount) {
3446         /* insert */
3447         beztnew = (BezTriple *)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
3448         beztn = beztnew;
3449         a = nu->pntsu;
3450         bezt = nu->bezt;
3451         while (a--) {
3452           memcpy(beztn, bezt, sizeof(BezTriple));
3453           keyIndex_updateBezt(editnurb, bezt, beztn, 1);
3454           beztn++;
3455
3456           nextbezt = BKE_nurb_bezt_get_next(nu, bezt);
3457           if (nextbezt == NULL) {
3458             break;
3459           }
3460
3461           if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) &&
3462               BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nextbezt)) {
3463             float prevvec[3][3];
3464
3465             memcpy(prevvec, bezt->vec, sizeof(float[9]));
3466
3467             for (int i = 0; i < number_cuts; i++) {
3468               factor = 1.0f / (number_cuts + 1 - i);
3469
3470               memcpy(beztn, nextbezt, sizeof(BezTriple));
3471
3472               /* midpoint subdividing */
3473               interp_v3_v3v3(vec, prevvec[1], prevvec[2], factor);
3474               interp_v3_v3v3(vec + 3, prevvec[2], nextbezt->vec[0], factor);
3475               interp_v3_v3v3(vec + 6, nextbezt->vec[0], nextbezt->vec[1], factor);
3476
3477               interp_v3_v3v3(vec + 9, vec, vec + 3, factor);
3478               interp_v3_v3v3(vec + 12, vec + 3, vec + 6, factor);
3479
3480               /* change handle of prev beztn */
3481               copy_v3_v3((beztn - 1)->vec[2], vec);
3482               /* new point */
3483               copy_v3_v3(beztn->vec[0], vec + 9);
3484               interp_v3_v3v3(beztn->vec[1], vec + 9, vec + 12, factor);
3485               copy_v3_v3(beztn->vec[2], vec + 12);
3486               /* handle of next bezt */
3487               if (a == 0 && i == number_cuts - 1 && (nu->flagu & CU_NURB_CYCLIC)) {
3488                 copy_v3_v3(beztnew->vec[0], vec + 6);
3489               }
3490               else {
3491                 copy_v3_v3(nextbezt->vec[0], vec + 6);
3492               }
3493
3494               beztn->radius = (bezt->radius + nextbezt->radius) / 2;
3495               beztn->weight = (bezt->weight + nextbezt->weight) / 2;
3496
3497               memcpy(prevvec, beztn->vec, sizeof(float[9]));
3498               beztn++;
3499             }
3500           }
3501
3502           bezt++;
3503         }
3504
3505         MEM_freeN(nu->bezt);
3506         nu->bezt = beztnew;
3507         nu->pntsu += amount;
3508
3509         BKE_nurb_handles_calc(nu);
3510       }
3511     } /* End of 'if (nu->type == CU_BEZIER)' */
3512     else if (nu->pntsv == 1) {
3513       BPoint *nextbp;
3514
3515       /*
3516        * All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves
3517        * are handled together with the regular NURB plane division, as it
3518        * should be. I split it off just now, let's see if it is
3519        * stable... nzc 30-5-'00
3520        */
3521       /* count */
3522       a = nu->pntsu;
3523       bp = nu->bp;
3524       while (a--) {
3525         nextbp = BKE_nurb_bpoint_get_next(nu, bp);
3526         if (nextbp == NULL) {
3527           break;
3528         }
3529
3530         if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) {
3531           amount += number_cuts;
3532         }
3533         bp++;
3534       }
3535
3536       if (amount) {
3537         /* insert */
3538         bpnew = (BPoint *)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
3539         bpn = bpnew;
3540
3541         a = nu->pntsu;
3542         bp = nu->bp;
3543
3544         while (a--) {
3545           /* Copy "old" point. */
3546           memcpy(bpn, bp, sizeof(BPoint));
3547           keyIndex_updateBP(editnurb, bp, bpn, 1);
3548           bpn++;
3549
3550           nextbp = BKE_nurb_bpoint_get_next(nu, bp);
3551           if (nextbp == NULL) {
3552             break;
3553           }
3554
3555           if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) {
3556             // printf("*** subdivideNurb: insert 'linear' point\n");
3557             for (int i = 0; i < number_cuts; i++) {
3558               factor = (float)(i + 1) / (number_cuts + 1);
3559
3560               memcpy(bpn, nextbp, sizeof(BPoint));
3561               interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor);
3562               bpn->radius = interpf(bp->radius, nextbp->radius, factor);
3563               bpn++;
3564             }
3565           }
3566           bp++;
3567         }
3568
3569         MEM_freeN(nu->bp);
3570         nu->bp = bpnew;
3571         nu->pntsu += amount;
3572
3573         if (nu->type & CU_NURBS) {
3574           BKE_nurb_knot_calc_u(nu);
3575         }
3576       }
3577     } /* End of 'else if (nu->pntsv == 1)' */
3578     else if (nu->type == CU_NURBS) {
3579       /* This is a very strange test ... */
3580       /**
3581        * Subdivide NURB surfaces - nzc 30-5-'00 -
3582        *
3583        * Subdivision of a NURB curve can be effected by adding a
3584        * control point (insertion of a knot), or by raising the
3585        * degree of the functions used to build the NURB. The
3586        * expression
3587        *
3588        *     `degree = knots - controlpoints + 1` (J Walter piece)
3589        *     `degree = knots - controlpoints` (Blender implementation)
3590        *       ( this is confusing.... what is true? Another concern
3591        *       is that the JW piece allows the curve to become
3592        *       explicitly 1st order derivative discontinuous, while
3593        *       this is not what we want here... )
3594        *
3595        * is an invariant for a single NURB curve. Raising the degree
3596        * of the NURB is done elsewhere; the degree is assumed
3597        * constant during this operation. Degree is a property shared
3598        * by all control-points in a curve (even though it is stored
3599        * per control point - this can be misleading).
3600        * Adding a knot is done by searching for the place in the
3601        * knot vector where a certain knot value must be inserted, or
3602        * by picking an appropriate knot value between two existing
3603        * ones. The number of control-points that is influenced by the
3604        * insertion depends on the order of the curve. A certain
3605        * minimum number of knots is needed to form high-order
3606        * curves, as can be seen from the equation above. In Blender,
3607        * currently NURBs may be up to 6th order, so we modify at
3608        * most 6 points. One point is added. For an n-degree curve,
3609        * n points are discarded, and n+1 points inserted
3610        * (so effectively, n points are modified).  (that holds for
3611        * the JW piece, but it seems not for our NURBs)
3612        * In practice, the knot spacing is copied, but the tail
3613        * (the points following the insertion point) need to be
3614        * offset to keep the knot series ascending. The knot series
3615        * is always a series of monotonically ascending integers in
3616        * Blender. When not enough control points are available to
3617        * fit the order, duplicates of the endpoints are added as
3618        * needed.
3619        */
3620       /* selection-arrays */
3621       usel = MEM_callocN(sizeof(int) * nu->pntsu, "subivideNurb3");
3622       vsel = MEM_callocN(sizeof(int) * nu->pntsv, "subivideNurb3");
3623       sel = 0;
3624
3625       /* Count the number of selected points. */
3626       bp = nu->bp;
3627       for (a = 0; a < nu->pntsv; a++) {
3628         for (b = 0; b < nu->pntsu; b++) {
3629           if (bp->f1 & SELECT) {
3630             usel[b]++;
3631             vsel[a]++;
3632             sel++;
3633           }
3634           bp++;
3635         }
3636       }
3637       if (sel == (nu->pntsu * nu->pntsv)) { /* subdivide entire nurb */
3638         /* Global subdivision is a special case of partial
3639          * subdivision. Strange it is considered separately... */
3640
3641         /* count of nodes (after subdivision) along U axis */
3642         int countu = nu->pntsu + (nu->pntsu - 1) * number_cuts;
3643
3644         /* total count of nodes after subdivision */
3645         int tot = ((number_cuts + 1) * nu->pntsu - number_cuts) *
3646                   ((number_cuts + 1) * nu->pntsv - number_cuts);
3647
3648         bpn = bpnew = MEM_mallocN(tot * sizeof(BPoint), "subdivideNurb4");
3649         bp = nu->bp;
3650         /* first subdivide rows */
3651         for (a = 0; a < nu->pntsv; a++) {
3652           for (b = 0; b < nu->pntsu; b++) {
3653             *bpn = *bp;
3654             keyIndex_updateBP(editnurb, bp, bpn, 1);
3655             bpn++;
3656             bp++;
3657             if (b < nu->pntsu - 1) {
3658               prevbp = bp - 1;
3659               for (int i = 0; i < number_cuts; i++) {
3660                 factor = (float)(i + 1) / (number_cuts + 1);
3661                 *bpn = *bp;
3662                 interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
3663                 bpn++;
3664               }
3665             }
3666           }
3667           bpn += number_cuts * countu;
3668         }
3669         /* now insert new */
3670         bpn = bpnew + ((number_cuts + 1) * nu->pntsu - number_cuts);
3671         bp = bpnew + (number_cuts + 1) * ((number_cuts + 1) * nu->pntsu - number_cuts);
3672         prevbp = bpnew;
3673         for (a = 1; a < nu->pntsv; a++) {
3674
3675           for (b = 0; b < (number_cuts + 1) * nu->pntsu - number_cuts; b++) {
3676             BPoint *tmp = bpn;
3677             for (int i = 0; i < number_cuts; i++) {
3678               factor = (float)(i + 1) / (number_cuts + 1);
3679               *tmp = *bp;
3680               interp_v4_v4v4(tmp->vec, prevbp->vec, bp->vec, factor);
3681               tmp += countu;
3682             }
3683             bp++;
3684             prevbp++;
3685             bpn++;
3686           }
3687           bp += number_cuts * countu;
3688           bpn += number_cuts * countu;
3689           prevbp += number_cuts * countu;
3690         }
3691         MEM_freeN(nu->bp);
3692         nu->bp = bpnew;
3693         nu->pntsu = (number_cuts + 1) * nu->pntsu - number_cuts;
3694         nu->pntsv = (number_cuts + 1) * nu->pntsv - number_cuts;
3695         BKE_nurb_knot_calc_u(nu);
3696         BKE_nurb_knot_calc_v(nu);
3697       } /* End of 'if (sel == nu->pntsu * nu->pntsv)' (subdivide entire NURB) */
3698       else {
3699         /* subdivide in v direction? */
3700         sel = 0;
3701         for (a = 0; a < nu->pntsv - 1; a++) {
3702           if (vsel[a] == nu->pntsu && vsel[a + 1] == nu->pntsu) {
3703             sel += number_cuts;
3704           }
3705         }
3706
3707         if (sel) { /* V ! */
3708           bpn = bpnew = MEM_mallocN((sel + nu->pntsv) * nu->pntsu * sizeof(BPoint),
3709                                     "subdivideNurb4");
3710           bp = nu->bp;
3711           for (a = 0; a < nu->pntsv; a++) {
3712             for (b = 0; b < nu->pntsu; b++) {
3713               *bpn = *bp;
3714               keyIndex_updateBP(editnurb, bp, bpn, 1);
3715               bpn++;
3716               bp++;
3717             }
3718             if ((a < nu->pntsv - 1) && vsel[a] == nu->pntsu && vsel[a + 1] == nu->pntsu) {
3719               for (int i = 0; i < number_cuts; i++) {
3720                 factor = (float)(i + 1) / (number_cuts + 1);
3721                 prevbp = bp - nu->pntsu;
3722                 for (b = 0; b < nu->pntsu; b++) {
3723                   /*
3724                    * This simple bisection must be replaces by a
3725                    * subtle resampling of a number of points. Our
3726                    * task is made slightly easier because each
3727                    * point in our curve is a separate data
3728                    * node. (is it?)
3729                    */
3730                   *bpn = *prevbp;
3731                   interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
3732                   bpn++;
3733
3734                   prevbp++;
3735                   bp++;
3736                 }
3737                 bp -= nu->pntsu;
3738               }
3739             }
3740           }
3741           MEM_freeN(nu->bp);
3742           nu->bp = bpnew;
3743           nu->pntsv += sel;
3744           BKE_nurb_knot_calc_v(nu);
3745         }
3746         else {
3747           /* or in u direction? */
3748           sel = 0;
3749           for (a = 0; a < nu->pntsu - 1; a++) {
3750             if (usel[a] == nu->pntsv && usel[a + 1] == nu->pntsv) {
3751               sel += number_cuts;
3752             }
3753           }
3754
3755           if (sel) { /* U ! */
3756             /* Inserting U points is sort of 'default' Flat curves only get */
3757             /* U points inserted in them.                                   */
3758             bpn = bpnew = MEM_mallocN((sel + nu->pntsu) * nu->pntsv * sizeof(BPoint),
3759                                       "subdivideNurb4");
3760             bp = nu->bp;
3761             for (a = 0; a < nu->pntsv; a++) {
3762               for (b = 0; b < nu->pntsu; b++) {
3763                 *bpn = *bp;
3764                 keyIndex_updateBP(editnurb, bp, bpn, 1);
3765                 bpn++;
3766                 bp++;
3767                 if ((b < nu->pntsu - 1) && usel[b] == nu->pntsv && usel[b + 1] == nu->pntsv) {
3768                   /*
3769                    * One thing that bugs me here is that the
3770                    * orders of things are not the same as in
3771                    * the JW piece. Also, this implies that we
3772                    * handle at most 3rd order curves? I miss
3773                    * some symmetry here...
3774                    */
3775                   for (int i = 0; i < number_cuts; i++) {
3776                     factor = (float)(i + 1) / (number_cuts + 1);
3777                     prevbp = bp - 1;
3778                     *bpn = *prevbp;
3779                     interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
3780                     bpn++;
3781                   }
3782                 }
3783               }
3784             }
3785             MEM_freeN(nu->bp);
3786             nu->bp = bpnew;
3787             nu->pntsu += sel;
3788             BKE_nurb_knot_calc_u(nu); /* shift knots forward */
3789           }
3790         }
3791       }
3792       MEM_freeN(usel);
3793       MEM_freeN(vsel);
3794
3795     } /* End of 'if (nu->type == CU_NURBS)'  */
3796   }
3797 }
3798
3799 static int subdivide_exec(bContext *C, wmOperator *op)
3800 {
3801   const int number_cuts = RNA_int_get(op->ptr, "number_cuts");
3802
3803   Main *bmain = CTX_data_main(C);
3804   ViewLayer *view_layer = CTX_data_view_layer(C);
3805   View3D *v3d = CTX_wm_view3d(C);
3806
3807   uint objects_len = 0;
3808   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3809       view_layer, CTX_wm_view3d(C), &objects_len);
3810   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3811     Object *obedit = objects[ob_index];
3812     Curve *cu = obedit->data;
3813
3814     if (!ED_curve_select_check(v3d, cu->editnurb)) {
3815       continue;
3816     }
3817
3818     subdividenurb(obedit, v3d, number_cuts);
3819
3820     if (ED_curve_updateAnimPaths(bmain, cu)) {
3821       WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
3822     }
3823
3824     WM_event_add_notifier(C, NC_GEOM | ND_DATA, cu);
3825     DEG_id_tag_update(obedit->data, 0);
3826   }
3827   MEM_freeN(objects);
3828
3829   return OPERATOR_FINISHED;
3830 }
3831
3832 void CURVE_OT_subdivide(wmOperatorType *ot)
3833 {
3834   PropertyRNA *prop;
3835
3836   /* identifiers */
3837   ot->name = "Subdivide";
3838   ot->description = "Subdivide selected segments";
3839   ot->idname = "CURVE_OT_subdivide";
3840
3841   /* api callbacks */
3842   ot->exec = subdivide_exec;
3843   ot->poll = ED_operator_editsurfcurve;
3844
3845   /* flags */
3846   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3847
3848   prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of cuts", "", 1, 10);
3849   /* Avoid re-using last var because it can cause _very_ high poly meshes
3850    * and annoy users (or worse crash). */
3851   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3852 }
3853
3854 /** \} */
3855
3856 /* -------------------------------------------------------------------- */
3857 /** \name Set Spline Type Operator
3858  * \{ */
3859
3860 static int set_spline_type_exec(bContext *C, wmOperator *op)
3861 {
3862   ViewLayer *view_layer = CTX_data_view_layer(C);
3863   uint objects_len;
3864   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3865       view_layer, CTX_wm_view3d(C), &objects_len);
3866   int ret_value = OPERATOR_CANCELLED;
3867
3868   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3869     Object *obedit = objects[ob_index];
3870     Main *bmain = CTX_data_main(C);
3871     View3D *v3d = CTX_wm_view3d(C);
3872     ListBase *editnurb = object_editcurve_get(obedit);
3873     bool changed = false;
3874     bool changed_size = false;
3875     const bool use_handles = RNA_boolean_get(op->ptr, "use_handles");
3876     const int type = RNA_enum_get(op->ptr, "type");
3877
3878     if (type == CU_CARDINAL || type == CU_BSPLINE) {
3879       BKE_report(op->reports, RPT_ERROR, "Not yet implemented");
3880       continue;
3881     }
3882
3883     LISTBASE_FOREACH (Nurb *, nu, editnurb) {
3884       if (ED_curve_nurb_select_check(v3d, nu)) {
3885         const int pntsu_prev = nu->pntsu;
3886         const char *err_msg = NULL;
3887         if (BKE_nurb_type_convert(nu, type, use_handles, &err_msg)) {
3888           changed = true;
3889           if (pntsu_prev != nu->pntsu) {
3890             changed_size = true;
3891           }
3892         }
3893         else {
3894           BKE_report(op->reports, RPT_ERROR, err_msg);
3895         }
3896       }
3897     }
3898
3899     if (changed) {
3900       if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
3901         WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
3902       }
3903
3904       DEG_id_tag_update(obedit->data, 0);
3905       WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
3906
3907       if (changed_size) {
3908         Curve *cu = obedit->data;
3909         cu->actvert = CU_ACT_NONE;
3910       }
3911
3912       ret_value = OPERATOR_FINISHED;
3913     }
3914   }
3915
3916   MEM_freeN(objects);
3917
3918   return ret_value;
3919 }
3920
3921 void CURVE_OT_spline_type_set(wmOperatorType *ot)
3922 {
3923   static const EnumPropertyItem type_items[] = {
3924       {CU_POLY, "POLY", 0, "Poly", ""},
3925       {CU_BEZIER, "BEZIER", 0, "Bezier", ""},
3926       //      {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
3927       //      {CU_BSPLINE, "B_SPLINE", 0, "B-Spline", ""},
3928       {CU_NURBS, "NURBS", 0, "NURBS", ""},
3929       {0, NULL, 0, NULL, NULL},
3930   };
3931
3932   /* identifiers */
3933   ot->name = "Set Spline Type";
3934   ot->description = "Set type of active spline";
3935   ot->idname = "CURVE_OT_spline_type_set";
3936
3937   /* api callbacks */
3938   ot->exec = set_spline_type_exec;
3939   ot->invoke = WM_menu_invoke;
3940   ot->poll = ED_operator_editcurve;
3941
3942   /* flags */
3943   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3944
3945   /* properties */
3946   ot->prop = RNA_def_enum(ot->srna, "type", type_items, CU_POLY, "Type", "Spline type");
3947   RNA_def_boolean(ot->srna,
3948                   "use_handles",
3949                   0,
3950                   "Handles",
3951                   "Use handles when converting bezier curves into polygons");
3952 }
3953
3954 /** \} */
3955
3956 /* -------------------------------------------------------------------- */
3957 /** \name Set Handle Type Operator
3958  * \{ */
3959
3960 static int set_handle_type_exec(bContext *C, wmOperator *op)
3961 {
3962   ViewLayer *view_layer = CTX_data_view_layer(C);
3963   View3D *v3d = CTX_wm_view3d(C);
3964   const int handle_type = RNA_enum_get(op->ptr, "type");
3965
3966   uint objects_len;
3967   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
3968       view_layer, CTX_wm_view3d(C), &objects_len);
3969   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3970     Object *obedit = objects[ob_index];
3971     Curve *cu = obedit->data;
3972
3973     if (!ED_curve_select_check(v3d, cu->editnurb)) {
3974       continue;
3975     }
3976
3977     ListBase *editnurb = object_editcurve_get(obedit);
3978     BKE_nurbList_handles_set(editnurb, handle_type);
3979
3980     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
3981     DEG_id_tag_update(obedit->data, 0);
3982   }
3983   MEM_freeN(objects);
3984   return OPERATOR_FINISHED;
3985 }
3986
3987 void CURVE_OT_handle_type_set(wmOperatorType *ot)
3988 {
3989   /* keep in sync with graphkeys_handle_type_items */
3990   static const EnumPropertyItem editcurve_handle_type_items[] = {
3991       {HD_AUTO, "AUTOMATIC", 0, "Automatic", ""},
3992       {HD_VECT, "VECTOR", 0, "Vector", ""},
3993       {5, "ALIGNED", 0, "Aligned", ""},
3994       {6, "FREE_ALIGN", 0, "Free", ""},
3995       {3, "TOGGLE_FREE_ALIGN", 0, "Toggle Free/Align", ""},
3996       {0, NULL, 0, NULL, NULL},
3997   };
3998
3999   /* identifiers */
4000   ot->name = "Set Handle Type";
4001   ot->description = "Set type of handles for selected control points";
4002   ot->idname = "CURVE_OT_handle_type_set";
4003
4004   /* api callbacks */
4005   ot->invoke = WM_menu_invoke;
4006   ot->exec = set_handle_type_exec;
4007   ot->poll = ED_operator_editcurve;
4008
4009   /* flags */
4010   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4011
4012   /* properties */
4013   ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
4014 }
4015
4016 /** \} */
4017
4018 /* -------------------------------------------------------------------- */
4019 /** \name Recalculate Handles Operator
4020  * \{ */
4021
4022 static int curve_normals_make_consistent_exec(bContext *C, wmOperator *op)
4023 {
4024   ViewLayer *view_layer = CTX_data_view_layer(C);
4025   View3D *v3d = CTX_wm_view3d(C);
4026
4027   const bool calc_length = RNA_boolean_get(op->ptr, "calc_length");
4028
4029   uint objects_len;
4030   Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
4031       view_layer, CTX_wm_view3d(C), &objects_len);
4032   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4033     Object *obedit = objects[ob_index];
4034     Curve *cu = obedit->data;
4035
4036     if (!ED_curve_select_check(v3d, cu->editnurb)) {
4037       continue;
4038     }
4039
4040     ListBase *editnurb = object_editcurve_get(obedit);
4041     BKE_nurbList_handles_recalculate(editnurb, calc_length, SELECT);
4042
4043     WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
4044     DEG_id_tag_update(obedit->data, 0);
4045   }
4046   MEM_freeN(objects);
4047   return OPERATOR_FINISHED;
4048 }
4049
4050 void CURVE_OT_normals_make_consistent(wmOperatorType *ot)
4051 {
4052   /* identifiers */
4053   ot->name = "Recalculate Handles";
4054   ot->description = "Recalculate the direction of selected handles";
4055   ot->idname = "CURVE_OT_normals_make_consistent";
4056
4057   /* api callbacks */
4058   ot->exec = curve_normals_make_consistent_exec;
4059   ot->poll = ED_operator_editcurve;
4060
4061   /* flags */
4062   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4063
4064   /* props */
4065   RNA_def_boolean(ot->srna, "calc_length", false, "Length", "Recalculate handle length");
4066 }
4067
4068 /** \} */
4069
4070 /* -------------------------------------------------------------------- */
4071 /** \name Make Segment Operator
4072  *
4073  * Also handles skinning & lofting.
4074  * \{ */
4075
4076 static void switchdirection_knots(float *base, int tot)
4077 {
4078   float *fp1, *fp2, *tempf;
4079   int a;
4080
4081   if (base == NULL || tot == 0) {
4082     return;
4083   }
4084
4085   /* reverse knots */
4086   a = tot;
4087   fp1 = base;
4088   fp2 = fp1 + (a - 1);
4089   a /= 2;
4090   while (fp1 != fp2 && a > 0) {
4091     SWAP(float, *fp1, *fp2);
4092     a--;
4093     fp1++;
4094     fp2--;
4095   }
4096
4097   /* and make in increasing order again */
4098   a = tot - 1;
4099   fp1 = base;
4100   fp2 = tempf = MEM_mallocN(sizeof(float) * tot, "switchdirect");
4101   while (a--) {
4102     fp2[0] = fabsf(fp1[1] - fp1[0]);
4103     fp1++;
4104     fp2++;
4105   }
4106   fp2[0] = 0.0f;
4107
4108   a = tot - 1;
4109   fp1 = base;
4110   fp2 = tempf;
4111   fp1[0] = 0.0;
4112   fp1++;
4113   while (a--) {
4114     fp1[0] = fp1[-1] + fp2[0];
4115     fp1++;
4116     fp2++;
4117   }
4118   MEM_freeN(tempf);
4119 }
4120
4121 static void rotate_direction_nurb(Nurb *nu)
4122 {
4123   BPoint *bp1, *bp2, *temp;
4124   int u, v;
4125
4126   SWAP(int, nu->pntsu, nu->pntsv);
4127   SWAP(short, nu->orderu, nu->orderv);
4128   SWAP(short, nu->resolu, nu->resolv);
4129   SWAP(short, nu->flagu, nu->flagv);
4130
4131   SWAP(float *, nu->knotsu, nu->knotsv);
4132   switchdirection_knots(nu->knotsv, KNOTSV(nu));
4133
4134   temp = MEM_dupallocN(nu->bp);
4135   bp1 = nu->bp;
4136   for (v = 0; v < nu->pntsv; v++) {
4137     for (u = 0; u < nu->pntsu; u++, bp1++) {
4138       bp2 = temp + (nu->pntsu - u - 1) * (nu->pntsv) + v;
4139       *bp1 = *bp2;
4140     }
4141   }
4142
4143   MEM_freeN(temp);
4144 }
4145
4146 static bool is_u_selected(Nurb *nu, int u)
4147 {
4148   BPoint *bp;
4149   int v;
4150
4151   /* what about resolu == 2? */
4152   bp = &nu->bp[u];
4153   for (v = 0; v < nu->pntsv - 1;&nbs