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