Blender  V2.93
editcurve.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include "DNA_anim_types.h"
25 #include "DNA_key_types.h"
26 #include "DNA_object_types.h"
27 #include "DNA_scene_types.h"
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "BLI_array_utils.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_ghash.h"
34 #include "BLI_math.h"
35 
36 #include "BLT_translation.h"
37 
38 #include "BKE_action.h"
39 #include "BKE_anim_data.h"
40 #include "BKE_context.h"
41 #include "BKE_curve.h"
42 #include "BKE_displist.h"
43 #include "BKE_fcurve.h"
44 #include "BKE_global.h"
45 #include "BKE_key.h"
46 #include "BKE_layer.h"
47 #include "BKE_lib_id.h"
48 #include "BKE_main.h"
49 #include "BKE_modifier.h"
50 #include "BKE_report.h"
51 
52 #include "DEG_depsgraph.h"
53 #include "DEG_depsgraph_build.h"
54 #include "DEG_depsgraph_query.h"
55 
56 #include "WM_api.h"
57 #include "WM_types.h"
58 
59 #include "ED_curve.h"
60 #include "ED_object.h"
61 #include "ED_outliner.h"
62 #include "ED_screen.h"
63 #include "ED_transform.h"
65 #include "ED_types.h"
66 #include "ED_view3d.h"
67 
68 #include "curve_intern.h"
69 
70 #include "curve_fit_nd.h"
71 
72 #include "UI_interface.h"
73 #include "UI_resources.h"
74 
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77 #include "RNA_enum_types.h"
78 
79 void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus);
80 static void adduplicateflagNurb(
81  Object *obedit, View3D *v3d, ListBase *newnurb, const uint8_t flag, const bool split);
82 static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split);
83 static bool curve_delete_vertices(Object *obedit, View3D *v3d);
84 
85 /* -------------------------------------------------------------------- */
90 {
91  if (ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
92  Curve *cu = ob->data;
93  return &cu->editnurb->nurbs;
94  }
95  return NULL;
96 }
97 
100 /* -------------------------------------------------------------------- */
104 #if 0
105 void printknots(Object *obedit)
106 {
107  ListBase *editnurb = object_editcurve_get(obedit);
108  Nurb *nu;
109  int a, num;
110 
111  for (nu = editnurb->first; nu; nu = nu->next) {
112  if (ED_curve_nurb_select_check(nu) && nu->type == CU_NURBS) {
113  if (nu->knotsu) {
114  num = KNOTSU(nu);
115  for (a = 0; a < num; a++) {
116  printf("knotu %d: %f\n", a, nu->knotsu[a]);
117  }
118  }
119  if (nu->knotsv) {
120  num = KNOTSV(nu);
121  for (a = 0; a < num; a++) {
122  printf("knotv %d: %f\n", a, nu->knotsv[a]);
123  }
124  }
125  }
126  }
127 }
128 #endif
129 
132 /* -------------------------------------------------------------------- */
137  void *cv, int key_index, int nu_index, int pt_index, int vertex_index)
138 {
139  CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), __func__);
140 
141  cvIndex->orig_cv = cv;
142  cvIndex->key_index = key_index;
143  cvIndex->nu_index = nu_index;
144  cvIndex->pt_index = pt_index;
145  cvIndex->vertex_index = vertex_index;
146  cvIndex->switched = false;
147 
148  return cvIndex;
149 }
150 
151 static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
152 {
153  Nurb *nu = editnurb->nurbs.first;
154  Nurb *orignu = origBase->first;
155  GHash *gh;
156  BezTriple *bezt, *origbezt;
157  BPoint *bp, *origbp;
158  CVKeyIndex *keyIndex;
159  int a, key_index = 0, nu_index = 0, pt_index = 0, vertex_index = 0;
160 
161  if (editnurb->keyindex) {
162  return;
163  }
164 
165  gh = BLI_ghash_ptr_new("editNurb keyIndex");
166 
167  while (orignu) {
168  if (orignu->bezt) {
169  a = orignu->pntsu;
170  bezt = nu->bezt;
171  origbezt = orignu->bezt;
172  pt_index = 0;
173  while (a--) {
174  /* We cannot keep *any* reference to curve obdata,
175  * it might be replaced and freed while editcurve remain in use
176  * (in viewport render case e.g.). Note that we could use a pool to avoid
177  * lots of malloc's here, but... not really a problem for now. */
178  BezTriple *origbezt_cpy = MEM_mallocN(sizeof(*origbezt), __func__);
179  *origbezt_cpy = *origbezt;
180  keyIndex = init_cvKeyIndex(origbezt_cpy, key_index, nu_index, pt_index, vertex_index);
181  BLI_ghash_insert(gh, bezt, keyIndex);
182  key_index += KEYELEM_FLOAT_LEN_BEZTRIPLE;
183  vertex_index += 3;
184  bezt++;
185  origbezt++;
186  pt_index++;
187  }
188  }
189  else {
190  a = orignu->pntsu * orignu->pntsv;
191  bp = nu->bp;
192  origbp = orignu->bp;
193  pt_index = 0;
194  while (a--) {
195  /* We cannot keep *any* reference to curve obdata,
196  * it might be replaced and freed while editcurve remain in use
197  * (in viewport render case e.g.). Note that we could use a pool to avoid
198  * lots of malloc's here, but... not really a problem for now. */
199  BPoint *origbp_cpy = MEM_mallocN(sizeof(*origbp_cpy), __func__);
200  *origbp_cpy = *origbp;
201  keyIndex = init_cvKeyIndex(origbp_cpy, key_index, nu_index, pt_index, vertex_index);
202  BLI_ghash_insert(gh, bp, keyIndex);
203  key_index += KEYELEM_FLOAT_LEN_BPOINT;
204  bp++;
205  origbp++;
206  pt_index++;
207  vertex_index++;
208  }
209  }
210 
211  nu = nu->next;
212  orignu = orignu->next;
213  nu_index++;
214  }
215 
216  editnurb->keyindex = gh;
217 }
218 
219 static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, const void *cv)
220 {
221  return BLI_ghash_lookup(editnurb->keyindex, cv);
222 }
223 
224 static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, const void *cv)
225 {
226  return BLI_ghash_popkey(editnurb->keyindex, cv, NULL);
227 }
228 
229 static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, const BezTriple *bezt)
230 {
231  CVKeyIndex *index = getCVKeyIndex(editnurb, bezt);
232 
233  if (!index) {
234  return NULL;
235  }
236 
237  return (BezTriple *)index->orig_cv;
238 }
239 
240 static BPoint *getKeyIndexOrig_bp(EditNurb *editnurb, BPoint *bp)
241 {
242  CVKeyIndex *index = getCVKeyIndex(editnurb, bp);
243 
244  if (!index) {
245  return NULL;
246  }
247 
248  return (BPoint *)index->orig_cv;
249 }
250 
251 static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
252 {
253  CVKeyIndex *index = getCVKeyIndex(editnurb, cv);
254 
255  if (!index) {
256  return -1;
257  }
258 
259  return index->key_index;
260 }
261 
262 static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
263 {
264  if (!editnurb->keyindex) {
265  return;
266  }
267 
269 }
270 
271 static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
272 {
273  if (!editnurb->keyindex) {
274  return;
275  }
276 
278 }
279 
280 static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
281 {
282  int a;
283 
284  if (!editnurb->keyindex) {
285  return;
286  }
287 
288  if (nu->bezt) {
289  const BezTriple *bezt = nu->bezt;
290  a = nu->pntsu;
291 
292  while (a--) {
294  bezt++;
295  }
296  }
297  else {
298  const BPoint *bp = nu->bp;
299  a = nu->pntsu * nu->pntsv;
300 
301  while (a--) {
303  bp++;
304  }
305  }
306 }
307 
308 static void keyIndex_delNurbList(EditNurb *editnurb, ListBase *nubase)
309 {
310  LISTBASE_FOREACH (Nurb *, nu, nubase) {
311  keyIndex_delNurb(editnurb, nu);
312  }
313 }
314 
315 static void keyIndex_updateCV(EditNurb *editnurb, char *cv, char *newcv, int count, int size)
316 {
317  int i;
318  CVKeyIndex *index;
319 
320  if (editnurb->keyindex == NULL) {
321  /* No shape keys - updating not needed */
322  return;
323  }
324 
325  for (i = 0; i < count; i++) {
326  index = popCVKeyIndex(editnurb, cv);
327 
328  if (index) {
329  BLI_ghash_insert(editnurb->keyindex, newcv, index);
330  }
331 
332  newcv += size;
333  cv += size;
334  }
335 }
336 
337 static void keyIndex_updateBezt(EditNurb *editnurb, BezTriple *bezt, BezTriple *newbezt, int count)
338 {
339  keyIndex_updateCV(editnurb, (char *)bezt, (char *)newbezt, count, sizeof(BezTriple));
340 }
341 
342 static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp, BPoint *newbp, int count)
343 {
344  keyIndex_updateCV(editnurb, (char *)bp, (char *)newbp, count, sizeof(BPoint));
345 }
346 
347 void ED_curve_keyindex_update_nurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
348 {
349  if (nu->bezt) {
350  keyIndex_updateBezt(editnurb, nu->bezt, newnu->bezt, newnu->pntsu);
351  }
352  else {
353  keyIndex_updateBP(editnurb, nu->bp, newnu->bp, newnu->pntsu * newnu->pntsv);
354  }
355 }
356 
357 static void keyIndex_swap(EditNurb *editnurb, void *a, void *b)
358 {
359  CVKeyIndex *index1 = popCVKeyIndex(editnurb, a);
360  CVKeyIndex *index2 = popCVKeyIndex(editnurb, b);
361 
362  if (index2) {
363  BLI_ghash_insert(editnurb->keyindex, a, index2);
364  }
365  if (index1) {
366  BLI_ghash_insert(editnurb->keyindex, b, index1);
367  }
368 }
369 
370 static void keyIndex_switchDirection(EditNurb *editnurb, Nurb *nu)
371 {
372  int a;
373  CVKeyIndex *index1, *index2;
374 
375  if (nu->bezt) {
376  BezTriple *bezt1, *bezt2;
377 
378  a = nu->pntsu;
379 
380  bezt1 = nu->bezt;
381  bezt2 = bezt1 + (a - 1);
382 
383  if (a & 1) {
384  a++;
385  }
386 
387  a /= 2;
388 
389  while (a--) {
390  index1 = getCVKeyIndex(editnurb, bezt1);
391  index2 = getCVKeyIndex(editnurb, bezt2);
392 
393  if (index1) {
394  index1->switched = !index1->switched;
395  }
396 
397  if (bezt1 != bezt2) {
398  keyIndex_swap(editnurb, bezt1, bezt2);
399 
400  if (index2) {
401  index2->switched = !index2->switched;
402  }
403  }
404 
405  bezt1++;
406  bezt2--;
407  }
408  }
409  else {
410  BPoint *bp1, *bp2;
411 
412  if (nu->pntsv == 1) {
413  a = nu->pntsu;
414  bp1 = nu->bp;
415  bp2 = bp1 + (a - 1);
416  a /= 2;
417  while (bp1 != bp2 && a > 0) {
418  index1 = getCVKeyIndex(editnurb, bp1);
419  index2 = getCVKeyIndex(editnurb, bp2);
420 
421  if (index1) {
422  index1->switched = !index1->switched;
423  }
424 
425  if (bp1 != bp2) {
426  if (index2) {
427  index2->switched = !index2->switched;
428  }
429 
430  keyIndex_swap(editnurb, bp1, bp2);
431  }
432 
433  a--;
434  bp1++;
435  bp2--;
436  }
437  }
438  else {
439  int b;
440 
441  for (b = 0; b < nu->pntsv; b++) {
442 
443  bp1 = &nu->bp[b * nu->pntsu];
444  a = nu->pntsu;
445  bp2 = bp1 + (a - 1);
446  a /= 2;
447 
448  while (bp1 != bp2 && a > 0) {
449  index1 = getCVKeyIndex(editnurb, bp1);
450  index2 = getCVKeyIndex(editnurb, bp2);
451 
452  if (index1) {
453  index1->switched = !index1->switched;
454  }
455 
456  if (bp1 != bp2) {
457  if (index2) {
458  index2->switched = !index2->switched;
459  }
460 
461  keyIndex_swap(editnurb, bp1, bp2);
462  }
463 
464  a--;
465  bp1++;
466  bp2--;
467  }
468  }
469  }
470  }
471 }
472 
473 static void switch_keys_direction(Curve *cu, Nurb *actnu)
474 {
475  EditNurb *editnurb = cu->editnurb;
476  ListBase *nubase = &editnurb->nurbs;
477  float *fp;
478  int a;
479 
480  LISTBASE_FOREACH (KeyBlock *, currkey, &cu->key->block) {
481  fp = currkey->data;
482 
483  LISTBASE_FOREACH (Nurb *, nu, nubase) {
484  if (nu->bezt) {
485  BezTriple *bezt = nu->bezt;
486  a = nu->pntsu;
487  if (nu == actnu) {
488  while (a--) {
489  if (getKeyIndexOrig_bezt(editnurb, bezt)) {
490  swap_v3_v3(fp, fp + 6);
491  *(fp + 9) = -*(fp + 9);
493  }
494  bezt++;
495  }
496  }
497  else {
499  }
500  }
501  else {
502  BPoint *bp = nu->bp;
503  a = nu->pntsu * nu->pntsv;
504  if (nu == actnu) {
505  while (a--) {
506  if (getKeyIndexOrig_bp(editnurb, bp)) {
507  *(fp + 3) = -*(fp + 3);
509  }
510  bp++;
511  }
512  }
513  else {
514  fp += a * KEYELEM_FLOAT_LEN_BPOINT;
515  }
516  }
517  }
518  }
519 }
520 
522 {
523  EditNurb *editnurb = cu->editnurb;
524 
525  if (!editnurb->keyindex) {
526  /* no shape keys - nothing to do */
527  return;
528  }
529 
530  keyIndex_switchDirection(editnurb, nu);
531  if (cu->key) {
532  switch_keys_direction(cu, nu);
533  }
534 }
535 
537 {
538  GHash *gh;
539  GHashIterator gh_iter;
540 
541  gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_len(keyindex));
542 
543  GHASH_ITER (gh_iter, keyindex) {
544  void *cv = BLI_ghashIterator_getKey(&gh_iter);
545  CVKeyIndex *index = BLI_ghashIterator_getValue(&gh_iter);
546  CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
547 
548  memcpy(newIndex, index, sizeof(CVKeyIndex));
549  newIndex->orig_cv = MEM_dupallocN(index->orig_cv);
550 
551  BLI_ghash_insert(gh, cv, newIndex);
552  }
553 
554  return gh;
555 }
556 
557 static void key_to_bezt(float *key, BezTriple *basebezt, BezTriple *bezt)
558 {
559  memcpy(bezt, basebezt, sizeof(BezTriple));
560  memcpy(bezt->vec, key, sizeof(float[9]));
561  bezt->tilt = key[9];
562  bezt->radius = key[10];
563 }
564 
565 static void bezt_to_key(BezTriple *bezt, float *key)
566 {
567  memcpy(key, bezt->vec, sizeof(float[9]));
568  key[9] = bezt->tilt;
569  key[10] = bezt->radius;
570 }
571 
572 static void calc_keyHandles(ListBase *nurb, float *key)
573 {
574  int a;
575  float *fp = key;
576  BezTriple *bezt;
577 
578  LISTBASE_FOREACH (Nurb *, nu, nurb) {
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++;
632  }
633  }
634  else {
635  a = nu->pntsu * nu->pntsv;
636  fp += a * KEYELEM_FLOAT_LEN_BPOINT;
637  }
638  }
639 }
640 
641 static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
642 {
643  Curve *cu = (Curve *)obedit->data;
644 
645  if (cu->key == NULL) {
646  return;
647  }
648 
649  int a, i;
650  EditNurb *editnurb = cu->editnurb;
651  KeyBlock *actkey = BLI_findlink(&cu->key->block, editnurb->shapenr - 1);
652  BezTriple *bezt, *oldbezt;
653  BPoint *bp, *oldbp;
654  Nurb *newnu;
655  int totvert = BKE_keyblock_curve_element_count(&editnurb->nurbs);
656 
657  float(*ofs)[3] = NULL;
658  float *oldkey, *newkey, *ofp;
659 
660  /* editing the base key should update others */
661  if (cu->key->type == KEY_RELATIVE) {
662  if (BKE_keyblock_is_basis(cu->key, editnurb->shapenr - 1)) { /* active key is a base */
663  int totvec = 0;
664 
665  /* Calculate needed memory to store offset */
666  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
667 
668  if (nu->bezt) {
669  /* Three vects to store handles and one for tilt. */
670  totvec += nu->pntsu * 4;
671  }
672  else {
673  totvec += 2 * nu->pntsu * nu->pntsv;
674  }
675  }
676 
677  ofs = MEM_callocN(sizeof(float[3]) * totvec, "currkey->data");
678  i = 0;
679  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
680  if (nu->bezt) {
681  bezt = nu->bezt;
682  a = nu->pntsu;
683  while (a--) {
684  oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
685 
686  if (oldbezt) {
687  int j;
688  for (j = 0; j < 3; j++) {
689  sub_v3_v3v3(ofs[i], bezt->vec[j], oldbezt->vec[j]);
690  i++;
691  }
692  ofs[i][0] = bezt->tilt - oldbezt->tilt;
693  ofs[i][1] = bezt->radius - oldbezt->radius;
694  i++;
695  }
696  else {
697  i += 4;
698  }
699  bezt++;
700  }
701  }
702  else {
703  bp = nu->bp;
704  a = nu->pntsu * nu->pntsv;
705  while (a--) {
706  oldbp = getKeyIndexOrig_bp(editnurb, bp);
707  if (oldbp) {
708  sub_v3_v3v3(ofs[i], bp->vec, oldbp->vec);
709  ofs[i + 1][0] = bp->tilt - oldbp->tilt;
710  ofs[i + 1][1] = bp->radius - oldbp->radius;
711  }
712  i += 2;
713  bp++;
714  }
715  }
716  }
717  }
718  }
719 
720  LISTBASE_FOREACH (KeyBlock *, currkey, &cu->key->block) {
721  const bool apply_offset = (ofs && (currkey != actkey) &&
722  (editnurb->shapenr - 1 == currkey->relative));
723 
724  float *fp = newkey = MEM_callocN(cu->key->elemsize * totvert, "currkey->data");
725  ofp = oldkey = currkey->data;
726 
727  Nurb *nu = editnurb->nurbs.first;
728  /* We need to restore to original curve into newnurb, *not* editcurve's nurbs.
729  * Otherwise, in case we update obdata *without* leaving editmode (e.g. viewport render),
730  * we would invalidate editcurve. */
731  newnu = newnurbs->first;
732  i = 0;
733  while (nu) {
734  if (currkey == actkey) {
735  const bool restore = actkey != cu->key->refkey;
736 
737  if (nu->bezt) {
738  bezt = nu->bezt;
739  a = nu->pntsu;
740  BezTriple *newbezt = newnu->bezt;
741  while (a--) {
742  int j;
743  oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
744 
745  for (j = 0; j < 3; j++, i++) {
746  copy_v3_v3(&fp[j * 3], bezt->vec[j]);
747 
748  if (restore && oldbezt) {
749  copy_v3_v3(newbezt->vec[j], oldbezt->vec[j]);
750  }
751  }
752  fp[9] = bezt->tilt;
753  fp[10] = bezt->radius;
754 
755  if (restore && oldbezt) {
756  newbezt->tilt = oldbezt->tilt;
757  newbezt->radius = oldbezt->radius;
758  }
759 
761  i++;
762  bezt++;
763  newbezt++;
764  }
765  }
766  else {
767  bp = nu->bp;
768  a = nu->pntsu * nu->pntsv;
769  BPoint *newbp = newnu->bp;
770  while (a--) {
771  oldbp = getKeyIndexOrig_bp(editnurb, bp);
772 
773  copy_v3_v3(fp, bp->vec);
774 
775  fp[3] = bp->tilt;
776  fp[4] = bp->radius;
777 
778  if (restore && oldbp) {
779  copy_v3_v3(newbp->vec, oldbp->vec);
780  newbp->tilt = oldbp->tilt;
781  newbp->radius = oldbp->radius;
782  }
783 
785  bp++;
786  newbp++;
787  i += 2;
788  }
789  }
790  }
791  else {
792  int index;
793  const float *curofp;
794 
795  if (oldkey) {
796  if (nu->bezt) {
797  bezt = nu->bezt;
798  a = nu->pntsu;
799 
800  while (a--) {
801  index = getKeyIndexOrig_keyIndex(editnurb, bezt);
802  if (index >= 0) {
803  int j;
804  curofp = ofp + index;
805 
806  for (j = 0; j < 3; j++, i++) {
807  copy_v3_v3(&fp[j * 3], &curofp[j * 3]);
808 
809  if (apply_offset) {
810  add_v3_v3(&fp[j * 3], ofs[i]);
811  }
812  }
813  fp[9] = curofp[9];
814  fp[10] = curofp[10];
815 
816  if (apply_offset) {
817  /* Apply tilt offsets. */
818  add_v3_v3(fp + 9, ofs[i]);
819  i++;
820  }
821 
823  }
824  else {
825  int j;
826  for (j = 0; j < 3; j++, i++) {
827  copy_v3_v3(&fp[j * 3], bezt->vec[j]);
828  }
829  fp[9] = bezt->tilt;
830  fp[10] = bezt->radius;
831 
833  }
834  bezt++;
835  }
836  }
837  else {
838  bp = nu->bp;
839  a = nu->pntsu * nu->pntsv;
840  while (a--) {
841  index = getKeyIndexOrig_keyIndex(editnurb, bp);
842 
843  if (index >= 0) {
844  curofp = ofp + index;
845  copy_v3_v3(fp, curofp);
846  fp[3] = curofp[3];
847  fp[4] = curofp[4];
848 
849  if (apply_offset) {
850  add_v3_v3(fp, ofs[i]);
851  add_v3_v3(&fp[3], ofs[i + 1]);
852  }
853  }
854  else {
855  copy_v3_v3(fp, bp->vec);
856  fp[3] = bp->tilt;
857  fp[4] = bp->radius;
858  }
859 
861  bp++;
862  i += 2;
863  }
864  }
865  }
866  }
867 
868  nu = nu->next;
869  newnu = newnu->next;
870  }
871 
872  if (apply_offset) {
873  /* handles could become malicious after offsets applying */
874  calc_keyHandles(&editnurb->nurbs, newkey);
875  }
876 
877  currkey->totelem = totvert;
878  if (currkey->data) {
879  MEM_freeN(currkey->data);
880  }
881  currkey->data = newkey;
882  }
883 
884  if (ofs) {
885  MEM_freeN(ofs);
886  }
887 }
888 
891 /* -------------------------------------------------------------------- */
895 static bool curve_is_animated(Curve *cu)
896 {
897  AnimData *ad = BKE_animdata_from_id(&cu->id);
898 
899  return ad && (ad->action || ad->drivers.first);
900 }
901 
902 static void fcurve_path_rename(AnimData *adt,
903  const char *orig_rna_path,
904  const char *rna_path,
905  ListBase *orig_curves,
906  ListBase *curves)
907 {
908  FCurve *nfcu;
909  int len = strlen(orig_rna_path);
910 
911  LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, orig_curves) {
912  if (STREQLEN(fcu->rna_path, orig_rna_path, len)) {
913  char *spath, *suffix = fcu->rna_path + len;
914  nfcu = BKE_fcurve_copy(fcu);
915  spath = nfcu->rna_path;
916  nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
917 
918  /* BKE_fcurve_copy() sets nfcu->grp to NULL. To maintain the groups, we need to keep the
919  * pointer. As a result, the group's 'channels' pointers will be wrong, which is fixed by
920  * calling `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
921  nfcu->grp = fcu->grp;
922  BLI_addtail(curves, nfcu);
923 
924  if (fcu->grp) {
926  }
927  else if ((adt->action) && (&adt->action->curves == orig_curves)) {
928  BLI_remlink(&adt->action->curves, fcu);
929  }
930  else {
931  BLI_remlink(&adt->drivers, fcu);
932  }
933 
934  BKE_fcurve_free(fcu);
935 
936  MEM_freeN(spath);
937  }
938  }
939 }
940 
941 static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu)
942 {
943  if (orig_curves == &adt->drivers) {
944  BLI_remlink(&adt->drivers, fcu);
945  }
946  else {
948  }
949 
950  BKE_fcurve_free(fcu);
951 }
952 
953 static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
954 {
955  int a, pt_index;
956  EditNurb *editnurb = cu->editnurb;
957  CVKeyIndex *keyIndex;
958  char rna_path[64], orig_rna_path[64];
959  AnimData *adt = BKE_animdata_from_id(&cu->id);
960  ListBase curves = {NULL, NULL};
961 
962  int nu_index = 0;
963  LISTBASE_FOREACH_INDEX (Nurb *, nu, &editnurb->nurbs, nu_index) {
964  if (nu->bezt) {
965  BezTriple *bezt = nu->bezt;
966  a = nu->pntsu;
967  pt_index = 0;
968 
969  while (a--) {
970  keyIndex = getCVKeyIndex(editnurb, bezt);
971  if (keyIndex) {
972  BLI_snprintf(
973  rna_path, sizeof(rna_path), "splines[%d].bezier_points[%d]", nu_index, pt_index);
974  BLI_snprintf(orig_rna_path,
975  sizeof(orig_rna_path),
976  "splines[%d].bezier_points[%d]",
977  keyIndex->nu_index,
978  keyIndex->pt_index);
979 
980  if (keyIndex->switched) {
981  char handle_path[64], orig_handle_path[64];
982  BLI_snprintf(orig_handle_path, sizeof(orig_rna_path), "%s.handle_left", orig_rna_path);
983  BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_right", rna_path);
984  fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
985 
986  BLI_snprintf(
987  orig_handle_path, sizeof(orig_rna_path), "%s.handle_right", orig_rna_path);
988  BLI_snprintf(handle_path, sizeof(rna_path), "%s.handle_left", rna_path);
989  fcurve_path_rename(adt, orig_handle_path, handle_path, orig_curves, &curves);
990  }
991 
992  fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
993 
994  keyIndex->nu_index = nu_index;
995  keyIndex->pt_index = pt_index;
996  }
997 
998  bezt++;
999  pt_index++;
1000  }
1001  }
1002  else {
1003  BPoint *bp = nu->bp;
1004  a = nu->pntsu * nu->pntsv;
1005  pt_index = 0;
1006 
1007  while (a--) {
1008  keyIndex = getCVKeyIndex(editnurb, bp);
1009  if (keyIndex) {
1010  BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d].points[%d]", nu_index, pt_index);
1011  BLI_snprintf(orig_rna_path,
1012  sizeof(orig_rna_path),
1013  "splines[%d].points[%d]",
1014  keyIndex->nu_index,
1015  keyIndex->pt_index);
1016  fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1017 
1018  keyIndex->nu_index = nu_index;
1019  keyIndex->pt_index = pt_index;
1020  }
1021 
1022  bp++;
1023  pt_index++;
1024  }
1025  }
1026  }
1027 
1028  /* remove paths for removed control points
1029  * need this to make further step with copying non-cv related curves copying
1030  * not touching cv's f-curves */
1031  LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, orig_curves) {
1032  if (STRPREFIX(fcu->rna_path, "splines")) {
1033  const char *ch = strchr(fcu->rna_path, '.');
1034 
1035  if (ch && (STRPREFIX(ch, ".bezier_points") || STRPREFIX(ch, ".points"))) {
1036  fcurve_remove(adt, orig_curves, fcu);
1037  }
1038  }
1039  }
1040 
1041  nu_index = 0;
1042  LISTBASE_FOREACH_INDEX (Nurb *, nu, &editnurb->nurbs, nu_index) {
1043  keyIndex = NULL;
1044  if (nu->pntsu) {
1045  if (nu->bezt) {
1046  keyIndex = getCVKeyIndex(editnurb, &nu->bezt[0]);
1047  }
1048  else {
1049  keyIndex = getCVKeyIndex(editnurb, &nu->bp[0]);
1050  }
1051  }
1052 
1053  if (keyIndex) {
1054  BLI_snprintf(rna_path, sizeof(rna_path), "splines[%d]", nu_index);
1055  BLI_snprintf(orig_rna_path, sizeof(orig_rna_path), "splines[%d]", keyIndex->nu_index);
1056  fcurve_path_rename(adt, orig_rna_path, rna_path, orig_curves, &curves);
1057  }
1058  }
1059 
1060  /* the remainders in orig_curves can be copied back (like follow path) */
1061  /* (if it's not path to spline) */
1062  LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, orig_curves) {
1063  if (STRPREFIX(fcu->rna_path, "splines")) {
1064  fcurve_remove(adt, orig_curves, fcu);
1065  }
1066  else {
1067  BLI_addtail(&curves, fcu);
1068  }
1069  }
1070 
1071  *orig_curves = curves;
1072  if (adt != NULL) {
1074  }
1075 }
1076 
1077 /* return 0 if animation data wasn't changed, 1 otherwise */
1079 {
1080  AnimData *adt = BKE_animdata_from_id(&cu->id);
1081  EditNurb *editnurb = cu->editnurb;
1082 
1083  if (!editnurb->keyindex) {
1084  return 0;
1085  }
1086 
1087  if (!curve_is_animated(cu)) {
1088  return 0;
1089  }
1090 
1091  if (adt->action != NULL) {
1092  curve_rename_fcurves(cu, &adt->action->curves);
1094  }
1095 
1096  curve_rename_fcurves(cu, &adt->drivers);
1098 
1099  /* TODO(sergey): Only update if something actually changed. */
1100  DEG_relations_tag_update(bmain);
1101 
1102  return 1;
1103 }
1104 
1107 /* -------------------------------------------------------------------- */
1111 static int *init_index_map(Object *obedit, int *r_old_totvert)
1112 {
1113  Curve *curve = (Curve *)obedit->data;
1114  EditNurb *editnurb = curve->editnurb;
1115  CVKeyIndex *keyIndex;
1116  int *old_to_new_map;
1117 
1118  int old_totvert = 0;
1119  LISTBASE_FOREACH (Nurb *, nu, &curve->nurb) {
1120  if (nu->bezt) {
1121  old_totvert += nu->pntsu * 3;
1122  }
1123  else {
1124  old_totvert += nu->pntsu * nu->pntsv;
1125  }
1126  }
1127 
1128  old_to_new_map = MEM_mallocN(old_totvert * sizeof(int), "curve old to new index map");
1129  for (int i = 0; i < old_totvert; i++) {
1130  old_to_new_map[i] = -1;
1131  }
1132 
1133  int vertex_index = 0;
1134  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
1135  if (nu->bezt) {
1136  BezTriple *bezt = nu->bezt;
1137  int a = nu->pntsu;
1138 
1139  while (a--) {
1140  keyIndex = getCVKeyIndex(editnurb, bezt);
1141  if (keyIndex && keyIndex->vertex_index + 2 < old_totvert) {
1142  if (keyIndex->switched) {
1143  old_to_new_map[keyIndex->vertex_index] = vertex_index + 2;
1144  old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
1145  old_to_new_map[keyIndex->vertex_index + 2] = vertex_index;
1146  }
1147  else {
1148  old_to_new_map[keyIndex->vertex_index] = vertex_index;
1149  old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
1150  old_to_new_map[keyIndex->vertex_index + 2] = vertex_index + 2;
1151  }
1152  }
1153  vertex_index += 3;
1154  bezt++;
1155  }
1156  }
1157  else {
1158  BPoint *bp = nu->bp;
1159  int a = nu->pntsu * nu->pntsv;
1160 
1161  while (a--) {
1162  keyIndex = getCVKeyIndex(editnurb, bp);
1163  if (keyIndex) {
1164  old_to_new_map[keyIndex->vertex_index] = vertex_index;
1165  }
1166  vertex_index++;
1167  bp++;
1168  }
1169  }
1170  }
1171 
1172  *r_old_totvert = old_totvert;
1173  return old_to_new_map;
1174 }
1175 
1176 static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit)
1177 {
1178  Curve *curve = (Curve *)obedit->data;
1179  EditNurb *editnurb = curve->editnurb;
1180  int *old_to_new_map = NULL;
1181  int old_totvert;
1182 
1183  if (editnurb->keyindex == NULL) {
1184  /* TODO(sergey): Happens when separating curves, this would lead to
1185  * the wrong indices in the hook modifier, address this together with
1186  * other indices issues.
1187  */
1188  return;
1189  }
1190 
1191  LISTBASE_FOREACH (Object *, object, &bmain->objects) {
1192  int index;
1193  if ((object->parent) && (object->parent->data == curve) &&
1194  ELEM(object->partype, PARVERT1, PARVERT3)) {
1195  if (old_to_new_map == NULL) {
1196  old_to_new_map = init_index_map(obedit, &old_totvert);
1197  }
1198 
1199  if (object->par1 < old_totvert) {
1200  index = old_to_new_map[object->par1];
1201  if (index != -1) {
1202  object->par1 = index;
1203  }
1204  }
1205  if (object->par2 < old_totvert) {
1206  index = old_to_new_map[object->par2];
1207  if (index != -1) {
1208  object->par2 = index;
1209  }
1210  }
1211  if (object->par3 < old_totvert) {
1212  index = old_to_new_map[object->par3];
1213  if (index != -1) {
1214  object->par3 = index;
1215  }
1216  }
1217  }
1218  if (object->data == curve) {
1219  LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
1220  if (md->type == eModifierType_Hook) {
1221  HookModifierData *hmd = (HookModifierData *)md;
1222  int i, j;
1223 
1224  if (old_to_new_map == NULL) {
1225  old_to_new_map = init_index_map(obedit, &old_totvert);
1226  }
1227 
1228  for (i = j = 0; i < hmd->totindex; i++) {
1229  if (hmd->indexar[i] < old_totvert) {
1230  index = old_to_new_map[hmd->indexar[i]];
1231  if (index != -1) {
1232  hmd->indexar[j++] = index;
1233  }
1234  }
1235  else {
1236  j++;
1237  }
1238  }
1239 
1240  hmd->totindex = j;
1241  }
1242  }
1243  }
1244  }
1245  if (old_to_new_map != NULL) {
1246  MEM_freeN(old_to_new_map);
1247  }
1248 }
1249 
1250 /* load editNurb in object */
1251 void ED_curve_editnurb_load(Main *bmain, Object *obedit)
1252 {
1253  ListBase *editnurb = object_editcurve_get(obedit);
1254 
1255  if (obedit == NULL) {
1256  return;
1257  }
1258 
1259  if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1260  Curve *cu = obedit->data;
1261  ListBase newnurb = {NULL, NULL}, oldnurb = cu->nurb;
1262 
1263  remap_hooks_and_vertex_parents(bmain, obedit);
1264 
1265  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1266  Nurb *newnu = BKE_nurb_duplicate(nu);
1267  BLI_addtail(&newnurb, newnu);
1268 
1269  if (nu->type == CU_NURBS) {
1271  }
1272  }
1273 
1274  /* We have to pass also new copied nurbs, since we want to restore original curve
1275  * (without edited shapekey) on obdata, but *not* on editcurve itself
1276  * (ED_curve_editnurb_load call does not always implies freeing
1277  * of editcurve, e.g. when called to generate render data). */
1278  calc_shapeKeys(obedit, &newnurb);
1279 
1280  cu->nurb = newnurb;
1281 
1282  ED_curve_updateAnimPaths(bmain, obedit->data);
1283 
1284  BKE_nurbList_free(&oldnurb);
1285  }
1286 }
1287 
1288 /* make copy in cu->editnurb */
1290 {
1291  Curve *cu = (Curve *)obedit->data;
1292  EditNurb *editnurb = cu->editnurb;
1293  KeyBlock *actkey;
1294 
1295  if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
1296  actkey = BKE_keyblock_from_object(obedit);
1297 
1298  if (actkey) {
1299  // XXX strcpy(G.editModeTitleExtra, "(Key) ");
1300  /* TODO(campbell): undo_system: investigate why this was needed. */
1301 #if 0
1302  undo_editmode_clear();
1303 #endif
1304  }
1305 
1306  if (editnurb) {
1307  BKE_nurbList_free(&editnurb->nurbs);
1308  BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex);
1309  }
1310  else {
1311  editnurb = MEM_callocN(sizeof(EditNurb), "editnurb");
1312  cu->editnurb = editnurb;
1313  }
1314 
1315  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
1316  Nurb *newnu = BKE_nurb_duplicate(nu);
1317  BLI_addtail(&editnurb->nurbs, newnu);
1318  }
1319 
1320  /* animation could be added in editmode even if there was no animdata in
1321  * object mode hence we always need CVs index be created */
1322  init_editNurb_keyIndex(editnurb, &cu->nurb);
1323 
1324  if (actkey) {
1325  editnurb->shapenr = obedit->shapenr;
1326  /* Apply shapekey to new nurbs of editnurb, not those of original curve
1327  * (and *after* we generated keyIndex), else we do not have valid 'original' data
1328  * to properly restore curve when leaving editmode. */
1329  BKE_keyblock_convert_to_curve(actkey, cu, &editnurb->nurbs);
1330  }
1331  }
1332 }
1333 
1335 {
1336  Curve *cu = obedit->data;
1337 
1339 }
1340 
1343 /* -------------------------------------------------------------------- */
1348 {
1349  Main *bmain = CTX_data_main(C);
1351  ViewLayer *view_layer = CTX_data_view_layer(C);
1352  View3D *v3d = CTX_wm_view3d(C);
1353 
1354  struct {
1355  int changed;
1356  int unselected;
1357  int error_vertex_keys;
1358  int error_generic;
1359  } status = {0};
1360 
1361  WM_cursor_wait(true);
1362 
1363  uint bases_len = 0;
1365  view_layer, CTX_wm_view3d(C), &bases_len);
1366  for (uint b_index = 0; b_index < bases_len; b_index++) {
1367  Base *oldbase = bases[b_index];
1368  Base *newbase;
1369  Object *oldob, *newob;
1370  Curve *oldcu, *newcu;
1371  EditNurb *newedit;
1372  ListBase newnurb = {NULL, NULL};
1373 
1374  oldob = oldbase->object;
1375  oldcu = oldob->data;
1376 
1377  if (oldcu->key) {
1378  status.error_vertex_keys++;
1379  continue;
1380  }
1381 
1382  if (!ED_curve_select_check(v3d, oldcu->editnurb)) {
1383  status.unselected++;
1384  continue;
1385  }
1386 
1387  /* 1. Duplicate geometry and check for valid selection for separate. */
1388  adduplicateflagNurb(oldob, v3d, &newnurb, SELECT, true);
1389 
1390  if (BLI_listbase_is_empty(&newnurb)) {
1391  status.error_generic++;
1392  continue;
1393  }
1394 
1395  /* 2. Duplicate the object and data. */
1396 
1397  /* Take into account user preferences for duplicating actions. */
1398  const eDupli_ID_Flags dupflag = (U.dupflag & USER_DUP_ACT);
1399 
1400  newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, dupflag);
1401  DEG_relations_tag_update(bmain);
1402 
1403  newob = newbase->object;
1404  newcu = newob->data = BKE_id_copy(bmain, &oldcu->id);
1405  newcu->editnurb = NULL;
1406  id_us_min(&oldcu->id); /* Because new curve is a copy: reduce user count. */
1407 
1408  /* 3. Put new object in editmode, clear it and set separated nurbs. */
1409  ED_curve_editnurb_make(newob);
1410  newedit = newcu->editnurb;
1411  BKE_nurbList_free(&newedit->nurbs);
1413  BLI_movelisttolist(&newedit->nurbs, &newnurb);
1414 
1415  /* 4. Put old object out of editmode and delete separated geometry. */
1416  ED_curve_editnurb_load(bmain, newob);
1417  ED_curve_editnurb_free(newob);
1418  curve_delete_segments(oldob, v3d, true);
1419 
1420  DEG_id_tag_update(&oldob->id, ID_RECALC_GEOMETRY); /* This is the original one. */
1421  DEG_id_tag_update(&newob->id, ID_RECALC_GEOMETRY); /* This is the separated one. */
1422 
1425  status.changed++;
1426  }
1427  MEM_freeN(bases);
1428  WM_cursor_wait(false);
1429 
1430  if (status.unselected == bases_len) {
1431  BKE_report(op->reports, RPT_ERROR, "No point was selected");
1432  return OPERATOR_CANCELLED;
1433  }
1434 
1435  const int tot_errors = status.error_vertex_keys + status.error_generic;
1436  if (tot_errors > 0) {
1437 
1438  /* Some curves changed, but some curves failed: don't explain why it failed. */
1439  if (status.changed) {
1440  BKE_reportf(op->reports,
1441  RPT_INFO,
1442  tot_errors == 1 ? "%d curve could not be separated" :
1443  "%d curves could not be separated",
1444  tot_errors);
1445  return OPERATOR_FINISHED;
1446  }
1447 
1448  /* All curves failed: If there is more than one error give a generic error report. */
1449  if (((status.error_vertex_keys ? 1 : 0) + (status.error_generic ? 1 : 0)) > 1) {
1450  BKE_report(op->reports,
1451  RPT_ERROR,
1452  tot_errors == 1 ? "Could not separate selected curves" :
1453  "Could not separate selected curve");
1454  }
1455 
1456  /* All curves failed due to the same error. */
1457  if (status.error_vertex_keys) {
1458  BKE_report(op->reports, RPT_ERROR, "Cannot separate curves with vertex keys");
1459  }
1460  else {
1461  BLI_assert(status.error_generic);
1462  BKE_report(op->reports, RPT_ERROR, "Cannot separate current selection");
1463  }
1464  return OPERATOR_CANCELLED;
1465  }
1466 
1468 
1469  return OPERATOR_FINISHED;
1470 }
1471 
1473 {
1474  /* identifiers */
1475  ot->name = "Separate";
1476  ot->idname = "CURVE_OT_separate";
1477  ot->description = "Separate selected points from connected unselected points into a new object";
1478 
1479  /* api callbacks */
1481  ot->exec = separate_exec;
1483 
1484  /* flags */
1486 }
1487 
1490 /* -------------------------------------------------------------------- */
1495 {
1496  Main *bmain = CTX_data_main(C);
1497  ViewLayer *view_layer = CTX_data_view_layer(C);
1498  View3D *v3d = CTX_wm_view3d(C);
1499  int ok = -1;
1500 
1501  uint objects_len;
1503  view_layer, CTX_wm_view3d(C), &objects_len);
1504  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1505  Object *obedit = objects[ob_index];
1506  Curve *cu = obedit->data;
1507 
1508  if (!ED_curve_select_check(v3d, cu->editnurb)) {
1509  continue;
1510  }
1511 
1512  ListBase newnurb = {NULL, NULL};
1513 
1514  adduplicateflagNurb(obedit, v3d, &newnurb, SELECT, true);
1515 
1516  if (BLI_listbase_is_empty(&newnurb)) {
1517  ok = MAX2(ok, 0);
1518  continue;
1519  }
1520 
1521  ListBase *editnurb = object_editcurve_get(obedit);
1522  const int len_orig = BLI_listbase_count(editnurb);
1523 
1524  curve_delete_segments(obedit, v3d, true);
1525  cu->actnu -= len_orig - BLI_listbase_count(editnurb);
1526  BLI_movelisttolist(editnurb, &newnurb);
1527 
1528  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
1530  }
1531 
1532  ok = 1;
1534  DEG_id_tag_update(obedit->data, 0);
1535  }
1536  MEM_freeN(objects);
1537 
1538  if (ok == 0) {
1539  BKE_report(op->reports, RPT_ERROR, "Cannot split current selection");
1540  return OPERATOR_CANCELLED;
1541  }
1542  return OPERATOR_FINISHED;
1543 }
1544 
1546 {
1547  /* identifiers */
1548  ot->name = "Split";
1549  ot->idname = "CURVE_OT_split";
1550  ot->description = "Split off selected points from connected unselected points";
1551 
1552  /* api callbacks */
1555 
1556  /* flags */
1558 }
1559 
1562 /* -------------------------------------------------------------------- */
1566 static bool isNurbselUV(const Nurb *nu, uint8_t flag, int *r_u, int *r_v)
1567 {
1568  /* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv
1569  * return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu
1570  */
1571  BPoint *bp;
1572  int a, b, sel;
1573 
1574  *r_u = *r_v = -1;
1575 
1576  bp = nu->bp;
1577  for (b = 0; b < nu->pntsv; b++) {
1578  sel = 0;
1579  for (a = 0; a < nu->pntsu; a++, bp++) {
1580  if (bp->f1 & flag) {
1581  sel++;
1582  }
1583  }
1584  if (sel == nu->pntsu) {
1585  if (*r_u == -1) {
1586  *r_u = b;
1587  }
1588  else {
1589  return 0;
1590  }
1591  }
1592  else if (sel > 1) {
1593  return 0; /* because sel == 1 is still ok */
1594  }
1595  }
1596 
1597  for (a = 0; a < nu->pntsu; a++) {
1598  sel = 0;
1599  bp = &nu->bp[a];
1600  for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1601  if (bp->f1 & flag) {
1602  sel++;
1603  }
1604  }
1605  if (sel == nu->pntsv) {
1606  if (*r_v == -1) {
1607  *r_v = a;
1608  }
1609  else {
1610  return 0;
1611  }
1612  }
1613  else if (sel > 1) {
1614  return 0;
1615  }
1616  }
1617 
1618  if (*r_u == -1 && *r_v > -1) {
1619  return 1;
1620  }
1621  if (*r_v == -1 && *r_u > -1) {
1622  return 1;
1623  }
1624  return 0;
1625 }
1626 
1627 /* return true if U direction is selected and number of selected columns v */
1628 static bool isNurbselU(Nurb *nu, int *v, int flag)
1629 {
1630  BPoint *bp;
1631  int a, b, sel;
1632 
1633  *v = 0;
1634 
1635  for (b = 0, bp = nu->bp; b < nu->pntsv; b++) {
1636  sel = 0;
1637  for (a = 0; a < nu->pntsu; a++, bp++) {
1638  if (bp->f1 & flag) {
1639  sel++;
1640  }
1641  }
1642  if (sel == nu->pntsu) {
1643  (*v)++;
1644  }
1645  else if (sel >= 1) {
1646  *v = 0;
1647  return 0;
1648  }
1649  }
1650 
1651  return 1;
1652 }
1653 
1654 /* return true if V direction is selected and number of selected rows u */
1655 static bool isNurbselV(Nurb *nu, int *u, int flag)
1656 {
1657  BPoint *bp;
1658  int a, b, sel;
1659 
1660  *u = 0;
1661 
1662  for (a = 0; a < nu->pntsu; a++) {
1663  bp = &nu->bp[a];
1664  sel = 0;
1665  for (b = 0; b < nu->pntsv; b++, bp += nu->pntsu) {
1666  if (bp->f1 & flag) {
1667  sel++;
1668  }
1669  }
1670  if (sel == nu->pntsv) {
1671  (*u)++;
1672  }
1673  else if (sel >= 1) {
1674  *u = 0;
1675  return 0;
1676  }
1677  }
1678 
1679  return 1;
1680 }
1681 
1682 static void rotateflagNurb(ListBase *editnurb,
1683  short flag,
1684  const float cent[3],
1685  const float rotmat[3][3])
1686 {
1687  /* all verts with (flag & 'flag') rotate */
1688  BPoint *bp;
1689  int a;
1690 
1691  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1692  if (nu->type == CU_NURBS) {
1693  bp = nu->bp;
1694  a = nu->pntsu * nu->pntsv;
1695 
1696  while (a--) {
1697  if (bp->f1 & flag) {
1698  sub_v3_v3(bp->vec, cent);
1699  mul_m3_v3(rotmat, bp->vec);
1700  add_v3_v3(bp->vec, cent);
1701  }
1702  bp++;
1703  }
1704  }
1705  }
1706 }
1707 
1708 void ed_editnurb_translate_flag(ListBase *editnurb, uint8_t flag, const float vec[3], bool is_2d)
1709 {
1710  /* all verts with ('flag' & flag) translate */
1711  BezTriple *bezt;
1712  BPoint *bp;
1713  int a;
1714 
1715  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1716  if (nu->type == CU_BEZIER) {
1717  a = nu->pntsu;
1718  bezt = nu->bezt;
1719  while (a--) {
1720  if (bezt->f1 & flag) {
1721  add_v3_v3(bezt->vec[0], vec);
1722  }
1723  if (bezt->f2 & flag) {
1724  add_v3_v3(bezt->vec[1], vec);
1725  }
1726  if (bezt->f3 & flag) {
1727  add_v3_v3(bezt->vec[2], vec);
1728  }
1729  bezt++;
1730  }
1731  }
1732  else {
1733  a = nu->pntsu * nu->pntsv;
1734  bp = nu->bp;
1735  while (a--) {
1736  if (bp->f1 & flag) {
1737  add_v3_v3(bp->vec, vec);
1738  }
1739  bp++;
1740  }
1741  }
1742 
1743  if (is_2d) {
1744  BKE_nurb_project_2d(nu);
1745  }
1746  }
1747 }
1748 
1749 static void weightflagNurb(ListBase *editnurb, short flag, float w)
1750 {
1751  BPoint *bp;
1752  int a;
1753 
1754  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
1755  if (nu->type == CU_NURBS) {
1756  a = nu->pntsu * nu->pntsv;
1757  bp = nu->bp;
1758  while (a--) {
1759  if (bp->f1 & flag) {
1760  /* a mode used to exist for replace/multiple but is was unused */
1761  bp->vec[3] *= w;
1762  }
1763  bp++;
1764  }
1765  }
1766  }
1767 }
1768 
1769 static void ed_surf_delete_selected(Object *obedit)
1770 {
1771  Curve *cu = obedit->data;
1772  ListBase *editnurb = object_editcurve_get(obedit);
1773  BPoint *bp, *bpn, *newbp;
1774  int a, b, newu, newv;
1775 
1776  BLI_assert(obedit->type == OB_SURF);
1777 
1778  LISTBASE_FOREACH_MUTABLE (Nurb *, nu, editnurb) {
1779  /* is entire nurb selected */
1780  bp = nu->bp;
1781  a = nu->pntsu * nu->pntsv;
1782  while (a) {
1783  a--;
1784  if (bp->f1 & SELECT) {
1785  /* pass */
1786  }
1787  else {
1788  break;
1789  }
1790  bp++;
1791  }
1792  if (a == 0) {
1793  BLI_remlink(editnurb, nu);
1794  keyIndex_delNurb(cu->editnurb, nu);
1795  BKE_nurb_free(nu);
1796  nu = NULL;
1797  }
1798  else {
1799  if (isNurbselU(nu, &newv, SELECT)) {
1800  /* U direction selected */
1801  newv = nu->pntsv - newv;
1802  if (newv != nu->pntsv) {
1803  /* delete */
1804  bp = nu->bp;
1805  bpn = newbp = (BPoint *)MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
1806  for (b = 0; b < nu->pntsv; b++) {
1807  if ((bp->f1 & SELECT) == 0) {
1808  memcpy(bpn, bp, nu->pntsu * sizeof(BPoint));
1809  keyIndex_updateBP(cu->editnurb, bp, bpn, nu->pntsu);
1810  bpn += nu->pntsu;
1811  }
1812  else {
1813  keyIndex_delBP(cu->editnurb, bp);
1814  }
1815  bp += nu->pntsu;
1816  }
1817  nu->pntsv = newv;
1818  MEM_freeN(nu->bp);
1819  nu->bp = newbp;
1821 
1823  }
1824  }
1825  else if (isNurbselV(nu, &newu, SELECT)) {
1826  /* V direction selected */
1827  newu = nu->pntsu - newu;
1828  if (newu != nu->pntsu) {
1829  /* delete */
1830  bp = nu->bp;
1831  bpn = newbp = (BPoint *)MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
1832  for (b = 0; b < nu->pntsv; b++) {
1833  for (a = 0; a < nu->pntsu; a++, bp++) {
1834  if ((bp->f1 & SELECT) == 0) {
1835  *bpn = *bp;
1836  keyIndex_updateBP(cu->editnurb, bp, bpn, 1);
1837  bpn++;
1838  }
1839  else {
1840  keyIndex_delBP(cu->editnurb, bp);
1841  }
1842  }
1843  }
1844  MEM_freeN(nu->bp);
1845  nu->bp = newbp;
1846  if (newu == 1 && nu->pntsv > 1) { /* make a U spline */
1847  nu->pntsu = nu->pntsv;
1848  nu->pntsv = 1;
1849  SWAP(short, nu->orderu, nu->orderv);
1851  if (nu->knotsv) {
1852  MEM_freeN(nu->knotsv);
1853  }
1854  nu->knotsv = NULL;
1855  }
1856  else {
1857  nu->pntsu = newu;
1859  }
1861  }
1862  }
1863  }
1864  }
1865 }
1866 
1867 static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
1868 {
1869  Curve *cu = obedit->data;
1870  EditNurb *editnurb = cu->editnurb;
1871  ListBase *nubase = &editnurb->nurbs;
1872  BezTriple *bezt, *bezt1;
1873  BPoint *bp, *bp1;
1874  int a, type, nuindex = 0;
1875 
1876  /* first loop, can we remove entire pieces? */
1877  LISTBASE_FOREACH_MUTABLE (Nurb *, nu, nubase) {
1878  if (nu->type == CU_BEZIER) {
1879  bezt = nu->bezt;
1880  a = nu->pntsu;
1881  if (a) {
1882  while (a) {
1883  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
1884  /* pass */
1885  }
1886  else {
1887  break;
1888  }
1889  a--;
1890  bezt++;
1891  }
1892  if (a == 0) {
1893  if (cu->actnu == nuindex) {
1894  cu->actnu = CU_ACT_NONE;
1895  }
1896 
1897  BLI_remlink(nubase, nu);
1898  keyIndex_delNurb(editnurb, nu);
1899  BKE_nurb_free(nu);
1900  nu = NULL;
1901  }
1902  }
1903  }
1904  else {
1905  bp = nu->bp;
1906  a = nu->pntsu * nu->pntsv;
1907  if (a) {
1908  while (a) {
1909  if (bp->f1 & SELECT) {
1910  /* pass */
1911  }
1912  else {
1913  break;
1914  }
1915  a--;
1916  bp++;
1917  }
1918  if (a == 0) {
1919  if (cu->actnu == nuindex) {
1920  cu->actnu = CU_ACT_NONE;
1921  }
1922 
1923  BLI_remlink(nubase, nu);
1924  keyIndex_delNurb(editnurb, nu);
1925  BKE_nurb_free(nu);
1926  nu = NULL;
1927  }
1928  }
1929  }
1930 
1931  /* Never allow the order to exceed the number of points
1932  * - note, this is ok but changes unselected nurbs, disable for now */
1933 #if 0
1934  if ((nu != NULL) && (nu->type == CU_NURBS)) {
1935  clamp_nurb_order_u(nu);
1936  }
1937 #endif
1938  nuindex++;
1939  }
1940  /* 2nd loop, delete small pieces: just for curves */
1941  LISTBASE_FOREACH_MUTABLE (Nurb *, nu, nubase) {
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;
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  }
2000  }
2001  }
2002 }
2003 
2004 /* only for OB_SURF */
2005 bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
2006 {
2007  BPoint *bp, *bpn, *newbp;
2008  int a, u, v, len;
2009  bool ok = false;
2010 
2011  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
2012  if (nu->pntsv == 1) {
2013  bp = nu->bp;
2014  a = nu->pntsu;
2015  while (a) {
2016  if (bp->f1 & flag) {
2017  /* pass */
2018  }
2019  else {
2020  break;
2021  }
2022  bp++;
2023  a--;
2024  }
2025  if (a == 0) {
2026  ok = true;
2027  newbp = (BPoint *)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
2028  ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
2029  bp = newbp + nu->pntsu;
2030  ED_curve_bpcpy(editnurb, bp, nu->bp, nu->pntsu);
2031  MEM_freeN(nu->bp);
2032  nu->bp = newbp;
2033  a = nu->pntsu;
2034  while (a--) {
2035  select_bpoint(bp, SELECT, flag, HIDDEN);
2036  select_bpoint(newbp, DESELECT, flag, HIDDEN);
2037  bp++;
2038  newbp++;
2039  }
2040 
2041  nu->pntsv = 2;
2042  nu->orderv = 2;
2044  }
2045  }
2046  else {
2047  /* which row or column is selected */
2048 
2049  if (isNurbselUV(nu, flag, &u, &v)) {
2050 
2051  /* deselect all */
2052  bp = nu->bp;
2053  a = nu->pntsu * nu->pntsv;
2054  while (a--) {
2055  select_bpoint(bp, DESELECT, flag, HIDDEN);
2056  bp++;
2057  }
2058 
2059  if (ELEM(u, 0, nu->pntsv - 1)) { /* row in u-direction selected */
2060  ok = true;
2061  newbp = (BPoint *)MEM_mallocN(nu->pntsu * (nu->pntsv + 1) * sizeof(BPoint),
2062  "extrudeNurb1");
2063  if (u == 0) {
2064  len = nu->pntsv * nu->pntsu;
2065  ED_curve_bpcpy(editnurb, newbp + nu->pntsu, nu->bp, len);
2066  ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
2067  bp = newbp;
2068  }
2069  else {
2070  len = nu->pntsv * nu->pntsu;
2071  ED_curve_bpcpy(editnurb, newbp, nu->bp, len);
2072  ED_curve_bpcpy(editnurb, newbp + len, &nu->bp[len - nu->pntsu], nu->pntsu);
2073  bp = newbp + len;
2074  }
2075 
2076  a = nu->pntsu;
2077  while (a--) {
2078  select_bpoint(bp, SELECT, flag, HIDDEN);
2079  bp++;
2080  }
2081 
2082  MEM_freeN(nu->bp);
2083  nu->bp = newbp;
2084  nu->pntsv++;
2086  }
2087  else if (ELEM(v, 0, nu->pntsu - 1)) { /* column in v-direction selected */
2088  ok = true;
2089  bpn = newbp = (BPoint *)MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint),
2090  "extrudeNurb1");
2091  bp = nu->bp;
2092 
2093  for (a = 0; a < nu->pntsv; a++) {
2094  if (v == 0) {
2095  *bpn = *bp;
2096  bpn->f1 |= flag;
2097  bpn++;
2098  }
2099  ED_curve_bpcpy(editnurb, bpn, bp, nu->pntsu);
2100  bp += nu->pntsu;
2101  bpn += nu->pntsu;
2102  if (v == nu->pntsu - 1) {
2103  *bpn = *(bp - 1);
2104  bpn->f1 |= flag;
2105  bpn++;
2106  }
2107  }
2108 
2109  MEM_freeN(nu->bp);
2110  nu->bp = newbp;
2111  nu->pntsu++;
2113  }
2114  }
2115  }
2116  }
2117 
2118  return ok;
2119 }
2120 
2121 static void calc_duplicate_actnurb(const ListBase *editnurb, const ListBase *newnurb, Curve *cu)
2122 {
2123  cu->actnu = BLI_listbase_count(editnurb) + BLI_listbase_count(newnurb);
2124 }
2125 
2127  const ListBase *editnurb, const ListBase *newnurb, Curve *cu, int start, int end, int vert)
2128 {
2129  if (cu->actvert == -1) {
2130  calc_duplicate_actnurb(editnurb, newnurb, cu);
2131  return true;
2132  }
2133 
2134  if ((start <= cu->actvert) && (end > cu->actvert)) {
2135  calc_duplicate_actnurb(editnurb, newnurb, cu);
2136  cu->actvert = vert;
2137  return true;
2138  }
2139  return false;
2140 }
2141 
2143  Object *obedit, View3D *v3d, ListBase *newnurb, const uint8_t flag, const bool split)
2144 {
2145  ListBase *editnurb = object_editcurve_get(obedit);
2146  Nurb *newnu;
2147  BezTriple *bezt, *bezt1;
2148  BPoint *bp, *bp1, *bp2, *bp3;
2149  Curve *cu = (Curve *)obedit->data;
2150  int a, b, c, starta, enda, diffa, cyclicu, cyclicv, newu, newv;
2151  char *usel;
2152 
2153  int i = 0;
2154  LISTBASE_FOREACH_INDEX (Nurb *, nu, editnurb, i) {
2155  cyclicu = cyclicv = 0;
2156  if (nu->type == CU_BEZIER) {
2157  for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
2158  enda = -1;
2159  starta = a;
2160  while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) {
2161  if (!split) {
2162  select_beztriple(bezt, DESELECT, flag, HIDDEN);
2163  }
2164  enda = a;
2165  if (a >= nu->pntsu - 1) {
2166  break;
2167  }
2168  a++;
2169  bezt++;
2170  }
2171  if (enda >= starta) {
2172  newu = diffa = enda - starta + 1; /* set newu and diffa, may use both */
2173 
2174  if (starta == 0 && newu != nu->pntsu && (nu->flagu & CU_NURB_CYCLIC)) {
2175  cyclicu = newu;
2176  }
2177  else {
2178  if (enda == nu->pntsu - 1) {
2179  newu += cyclicu;
2180  }
2181  if (i == cu->actnu) {
2183  editnurb, newnurb, cu, starta, starta + diffa, cu->actvert - starta);
2184  }
2185 
2186  newnu = BKE_nurb_copy(nu, newu, 1);
2187  memcpy(newnu->bezt, &nu->bezt[starta], diffa * sizeof(BezTriple));
2188  if (newu != diffa) {
2189  memcpy(&newnu->bezt[diffa], nu->bezt, cyclicu * sizeof(BezTriple));
2190  if (i == cu->actnu) {
2192  editnurb, newnurb, cu, 0, cyclicu, newu - cyclicu + cu->actvert);
2193  }
2194  cyclicu = 0;
2195  }
2196 
2197  if (newu != nu->pntsu) {
2198  newnu->flagu &= ~CU_NURB_CYCLIC;
2199  }
2200 
2201  for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
2202  select_beztriple(bezt1, SELECT, flag, HIDDEN);
2203  }
2204 
2205  BLI_addtail(newnurb, newnu);
2206  }
2207  }
2208  }
2209 
2210  if (cyclicu != 0) {
2211  if (i == cu->actnu) {
2212  calc_duplicate_actvert(editnurb, newnurb, cu, 0, cyclicu, cu->actvert);
2213  }
2214 
2215  newnu = BKE_nurb_copy(nu, cyclicu, 1);
2216  memcpy(newnu->bezt, nu->bezt, cyclicu * sizeof(BezTriple));
2217  newnu->flagu &= ~CU_NURB_CYCLIC;
2218 
2219  for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
2220  select_beztriple(bezt1, SELECT, flag, HIDDEN);
2221  }
2222 
2223  BLI_addtail(newnurb, newnu);
2224  }
2225  }
2226  else if (nu->pntsv == 1) { /* because UV Nurb has a different method for dupli */
2227  for (a = 0, bp = nu->bp; a < nu->pntsu; a++, bp++) {
2228  enda = -1;
2229  starta = a;
2230  while (bp->f1 & flag) {
2231  if (!split) {
2232  select_bpoint(bp, DESELECT, flag, HIDDEN);
2233  }
2234  enda = a;
2235  if (a >= nu->pntsu - 1) {
2236  break;
2237  }
2238  a++;
2239  bp++;
2240  }
2241  if (enda >= starta) {
2242  newu = diffa = enda - starta + 1; /* set newu and diffa, may use both */
2243 
2244  if (starta == 0 && newu != nu->pntsu && (nu->flagu & CU_NURB_CYCLIC)) {
2245  cyclicu = newu;
2246  }
2247  else {
2248  if (enda == nu->pntsu - 1) {
2249  newu += cyclicu;
2250  }
2251  if (i == cu->actnu) {
2253  editnurb, newnurb, cu, starta, starta + diffa, cu->actvert - starta);
2254  }
2255 
2256  newnu = BKE_nurb_copy(nu, newu, 1);
2257  memcpy(newnu->bp, &nu->bp[starta], diffa * sizeof(BPoint));
2258  if (newu != diffa) {
2259  memcpy(&newnu->bp[diffa], nu->bp, cyclicu * sizeof(BPoint));
2260  if (i == cu->actnu) {
2262  editnurb, newnurb, cu, 0, cyclicu, newu - cyclicu + cu->actvert);
2263  }
2264  cyclicu = 0;
2265  }
2266 
2267  if (newu != nu->pntsu) {
2268  newnu->flagu &= ~CU_NURB_CYCLIC;
2269  }
2270 
2271  for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
2272  select_bpoint(bp1, SELECT, flag, HIDDEN);
2273  }
2274 
2275  BLI_addtail(newnurb, newnu);
2276  }
2277  }
2278  }
2279 
2280  if (cyclicu != 0) {
2281  if (i == cu->actnu) {
2282  calc_duplicate_actvert(editnurb, newnurb, cu, 0, cyclicu, cu->actvert);
2283  }
2284 
2285  newnu = BKE_nurb_copy(nu, cyclicu, 1);
2286  memcpy(newnu->bp, nu->bp, cyclicu * sizeof(BPoint));
2287  newnu->flagu &= ~CU_NURB_CYCLIC;
2288 
2289  for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
2290  select_bpoint(bp1, SELECT, flag, HIDDEN);
2291  }
2292 
2293  BLI_addtail(newnurb, newnu);
2294  }
2295  }
2296  else {
2297  if (ED_curve_nurb_select_check(v3d, nu)) {
2298  /* A rectangular area in nurb has to be selected and if splitting
2299  * must be in U or V direction. */
2300  usel = MEM_callocN(nu->pntsu, "adduplicateN3");
2301  bp = nu->bp;
2302  for (a = 0; a < nu->pntsv; a++) {
2303  for (b = 0; b < nu->pntsu; b++, bp++) {
2304  if (bp->f1 & flag) {
2305  usel[b]++;
2306  }
2307  }
2308  }
2309  newu = 0;
2310  newv = 0;
2311  for (a = 0; a < nu->pntsu; a++) {
2312  if (usel[a]) {
2313  if (ELEM(newv, 0, usel[a])) {
2314  newv = usel[a];
2315  newu++;
2316  }
2317  else {
2318  newv = 0;
2319  break;
2320  }
2321  }
2322  }
2323  MEM_freeN(usel);
2324 
2325  if ((newu == 0 || newv == 0) ||
2326  (split && !isNurbselU(nu, &newv, SELECT) && !isNurbselV(nu, &newu, SELECT))) {
2327  if (G.debug & G_DEBUG) {
2328  printf("Can't duplicate Nurb\n");
2329  }
2330  }
2331  else {
2332  for (a = 0, bp1 = nu->bp; a < nu->pntsu * nu->pntsv; a++, bp1++) {
2333  newv = newu = 0;
2334 
2335  if ((bp1->f1 & flag) && !(bp1->f1 & SURF_SEEN)) {
2336  /* point selected, now loop over points in U and V directions */
2337  for (b = a % nu->pntsu, bp2 = bp1; b < nu->pntsu; b++, bp2++) {
2338  if (bp2->f1 & flag) {
2339  newu++;
2340  for (c = a / nu->pntsu, bp3 = bp2; c < nu->pntsv; c++, bp3 += nu->pntsu) {
2341  if (bp3->f1 & flag) {
2342  /* flag as seen so skipped on future iterations */
2343  bp3->f1 |= SURF_SEEN;
2344  if (newu == 1) {
2345  newv++;
2346  }
2347  }
2348  else {
2349  break;
2350  }
2351  }
2352  }
2353  else {
2354  break;
2355  }
2356  }
2357  }
2358 
2359  if ((newu + newv) > 2) {
2360  /* ignore single points */
2361  if (a == 0) {
2362  /* check if need to save cyclic selection and continue if so */
2363  if (newu == nu->pntsu && (nu->flagv & CU_NURB_CYCLIC)) {
2364  cyclicv = newv;
2365  }
2366  if (newv == nu->pntsv && (nu->flagu & CU_NURB_CYCLIC)) {
2367  cyclicu = newu;
2368  }
2369  if (cyclicu != 0 || cyclicv != 0) {
2370  continue;
2371  }
2372  }
2373 
2374  if (a + newu == nu->pntsu && cyclicu != 0) {
2375  /* cyclic in U direction */
2376  newnu = BKE_nurb_copy(nu, newu + cyclicu, newv);
2377  for (b = 0; b < newv; b++) {
2378  memcpy(&newnu->bp[b * newnu->pntsu],
2379  &nu->bp[b * nu->pntsu + a],
2380  newu * sizeof(BPoint));
2381  memcpy(&newnu->bp[b * newnu->pntsu + newu],
2382  &nu->bp[b * nu->pntsu],
2383  cyclicu * sizeof(BPoint));
2384  }
2385 
2386  if (cu->actnu == i) {
2387  if (cu->actvert == -1) {
2388  calc_duplicate_actnurb(editnurb, newnurb, cu);
2389  }
2390  else {
2391  for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2392  starta = b * nu->pntsu + a;
2393  if (calc_duplicate_actvert(editnurb,
2394  newnurb,
2395  cu,
2396  cu->actvert,
2397  starta,
2398  cu->actvert % nu->pntsu + newu +
2399  b * newnu->pntsu)) {
2400  /* actvert in cyclicu selection */
2401  break;
2402  }
2403  if (calc_duplicate_actvert(editnurb,
2404  newnurb,
2405  cu,
2406  starta,
2407  starta + newu,
2408  cu->actvert - starta + b * newnu->pntsu)) {
2409  /* actvert in 'current' iteration selection */
2410  break;
2411  }
2412  }
2413  }
2414  }
2415  cyclicu = cyclicv = 0;
2416  }
2417  else if ((a / nu->pntsu) + newv == nu->pntsv && cyclicv != 0) {
2418  /* cyclic in V direction */
2419  newnu = BKE_nurb_copy(nu, newu, newv + cyclicv);
2420  memcpy(newnu->bp, &nu->bp[a], newu * newv * sizeof(BPoint));
2421  memcpy(&newnu->bp[newu * newv], nu->bp, newu * cyclicv * sizeof(BPoint));
2422 
2423  /* check for actvert in cyclicv selection */
2424  if (cu->actnu == i) {
2426  editnurb, newnurb, cu, cu->actvert, a, (newu * newv) + cu->actvert);
2427  }
2428  cyclicu = cyclicv = 0;
2429  }
2430  else {
2431  newnu = BKE_nurb_copy(nu, newu, newv);
2432  for (b = 0; b < newv; b++) {
2433  memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint));
2434  }
2435  }
2436 
2437  /* general case if not handled by cyclicu or cyclicv */
2438  if (cu->actnu == i) {
2439  if (cu->actvert == -1) {
2440  calc_duplicate_actnurb(editnurb, newnurb, cu);
2441  }
2442  else {
2443  for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2444  starta = b * nu->pntsu + a;
2445  if (calc_duplicate_actvert(editnurb,
2446  newnurb,
2447  cu,
2448  starta,
2449  starta + newu,
2450  cu->actvert - (a / nu->pntsu * nu->pntsu + diffa +
2451  (starta % nu->pntsu)))) {
2452  break;
2453  }
2454  }
2455  }
2456  }
2457  BLI_addtail(newnurb, newnu);
2458 
2459  if (newu != nu->pntsu) {
2460  newnu->flagu &= ~CU_NURB_CYCLIC;
2461  }
2462  if (newv != nu->pntsv) {
2463  newnu->flagv &= ~CU_NURB_CYCLIC;
2464  }
2465  }
2466  }
2467 
2468  if (cyclicu != 0 || cyclicv != 0) {
2469  /* copy start of a cyclic surface, or copying all selected points */
2470  newu = cyclicu == 0 ? nu->pntsu : cyclicu;
2471  newv = cyclicv == 0 ? nu->pntsv : cyclicv;
2472 
2473  newnu = BKE_nurb_copy(nu, newu, newv);
2474  for (b = 0; b < newv; b++) {
2475  memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu], newu * sizeof(BPoint));
2476  }
2477 
2478  /* Check for `actvert` in the unused cyclic-UV selection. */
2479  if (cu->actnu == i) {
2480  if (cu->actvert == -1) {
2481  calc_duplicate_actnurb(editnurb, newnurb, cu);
2482  }
2483  else {
2484  for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
2485  starta = b * nu->pntsu;
2486  if (calc_duplicate_actvert(editnurb,
2487  newnurb,
2488  cu,
2489  starta,
2490  starta + newu,
2491  cu->actvert - (diffa + (starta % nu->pntsu)))) {
2492  break;
2493  }
2494  }
2495  }
2496  }
2497  BLI_addtail(newnurb, newnu);
2498 
2499  if (newu != nu->pntsu) {
2500  newnu->flagu &= ~CU_NURB_CYCLIC;
2501  }
2502  if (newv != nu->pntsv) {
2503  newnu->flagv &= ~CU_NURB_CYCLIC;
2504  }
2505  }
2506 
2507  for (b = 0, bp1 = nu->bp; b < nu->pntsu * nu->pntsv; b++, bp1++) {
2508  bp1->f1 &= ~SURF_SEEN;
2509  if (!split) {
2510  select_bpoint(bp1, DESELECT, flag, HIDDEN);
2511  }
2512  }
2513  }
2514  }
2515  }
2516  }
2517 
2518  if (BLI_listbase_is_empty(newnurb) == false) {
2519  LISTBASE_FOREACH (Nurb *, nu, newnurb) {
2520  if (nu->type == CU_BEZIER) {
2521  if (split) {
2522  /* recalc first and last */
2523  BKE_nurb_handle_calc_simple(nu, &nu->bezt[0]);
2524  BKE_nurb_handle_calc_simple(nu, &nu->bezt[nu->pntsu - 1]);
2525  }
2526  }
2527  else {
2528  /* knots done after duplicate as pntsu may change */
2531 
2532  if (obedit->type == OB_SURF) {
2533  for (a = 0, bp = nu->bp; a < nu->pntsu * nu->pntsv; a++, bp++) {
2534  bp->f1 &= ~SURF_SEEN;
2535  }
2536 
2539  }
2540  }
2541  }
2542  }
2543 }
2544 
2547 /* -------------------------------------------------------------------- */
2552 {
2553  Main *bmain = CTX_data_main(C);
2554  ViewLayer *view_layer = CTX_data_view_layer(C);
2555  View3D *v3d = CTX_wm_view3d(C);
2556 
2557  uint objects_len;
2559  view_layer, CTX_wm_view3d(C), &objects_len);
2560  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2561  Object *obedit = objects[ob_index];
2562  Curve *cu = obedit->data;
2563 
2564  if (!ED_curve_select_check(v3d, cu->editnurb)) {
2565  continue;
2566  }
2567 
2568  EditNurb *editnurb = cu->editnurb;
2569 
2570  int i = 0;
2571  LISTBASE_FOREACH_INDEX (Nurb *, nu, &editnurb->nurbs, i) {
2572  if (ED_curve_nurb_select_check(v3d, nu)) {
2575  if ((i == cu->actnu) && (cu->actvert != CU_ACT_NONE)) {
2576  cu->actvert = (nu->pntsu - 1) - cu->actvert;
2577  }
2578  }
2579  }
2580 
2581  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
2583  }
2584 
2585  DEG_id_tag_update(obedit->data, 0);
2587  }
2588  MEM_freeN(objects);
2589  return OPERATOR_FINISHED;
2590 }
2591 
2593 {
2594  /* identifiers */
2595  ot->name = "Switch Direction";
2596  ot->description = "Switch direction of selected splines";
2597  ot->idname = "CURVE_OT_switch_direction";
2598 
2599  /* api callbacks */
2602 
2603  /* flags */
2605 }
2606 
2609 /* -------------------------------------------------------------------- */
2614 {
2615  ViewLayer *view_layer = CTX_data_view_layer(C);
2616  uint objects_len;
2618  view_layer, CTX_wm_view3d(C), &objects_len);
2619 
2620  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2621  Object *obedit = objects[ob_index];
2622  ListBase *editnurb = object_editcurve_get(obedit);
2623  BezTriple *bezt;
2624  BPoint *bp;
2625  float weight = RNA_float_get(op->ptr, "weight");
2626  int a;
2627 
2628  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2629  if (nu->bezt) {
2630  for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2631  if (bezt->f2 & SELECT) {
2632  bezt->weight = weight;
2633  }
2634  }
2635  }
2636  else if (nu->bp) {
2637  for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2638  if (bp->f1 & SELECT) {
2639  bp->weight = weight;
2640  }
2641  }
2642  }
2643  }
2644 
2645  DEG_id_tag_update(obedit->data, 0);
2647  }
2648 
2649  MEM_freeN(objects);
2650 
2651  return OPERATOR_FINISHED;
2652 }
2653 
2655 {
2656  /* identifiers */
2657  ot->name = "Set Goal Weight";
2658  ot->description = "Set softbody goal weight for selected points";
2659  ot->idname = "CURVE_OT_spline_weight_set";
2660 
2661  /* api callbacks */
2665 
2666  /* flags */
2668 
2669  /* properties */
2670  RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
2671 }
2672 
2675 /* -------------------------------------------------------------------- */
2680 {
2681  ViewLayer *view_layer = CTX_data_view_layer(C);
2682  uint objects_len;
2684  view_layer, CTX_wm_view3d(C), &objects_len);
2685 
2686  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2687  Object *obedit = objects[ob_index];
2688  ListBase *editnurb = object_editcurve_get(obedit);
2689  BezTriple *bezt;
2690  BPoint *bp;
2691  float radius = RNA_float_get(op->ptr, "radius");
2692  int a;
2693 
2694  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2695  if (nu->bezt) {
2696  for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) {
2697  if (bezt->f2 & SELECT) {
2698  bezt->radius = radius;
2699  }
2700  }
2701  }
2702  else if (nu->bp) {
2703  for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
2704  if (bp->f1 & SELECT) {
2705  bp->radius = radius;
2706  }
2707  }
2708  }
2709  }
2710 
2712  DEG_id_tag_update(obedit->data, 0);
2713  }
2714 
2715  MEM_freeN(objects);
2716 
2717  return OPERATOR_FINISHED;
2718 }
2719 
2721 {
2722  /* identifiers */
2723  ot->name = "Set Curve Radius";
2724  ot->description = "Set per-point radius which is used for bevel tapering";
2725  ot->idname = "CURVE_OT_radius_set";
2726 
2727  /* api callbacks */
2728  ot->exec = set_radius_exec;
2731 
2732  /* flags */
2734 
2735  /* properties */
2736  RNA_def_float(
2737  ot->srna, "radius", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.0001f, 10.0f);
2738 }
2739 
2742 /* -------------------------------------------------------------------- */
2746 static void smooth_single_bezt(BezTriple *bezt,
2747  const BezTriple *bezt_orig_prev,
2748  const BezTriple *bezt_orig_next,
2749  float factor)
2750 {
2751  BLI_assert(IN_RANGE_INCL(factor, 0.0f, 1.0f));
2752 
2753  for (int i = 0; i < 3; i++) {
2754  /* get single dimension pos of the mid handle */
2755  float val_old = bezt->vec[1][i];
2756 
2757  /* get the weights of the previous/next mid handles and calc offset */
2758  float val_new = (bezt_orig_prev->vec[1][i] * 0.5f) + (bezt_orig_next->vec[1][i] * 0.5f);
2759  float offset = (val_old * (1.0f - factor)) + (val_new * factor) - val_old;
2760 
2761  /* offset midpoint and 2 handles */
2762  bezt->vec[1][i] += offset;
2763  bezt->vec[0][i] += offset;
2764  bezt->vec[2][i] += offset;
2765  }
2766 }
2767 
2771 static void smooth_single_bp(BPoint *bp,
2772  const BPoint *bp_orig_prev,
2773  const BPoint *bp_orig_next,
2774  float factor)
2775 {
2776  BLI_assert(IN_RANGE_INCL(factor, 0.0f, 1.0f));
2777 
2778  for (int i = 0; i < 3; i++) {
2779  float val_old, val_new, offset;
2780 
2781  val_old = bp->vec[i];
2782  val_new = (bp_orig_prev->vec[i] * 0.5f) + (bp_orig_next->vec[i] * 0.5f);
2783  offset = (val_old * (1.0f - factor)) + (val_new * factor) - val_old;
2784 
2785  bp->vec[i] += offset;
2786  }
2787 }
2788 
2790 {
2791  const float factor = 1.0f / 6.0f;
2792  ViewLayer *view_layer = CTX_data_view_layer(C);
2793  uint objects_len;
2795  view_layer, CTX_wm_view3d(C), &objects_len);
2796 
2797  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2798  Object *obedit = objects[ob_index];
2799  ListBase *editnurb = object_editcurve_get(obedit);
2800 
2801  int a, a_end;
2802  bool changed = false;
2803 
2804  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2805  if (nu->bezt) {
2806  /* duplicate the curve to use in weight calculation */
2807  const BezTriple *bezt_orig = MEM_dupallocN(nu->bezt);
2808  BezTriple *bezt;
2809  changed = false;
2810 
2811  /* check whether its cyclic or not, and set initial & final conditions */
2812  if (nu->flagu & CU_NURB_CYCLIC) {
2813  a = 0;
2814  a_end = nu->pntsu;
2815  }
2816  else {
2817  a = 1;
2818  a_end = nu->pntsu - 1;
2819  }
2820 
2821  /* for all the curve points */
2822  for (; a < a_end; a++) {
2823  /* respect selection */
2824  bezt = &nu->bezt[a];
2825  if (bezt->f2 & SELECT) {
2826  const BezTriple *bezt_orig_prev, *bezt_orig_next;
2827 
2828  bezt_orig_prev = &bezt_orig[mod_i(a - 1, nu->pntsu)];
2829  bezt_orig_next = &bezt_orig[mod_i(a + 1, nu->pntsu)];
2830 
2831  smooth_single_bezt(bezt, bezt_orig_prev, bezt_orig_next, factor);
2832 
2833  changed = true;
2834  }
2835  }
2836  MEM_freeN((void *)bezt_orig);
2837  if (changed) {
2839  }
2840  }
2841  else if (nu->bp) {
2842  /* Same as above, keep these the same! */
2843  const BPoint *bp_orig = MEM_dupallocN(nu->bp);
2844  BPoint *bp;
2845 
2846  if (nu->flagu & CU_NURB_CYCLIC) {
2847  a = 0;
2848  a_end = nu->pntsu;
2849  }
2850  else {
2851  a = 1;
2852  a_end = nu->pntsu - 1;
2853  }
2854 
2855  for (; a < a_end; a++) {
2856  bp = &nu->bp[a];
2857  if (bp->f1 & SELECT) {
2858  const BPoint *bp_orig_prev, *bp_orig_next;
2859 
2860  bp_orig_prev = &bp_orig[mod_i(a - 1, nu->pntsu)];
2861  bp_orig_next = &bp_orig[mod_i(a + 1, nu->pntsu)];
2862 
2863  smooth_single_bp(bp, bp_orig_prev, bp_orig_next, factor);
2864  }
2865  }
2866  MEM_freeN((void *)bp_orig);
2867  }
2868  }
2869 
2871  DEG_id_tag_update(obedit->data, 0);
2872  }
2873 
2874  MEM_freeN(objects);
2875 
2876  return OPERATOR_FINISHED;
2877 }
2878 
2880 {
2881  /* identifiers */
2882  ot->name = "Smooth";
2883  ot->description = "Flatten angles of selected points";
2884  ot->idname = "CURVE_OT_smooth";
2885 
2886  /* api callbacks */
2887  ot->exec = smooth_exec;
2889 
2890  /* flags */
2892 }
2893 
2896 /* -------------------------------------------------------------------- */
2904 static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, const int bp_offset)
2905 {
2906  BezTriple *bezt;
2907  BPoint *bp;
2908  int a;
2909 
2910  /* use for smoothing */
2911  int last_sel;
2912  int start_sel, end_sel; /* selection indices, inclusive */
2913  float start_rad, end_rad, fac, range;
2914 
2915  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
2916  if (nu->bezt) {
2917 #define BEZT_VALUE(bezt) (*((float *)((char *)(bezt) + bezt_offsetof)))
2918 
2919  for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
2920  /* loop over selection segments of a curve, smooth each */
2921 
2922  /* Start BezTriple code,
2923  * this is duplicated below for points, make sure these functions stay in sync */
2924  start_sel = -1;
2925  for (bezt = &nu->bezt[last_sel], a = last_sel; a < nu->pntsu; a++, bezt++) {
2926  if (bezt->f2 & SELECT) {
2927  start_sel = a;
2928  break;
2929  }
2930  }
2931  /* in case there are no other selected verts */
2932  end_sel = start_sel;
2933  for (bezt = &nu->bezt[start_sel + 1], a = start_sel + 1; a < nu->pntsu; a++, bezt++) {
2934  if ((bezt->f2 & SELECT) == 0) {
2935  break;
2936  }
2937  end_sel = a;
2938  }
2939 
2940  if (start_sel == -1) {
2941  last_sel = nu->pntsu; /* next... */
2942  }
2943  else {
2944  last_sel = end_sel; /* before we modify it */
2945 
2946  /* now blend between start and end sel */
2947  start_rad = end_rad = FLT_MAX;
2948 
2949  if (start_sel == end_sel) {
2950  /* simple, only 1 point selected */
2951  if (start_sel > 0) {
2952  start_rad = BEZT_VALUE(&nu->bezt[start_sel - 1]);
2953  }
2954  if (end_sel != -1 && end_sel < nu->pntsu) {
2955  end_rad = BEZT_VALUE(&nu->bezt[start_sel + 1]);
2956  }
2957 
2958  if (start_rad != FLT_MAX && end_rad >= FLT_MAX) {
2959  BEZT_VALUE(&nu->bezt[start_sel]) = (start_rad + end_rad) / 2.0f;
2960  }
2961  else if (start_rad != FLT_MAX) {
2962  BEZT_VALUE(&nu->bezt[start_sel]) = start_rad;
2963  }
2964  else if (end_rad != FLT_MAX) {
2965  BEZT_VALUE(&nu->bezt[start_sel]) = end_rad;
2966  }
2967  }
2968  else {
2969  /* if endpoints selected, then use them */
2970  if (start_sel == 0) {
2971  start_rad = BEZT_VALUE(&nu->bezt[start_sel]);
2972  start_sel++; /* we don't want to edit the selected endpoint */
2973  }
2974  else {
2975  start_rad = BEZT_VALUE(&nu->bezt[start_sel - 1]);
2976  }
2977  if (end_sel == nu->pntsu - 1) {
2978  end_rad = BEZT_VALUE(&nu->bezt[end_sel]);
2979  end_sel--; /* we don't want to edit the selected endpoint */
2980  }
2981  else {
2982  end_rad = BEZT_VALUE(&nu->bezt[end_sel + 1]);
2983  }
2984 
2985  /* Now Blend between the points */
2986  range = (float)(end_sel - start_sel) + 2.0f;
2987  for (bezt = &nu->bezt[start_sel], a = start_sel; a <= end_sel; a++, bezt++) {
2988  fac = (float)(1 + a - start_sel) / range;
2989  BEZT_VALUE(bezt) = start_rad * (1.0f - fac) + end_rad * fac;
2990  }
2991  }
2992  }
2993  }
2994 #undef BEZT_VALUE
2995  }
2996  else if (nu->bp) {
2997 #define BP_VALUE(bp) (*((float *)((char *)(bp) + bp_offset)))
2998 
2999  /* Same as above, keep these the same! */
3000  for (last_sel = 0; last_sel < nu->pntsu; last_sel++) {
3001  /* loop over selection segments of a curve, smooth each */
3002 
3003  /* Start BezTriple code,
3004  * this is duplicated below for points, make sure these functions stay in sync */
3005  start_sel = -1;
3006  for (bp = &nu->bp[last_sel], a = last_sel; a < nu->pntsu; a++, bp++) {
3007  if (bp->f1 & SELECT) {
3008  start_sel = a;
3009  break;
3010  }
3011  }
3012  /* in case there are no other selected verts */
3013  end_sel = start_sel;
3014  for (bp = &nu->bp[start_sel + 1], a = start_sel + 1; a < nu->pntsu; a++, bp++) {
3015  if ((bp->f1 & SELECT) == 0) {
3016  break;
3017  }
3018  end_sel = a;
3019  }
3020 
3021  if (start_sel == -1) {
3022  last_sel = nu->pntsu; /* next... */
3023  }
3024  else {
3025  last_sel = end_sel; /* before we modify it */
3026 
3027  /* now blend between start and end sel */
3028  start_rad = end_rad = FLT_MAX;
3029 
3030  if (start_sel == end_sel) {
3031  /* simple, only 1 point selected */
3032  if (start_sel > 0) {
3033  start_rad = BP_VALUE(&nu->bp[start_sel - 1]);
3034  }
3035  if (end_sel != -1 && end_sel < nu->pntsu) {
3036  end_rad = BP_VALUE(&nu->bp[start_sel + 1]);
3037  }
3038 
3039  if (start_rad != FLT_MAX && end_rad != FLT_MAX) {
3040  BP_VALUE(&nu->bp[start_sel]) = (start_rad + end_rad) / 2;
3041  }
3042  else if (start_rad != FLT_MAX) {
3043  BP_VALUE(&nu->bp[start_sel]) = start_rad;
3044  }
3045  else if (end_rad != FLT_MAX) {
3046  BP_VALUE(&nu->bp[start_sel]) = end_rad;
3047  }
3048  }
3049  else {
3050  /* if endpoints selected, then use them */
3051  if (start_sel == 0) {
3052  start_rad = BP_VALUE(&nu->bp[start_sel]);
3053  start_sel++; /* we don't want to edit the selected endpoint */
3054  }
3055  else {
3056  start_rad = BP_VALUE(&nu->bp[start_sel - 1]);
3057  }
3058  if (end_sel == nu->pntsu - 1) {
3059  end_rad = BP_VALUE(&nu->bp[end_sel]);
3060  end_sel--; /* we don't want to edit the selected endpoint */
3061  }
3062  else {
3063  end_rad = BP_VALUE(&nu->bp[end_sel + 1]);
3064  }
3065 
3066  /* Now Blend between the points */
3067  range = (float)(end_sel - start_sel) + 2.0f;
3068  for (bp = &nu->bp[start_sel], a = start_sel; a <= end_sel; a++, bp++) {
3069  fac = (float)(1 + a - start_sel) / range;
3070  BP_VALUE(bp) = start_rad * (1.0f - fac) + end_rad * fac;
3071  }
3072  }
3073  }
3074  }
3075 #undef BP_VALUE
3076  }
3077  }
3078 }
3079 
3082 /* -------------------------------------------------------------------- */
3087 {
3088  ViewLayer *view_layer = CTX_data_view_layer(C);
3089  uint objects_len;
3091  view_layer, CTX_wm_view3d(C), &objects_len);
3092 
3093  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3094  Object *obedit = objects[ob_index];
3095  ListBase *editnurb = object_editcurve_get(obedit);
3096 
3097  curve_smooth_value(editnurb, offsetof(BezTriple, weight), offsetof(BPoint, weight));
3098 
3100  DEG_id_tag_update(obedit->data, 0);
3101  }
3102 
3103  MEM_freeN(objects);
3104 
3105  return OPERATOR_FINISHED;
3106 }
3107 
3109 {
3110  /* identifiers */
3111  ot->name = "Smooth Curve Weight";
3112  ot->description = "Interpolate weight of selected points";
3113  ot->idname = "CURVE_OT_smooth_weight";
3114 
3115  /* api callbacks */
3118 
3119  /* flags */
3121 }
3122 
3125 /* -------------------------------------------------------------------- */
3130 {
3131  ViewLayer *view_layer = CTX_data_view_layer(C);
3132  uint objects_len;
3134  view_layer, CTX_wm_view3d(C), &objects_len);
3135 
3136  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3137  Object *obedit = objects[ob_index];
3138  ListBase *editnurb = object_editcurve_get(obedit);
3139 
3140  curve_smooth_value(editnurb, offsetof(BezTriple, radius), offsetof(BPoint, radius));
3141 
3143  DEG_id_tag_update(obedit->data, 0);
3144  }
3145 
3146  MEM_freeN(objects);
3147 
3148  return OPERATOR_FINISHED;
3149 }
3150 
3152 {
3153  /* identifiers */
3154  ot->name = "Smooth Curve Radius";
3155  ot->description = "Interpolate radii of selected points";
3156  ot->idname = "CURVE_OT_smooth_radius";
3157 
3158  /* api callbacks */
3161 
3162  /* flags */
3164 }
3165 
3168 /* -------------------------------------------------------------------- */
3173 {
3174  ViewLayer *view_layer = CTX_data_view_layer(C);
3175  uint objects_len;
3177  view_layer, CTX_wm_view3d(C), &objects_len);
3178 
3179  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3180  Object *obedit = objects[ob_index];
3181  ListBase *editnurb = object_editcurve_get(obedit);
3182 
3183  curve_smooth_value(editnurb, offsetof(BezTriple, tilt), offsetof(BPoint, tilt));
3184 
3186  DEG_id_tag_update(obedit->data, 0);
3187  }
3188 
3189  MEM_freeN(objects);
3190 
3191  return OPERATOR_FINISHED;
3192 }
3193 
3195 {
3196  /* identifiers */
3197  ot->name = "Smooth Curve Tilt";
3198  ot->description = "Interpolate tilt of selected points";
3199  ot->idname = "CURVE_OT_smooth_tilt";
3200 
3201  /* api callbacks */
3204 
3205  /* flags */
3207 }
3208 
3211 /* -------------------------------------------------------------------- */
3215 static int hide_exec(bContext *C, wmOperator *op)
3216 {
3217  ViewLayer *view_layer = CTX_data_view_layer(C);
3218  View3D *v3d = CTX_wm_view3d(C);
3219 
3220  const bool invert = RNA_boolean_get(op->ptr, "unselected");
3221 
3222  uint objects_len;
3224  view_layer, CTX_wm_view3d(C), &objects_len);
3225  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3226  Object *obedit = objects[ob_index];
3227  Curve *cu = obedit->data;
3228 
3229  if (!(invert || ED_curve_select_check(v3d, cu->editnurb))) {
3230  continue;
3231  }
3232 
3233  ListBase *editnurb = object_editcurve_get(obedit);
3234  BPoint *bp;
3235  BezTriple *bezt;
3236  int a, sel;
3237 
3238  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
3239  if (nu->type == CU_BEZIER) {
3240  bezt = nu->bezt;
3241  a = nu->pntsu;
3242  sel = 0;
3243  while (a--) {
3244  if (invert == 0 && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
3246  bezt->hide = 1;
3247  }
3248  else if (invert && !BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
3250  bezt->hide = 1;
3251  }
3252  if (bezt->hide) {
3253  sel++;
3254  }
3255  bezt++;
3256  }
3257  if (sel == nu->pntsu) {
3258  nu->hide = 1;
3259  }
3260  }
3261  else {
3262  bp = nu->bp;
3263  a = nu->pntsu * nu->pntsv;
3264  sel = 0;
3265  while (a--) {
3266  if (invert == 0 && (bp->f1 & SELECT)) {
3268  bp->hide = 1;
3269  }
3270  else if (invert && (bp->f1 & SELECT) == 0) {
3272  bp->hide = 1;
3273  }
3274  if (bp->hide) {
3275  sel++;
3276  }
3277  bp++;
3278  }
3279  if (sel == nu->pntsu * nu->pntsv) {
3280  nu->hide = 1;
3281  }
3282  }
3283  }
3284 
3288  }
3289  MEM_freeN(objects);
3290  return OPERATOR_FINISHED;
3291 }
3292 
3294 {
3295  /* identifiers */
3296  ot->name = "Hide Selected";
3297  ot->idname = "CURVE_OT_hide";
3298  ot->description = "Hide (un)selected control points";
3299 
3300  /* api callbacks */
3301  ot->exec = hide_exec;
3303 
3304  /* flags */
3306 
3307  /* props */
3308  RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
3309 }
3310 
3313 /* -------------------------------------------------------------------- */
3318 {
3319  ViewLayer *view_layer = CTX_data_view_layer(C);
3320  const bool select = RNA_boolean_get(op->ptr, "select");
3321  bool changed_multi = false;
3322 
3323  uint objects_len;
3325  view_layer, CTX_wm_view3d(C), &objects_len);
3326  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3327  Object *obedit = objects[ob_index];
3328  ListBase *editnurb = object_editcurve_get(obedit);
3329  BPoint *bp;
3330  BezTriple *bezt;
3331  int a;
3332  bool changed = false;
3333 
3334  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
3335  nu->hide = 0;
3336  if (nu->type == CU_BEZIER) {
3337  bezt = nu->bezt;
3338  a = nu->pntsu;
3339  while (a--) {
3340  if (bezt->hide) {
3342  bezt->hide = 0;
3343  changed = true;
3344  }
3345  bezt++;
3346  }
3347  }
3348  else {
3349  bp = nu->bp;
3350  a = nu->pntsu * nu->pntsv;
3351  while (a--) {
3352  if (bp->hide) {
3354  bp->hide = 0;
3355  changed = true;
3356  }
3357  bp++;
3358  }
3359  }
3360  }
3361 
3362  if (changed) {
3363  DEG_id_tag_update(obedit->data,
3366  changed_multi = true;
3367  }
3368  }
3369  MEM_freeN(objects);
3370  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3371 }
3372 
3374 {
3375  /* identifiers */
3376  ot->name = "Reveal Hidden";
3377  ot->idname = "CURVE_OT_reveal";
3378  ot->description = "Reveal hidden control points";
3379 
3380  /* api callbacks */
3381  ot->exec = reveal_exec;
3383 
3384  /* flags */
3386 
3387  RNA_def_boolean(ot->srna, "select", true, "Select", "");
3388 }
3389 
3392 /* -------------------------------------------------------------------- */
3401 static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts)
3402 {
3403  Curve *cu = obedit->data;
3404  EditNurb *editnurb = cu->editnurb;
3405  BezTriple *bezt, *beztnew, *beztn;
3406  BPoint *bp, *prevbp, *bpnew, *bpn;
3407  float vec[15];
3408  int a, b, sel, amount, *usel, *vsel;
3409  float factor;
3410 
3411  // printf("*** subdivideNurb: entering subdivide\n");
3412 
3413  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
3414  amount = 0;
3415  if (nu->type == CU_BEZIER) {
3416  BezTriple *nextbezt;
3417 
3418  /*
3419  * Insert a point into a 2D Bezier curve.
3420  * Endpoints are preserved. Otherwise, all selected and inserted points are
3421  * newly created. Old points are discarded.
3422  */
3423  /* count */
3424  a = nu->pntsu;
3425  bezt = nu->bezt;
3426  while (a--) {
3427  nextbezt = BKE_nurb_bezt_get_next(nu, bezt);
3428  if (nextbezt == NULL) {
3429  break;
3430  }
3431 
3432  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) &&
3433  BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nextbezt)) {
3434  amount += number_cuts;
3435  }
3436  bezt++;
3437  }
3438 
3439  if (amount) {
3440  /* insert */
3441  beztnew = (BezTriple *)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
3442  beztn = beztnew;
3443  a = nu->pntsu;
3444  bezt = nu->bezt;
3445  while (a--) {
3446  memcpy(beztn, bezt, sizeof(BezTriple));
3447  keyIndex_updateBezt(editnurb, bezt, beztn, 1);
3448  beztn++;
3449 
3450  nextbezt = BKE_nurb_bezt_get_next(nu, bezt);
3451  if (nextbezt == NULL) {
3452  break;
3453  }
3454 
3455  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) &&
3456  BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nextbezt)) {
3457  float prevvec[3][3];
3458 
3459  memcpy(prevvec, bezt->vec, sizeof(float[9]));
3460 
3461  for (int i = 0; i < number_cuts; i++) {
3462  factor = 1.0f / (number_cuts + 1 - i);
3463 
3464  memcpy(beztn, nextbezt, sizeof(BezTriple));
3465 
3466  /* midpoint subdividing */
3467  interp_v3_v3v3(vec, prevvec[1], prevvec[2], factor);
3468  interp_v3_v3v3(vec + 3, prevvec[2], nextbezt->vec[0], factor);
3469  interp_v3_v3v3(vec + 6, nextbezt->vec[0], nextbezt->vec[1], factor);
3470 
3471  interp_v3_v3v3(vec + 9, vec, vec + 3, factor);
3472  interp_v3_v3v3(vec + 12, vec + 3, vec + 6, factor);
3473 
3474  /* change handle of prev beztn */
3475  copy_v3_v3((beztn - 1)->vec[2], vec);
3476  /* new point */
3477  copy_v3_v3(beztn->vec[0], vec + 9);
3478  interp_v3_v3v3(beztn->vec[1], vec + 9, vec + 12, factor);
3479  copy_v3_v3(beztn->vec[2], vec + 12);
3480  /* handle of next bezt */
3481  if (a == 0 && i == number_cuts - 1 && (nu->flagu & CU_NURB_CYCLIC)) {
3482  copy_v3_v3(beztnew->vec[0], vec + 6);
3483  }
3484  else {
3485  copy_v3_v3(nextbezt->vec[0], vec + 6);
3486  }
3487 
3488  beztn->radius = (bezt->radius + nextbezt->radius) / 2;
3489  beztn->weight = (bezt->weight + nextbezt->weight) / 2;
3490 
3491  memcpy(prevvec, beztn->vec, sizeof(float[9]));
3492  beztn++;
3493  }
3494  }
3495 
3496  bezt++;
3497  }
3498 
3499  MEM_freeN(nu->bezt);
3500  nu->bezt = beztnew;
3501  nu->pntsu += amount;
3502 
3504  }
3505  } /* End of 'if (nu->type == CU_BEZIER)' */
3506  else if (nu->pntsv == 1) {
3507  BPoint *nextbp;
3508 
3509  /*
3510  * All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves
3511  * are handled together with the regular NURB plane division, as it
3512  * should be. I split it off just now, let's see if it is
3513  * stable... nzc 30-5-'00
3514  */
3515  /* count */
3516  a = nu->pntsu;
3517  bp = nu->bp;
3518  while (a--) {
3519  nextbp = BKE_nurb_bpoint_get_next(nu, bp);
3520  if (nextbp == NULL) {
3521  break;
3522  }
3523 
3524  if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) {
3525  amount += number_cuts;
3526  }
3527  bp++;
3528  }
3529 
3530  if (amount) {
3531  /* insert */
3532  bpnew = (BPoint *)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
3533  bpn = bpnew;
3534 
3535  a = nu->pntsu;
3536  bp = nu->bp;
3537 
3538  while (a--) {
3539  /* Copy "old" point. */
3540  memcpy(bpn, bp, sizeof(BPoint));
3541  keyIndex_updateBP(editnurb, bp, bpn, 1);
3542  bpn++;
3543 
3544  nextbp = BKE_nurb_bpoint_get_next(nu, bp);
3545  if (nextbp == NULL) {
3546  break;
3547  }
3548 
3549  if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) {
3550  // printf("*** subdivideNurb: insert 'linear' point\n");
3551  for (int i = 0; i < number_cuts; i++) {
3552  factor = (float)(i + 1) / (number_cuts + 1);
3553 
3554  memcpy(bpn, nextbp, sizeof(BPoint));
3555  interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor);
3556  bpn->radius = interpf(bp->radius, nextbp->radius, factor);
3557  bpn++;
3558  }
3559  }
3560  bp++;
3561  }
3562 
3563  MEM_freeN(nu->bp);
3564  nu->bp = bpnew;
3565  nu->pntsu += amount;
3566 
3567  if (nu->type & CU_NURBS) {
3569  }
3570  }
3571  } /* End of 'else if (nu->pntsv == 1)' */
3572  else if (nu->type == CU_NURBS) {
3573  /* This is a very strange test ... */
3614  /* selection-arrays */
3615  usel = MEM_callocN(sizeof(int) * nu->pntsu, "subivideNurb3");
3616  vsel = MEM_callocN(sizeof(int) * nu->pntsv, "subivideNurb3");
3617  sel = 0;
3618 
3619  /* Count the number of selected points. */
3620  bp = nu->bp;
3621  for (a = 0; a < nu->pntsv; a++) {
3622  for (b = 0; b < nu->pntsu; b++) {
3623  if (bp->f1 & SELECT) {
3624  usel[b]++;
3625  vsel[a]++;
3626  sel++;
3627  }
3628  bp++;
3629  }
3630  }
3631  if (sel == (nu->pntsu * nu->pntsv)) { /* subdivide entire nurb */
3632  /* Global subdivision is a special case of partial
3633  * subdivision. Strange it is considered separately... */
3634 
3635  /* count of nodes (after subdivision) along U axis */
3636  int countu = nu->pntsu + (nu->pntsu - 1) * number_cuts;
3637 
3638  /* total count of nodes after subdivision */
3639  int tot = ((number_cuts + 1) * nu->pntsu - number_cuts) *
3640  ((number_cuts + 1) * nu->pntsv - number_cuts);
3641 
3642  bpn = bpnew = MEM_mallocN(tot * sizeof(BPoint), "subdivideNurb4");
3643  bp = nu->bp;
3644  /* first subdivide rows */
3645  for (a = 0; a < nu->pntsv; a++) {
3646  for (b = 0; b < nu->pntsu; b++) {
3647  *bpn = *bp;
3648  keyIndex_updateBP(editnurb, bp, bpn, 1);
3649  bpn++;
3650  bp++;
3651  if (b < nu->pntsu - 1) {
3652  prevbp = bp - 1;
3653  for (int i = 0; i < number_cuts; i++) {
3654  factor = (float)(i + 1) / (number_cuts + 1);
3655  *bpn = *bp;
3656  interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
3657  bpn++;
3658  }
3659  }
3660  }
3661  bpn += number_cuts * countu;
3662  }
3663  /* now insert new */
3664  bpn = bpnew + ((number_cuts + 1) * nu->pntsu - number_cuts);
3665  bp = bpnew + (number_cuts + 1) * ((number_cuts + 1) * nu->pntsu - number_cuts);
3666  prevbp = bpnew;
3667  for (a = 1; a < nu->pntsv; a++) {
3668 
3669  for (b = 0; b < (number_cuts + 1) * nu->pntsu - number_cuts; b++) {
3670  BPoint *tmp = bpn;
3671  for (int i = 0; i < number_cuts; i++) {
3672  factor = (float)(i + 1) / (number_cuts + 1);
3673  *tmp = *bp;
3674  interp_v4_v4v4(tmp->vec, prevbp->vec, bp->vec, factor);
3675  tmp += countu;
3676  }
3677  bp++;
3678  prevbp++;
3679  bpn++;
3680  }
3681  bp += number_cuts * countu;
3682  bpn += number_cuts * countu;
3683  prevbp += number_cuts * countu;
3684  }
3685  MEM_freeN(nu->bp);
3686  nu->bp = bpnew;
3687  nu->pntsu = (number_cuts + 1) * nu->pntsu - number_cuts;
3688  nu->pntsv = (number_cuts + 1) * nu->pntsv - number_cuts;
3691  } /* End of 'if (sel == nu->pntsu * nu->pntsv)' (subdivide entire NURB) */
3692  else {
3693  /* subdivide in v direction? */
3694  sel = 0;
3695  for (a = 0; a < nu->pntsv - 1; a++) {
3696  if (vsel[a] == nu->pntsu && vsel[a + 1] == nu->pntsu) {
3697  sel += number_cuts;
3698  }
3699  }
3700 
3701  if (sel) { /* V ! */
3702  bpn = bpnew = MEM_mallocN((sel + nu->pntsv) * nu->pntsu * sizeof(BPoint),
3703  "subdivideNurb4");
3704  bp = nu->bp;
3705  for (a = 0; a < nu->pntsv; a++) {
3706  for (b = 0; b < nu->pntsu; b++) {
3707  *bpn = *bp;
3708  keyIndex_updateBP(editnurb, bp, bpn, 1);
3709  bpn++;
3710  bp++;
3711  }
3712  if ((a < nu->pntsv - 1) && vsel[a] == nu->pntsu && vsel[a + 1] == nu->pntsu) {
3713  for (int i = 0; i < number_cuts; i++) {
3714  factor = (float)(i + 1) / (number_cuts + 1);
3715  prevbp = bp - nu->pntsu;
3716  for (b = 0; b < nu->pntsu; b++) {
3717  /*
3718  * This simple bisection must be replaces by a
3719  * subtle resampling of a number of points. Our
3720  * task is made slightly easier because each
3721  * point in our curve is a separate data
3722  * node. (is it?)
3723  */
3724  *bpn = *prevbp;
3725  interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
3726  bpn++;
3727 
3728  prevbp++;
3729  bp++;
3730  }
3731  bp -= nu->pntsu;
3732  }
3733  }
3734  }
3735  MEM_freeN(nu->bp);
3736  nu->bp = bpnew;
3737  nu->pntsv += sel;
3739  }
3740  else {
3741  /* or in u direction? */
3742  sel = 0;
3743  for (a = 0; a < nu->pntsu - 1; a++) {
3744  if (usel[a] == nu->pntsv && usel[a + 1] == nu->pntsv) {
3745  sel += number_cuts;
3746  }
3747  }
3748 
3749  if (sel) { /* U ! */
3750  /* Inserting U points is sort of 'default' Flat curves only get */
3751  /* U points inserted in them. */
3752  bpn = bpnew = MEM_mallocN((sel + nu->pntsu) * nu->pntsv * sizeof(BPoint),
3753  "subdivideNurb4");
3754  bp = nu->bp;
3755  for (a = 0; a < nu->pntsv; a++) {
3756  for (b = 0; b < nu->pntsu; b++) {
3757  *bpn = *bp;
3758  keyIndex_updateBP(editnurb, bp, bpn, 1);
3759  bpn++;
3760  bp++;
3761  if ((b < nu->pntsu - 1) && usel[b] == nu->pntsv && usel[b + 1] == nu->pntsv) {
3762  /*
3763  * One thing that bugs me here is that the
3764  * orders of things are not the same as in
3765  * the JW piece. Also, this implies that we
3766  * handle at most 3rd order curves? I miss
3767  * some symmetry here...
3768  */
3769  for (int i = 0; i < number_cuts; i++) {
3770  factor = (float)(i + 1) / (number_cuts + 1);
3771  prevbp = bp - 1;
3772  *bpn = *prevbp;
3773  interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
3774  bpn++;
3775  }
3776  }
3777  }
3778  }
3779  MEM_freeN(nu->bp);
3780  nu->bp = bpnew;
3781  nu->pntsu += sel;
3782  BKE_nurb_knot_calc_u(nu); /* shift knots forward */
3783  }
3784  }
3785  }
3786  MEM_freeN(usel);
3787  MEM_freeN(vsel);
3788 
3789  } /* End of 'if (nu->type == CU_NURBS)' */
3790  }
3791 }
3792 
3794 {
3795  const int number_cuts = RNA_int_get(op->ptr, "number_cuts");
3796 
3797  Main *bmain = CTX_data_main(C);
3798  ViewLayer *view_layer = CTX_data_view_layer(C);
3799  View3D *v3d = CTX_wm_view3d(C);
3800 
3801  uint objects_len = 0;
3803  view_layer, CTX_wm_view3d(C), &objects_len);
3804  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3805  Object *obedit = objects[ob_index];
3806  Curve *cu = obedit->data;
3807 
3808  if (!ED_curve_select_check(v3d, cu->editnurb)) {
3809  continue;
3810  }
3811 
3812  subdividenurb(obedit, v3d, number_cuts);
3813 
3814  if (ED_curve_updateAnimPaths(bmain, cu)) {
3816  }
3817 
3819  DEG_id_tag_update(obedit->data, 0);
3820  }
3821  MEM_freeN(objects);
3822 
3823  return OPERATOR_FINISHED;
3824 }
3825 
3827 {
3828  PropertyRNA *prop;
3829 
3830  /* identifiers */
3831  ot->name = "Subdivide";
3832  ot->description = "Subdivide selected segments";
3833  ot->idname = "CURVE_OT_subdivide";
3834 
3835  /* api callbacks */
3836  ot->exec = subdivide_exec;
3838 
3839  /* flags */
3841 
3842  prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10);
3843  /* Avoid re-using last var because it can cause _very_ high poly meshes
3844  * and annoy users (or worse crash). */
3846 }
3847 
3850 /* -------------------------------------------------------------------- */
3855 {
3856  ViewLayer *view_layer = CTX_data_view_layer(C);
3857  uint objects_len;
3859  view_layer, CTX_wm_view3d(C), &objects_len);
3860  int ret_value = OPERATOR_CANCELLED;
3861 
3862  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3863  Object *obedit = objects[ob_index];
3864  Main *bmain = CTX_data_main(C);
3865  View3D *v3d = CTX_wm_view3d(C);
3866  ListBase *editnurb = object_editcurve_get(obedit);
3867  bool changed = false;
3868  bool changed_size = false;
3869  const bool use_handles = RNA_boolean_get(op->ptr, "use_handles");
3870  const int type = RNA_enum_get(op->ptr, "type");
3871 
3872  if (ELEM(type, CU_CARDINAL, CU_BSPLINE)) {
3873  BKE_report(op->reports, RPT_ERROR, "Not yet implemented");
3874  continue;
3875  }
3876 
3877  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
3878  if (ED_curve_nurb_select_check(v3d, nu)) {
3879  const int pntsu_prev = nu->pntsu;
3880  const char *err_msg = NULL;
3881  if (BKE_nurb_type_convert(nu, type, use_handles, &err_msg)) {
3882  changed = true;
3883  if (pntsu_prev != nu->pntsu) {
3884  changed_size = true;
3885  }
3886  }
3887  else {
3888  BKE_report(op->reports, RPT_ERROR, err_msg);
3889  }
3890  }
3891  }
3892 
3893  if (changed) {
3894  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
3896  }
3897 
3898  DEG_id_tag_update(obedit->data, 0);
3900 
3901  if (changed_size) {
3902  Curve *cu = obedit->data;
3903  cu->actvert = CU_ACT_NONE;
3904  }
3905 
3906  ret_value = OPERATOR_FINISHED;
3907  }
3908  }
3909 
3910  MEM_freeN(objects);
3911 
3912  return ret_value;
3913 }
3914 
3916 {
3917  static const EnumPropertyItem type_items[] = {
3918  {CU_POLY, "POLY", 0, "Poly", ""},
3919  {CU_BEZIER, "BEZIER", 0, "Bezier", ""},
3920  // {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
3921  // {CU_BSPLINE, "B_SPLINE", 0, "B-Spline", ""},
3922  {CU_NURBS, "NURBS", 0, "NURBS", ""},
3923  {0, NULL, 0, NULL, NULL},
3924  };
3925 
3926  /* identifiers */
3927  ot->name = "Set Spline Type";
3928  ot->description = "Set type of active spline";
3929  ot->idname = "CURVE_OT_spline_type_set";
3930 
3931  /* api callbacks */
3935 
3936  /* flags */
3938 
3939  /* properties */
3940  ot->prop = RNA_def_enum(ot->srna, "type", type_items, CU_POLY, "Type", "Spline type");
3942  "use_handles",
3943  0,
3944  "Handles",
3945  "Use handles when converting bezier curves into polygons");
3946 }
3947 
3950 /* -------------------------------------------------------------------- */
3955 {
3956  ViewLayer *view_layer = CTX_data_view_layer(C);
3957  View3D *v3d = CTX_wm_view3d(C);
3958  const int handle_type = RNA_enum_get(op->ptr, "type");
3959 
3960  uint objects_len;
3962  view_layer, CTX_wm_view3d(C), &objects_len);
3963  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3964  Object *obedit = objects[ob_index];
3965  Curve *cu = obedit->data;
3966 
3967  if (!ED_curve_select_check(v3d, cu->editnurb)) {
3968  continue;
3969  }
3970 
3971  ListBase *editnurb = object_editcurve_get(obedit);
3972  BKE_nurbList_handles_set(editnurb, handle_type);
3973 
3975  DEG_id_tag_update(obedit->data, 0);
3976  }
3977  MEM_freeN(objects);
3978  return OPERATOR_FINISHED;
3979 }
3980 
3982 {
3983  /* keep in sync with graphkeys_handle_type_items */
3984  static const EnumPropertyItem editcurve_handle_type_items[] = {
3985  {HD_AUTO, "AUTOMATIC", 0, "Automatic", ""},
3986  {HD_VECT, "VECTOR", 0, "Vector", ""},
3987  {5, "ALIGNED", 0, "Aligned", ""},
3988  {6, "FREE_ALIGN", 0, "Free", ""},
3989  {3, "TOGGLE_FREE_ALIGN", 0, "Toggle Free/Align", ""},
3990  {0, NULL, 0, NULL, NULL},
3991  };
3992 
3993  /* identifiers */
3994  ot->name = "Set Handle Type";
3995  ot->description = "Set type of handles for selected control points";
3996  ot->idname = "CURVE_OT_handle_type_set";
3997 
3998  /* api callbacks */
4002 
4003  /* flags */
4005 
4006  /* properties */
4007  ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
4008 }
4009 
4012 /* -------------------------------------------------------------------- */
4017 {
4018  ViewLayer *view_layer = CTX_data_view_layer(C);
4019  View3D *v3d = CTX_wm_view3d(C);
4020 
4021  const bool calc_length = RNA_boolean_get(op->ptr, "calc_length");
4022 
4023  uint objects_len;
4025  view_layer, CTX_wm_view3d(C), &objects_len);
4026  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4027  Object *obedit = objects[ob_index];
4028  Curve *cu = obedit->data;
4029 
4030  if (!ED_curve_select_check(v3d, cu->editnurb)) {
4031  continue;
4032  }
4033 
4034  ListBase *editnurb = object_editcurve_get(obedit);
4035  BKE_nurbList_handles_recalculate(editnurb, calc_length, SELECT);
4036 
4038  DEG_id_tag_update(obedit->data, 0);
4039  }
4040  MEM_freeN(objects);
4041  return OPERATOR_FINISHED;
4042 }
4043 
4045 {
4046  /* identifiers */
4047  ot->name = "Recalculate Handles";
4048  ot->description = "Recalculate the direction of selected handles";
4049  ot->idname = "CURVE_OT_normals_make_consistent";
4050 
4051  /* api callbacks */
4054 
4055  /* flags */
4057 
4058  /* props */
4059  RNA_def_boolean(ot->srna, "calc_length", false, "Length", "Recalculate handle length");
4060 }
4061 
4064 /* -------------------------------------------------------------------- */
4070 static void switchdirection_knots(float *base, int tot)
4071 {
4072  float *fp1, *fp2, *tempf;
4073  int a;
4074 
4075  if (base == NULL || tot == 0) {
4076  return;
4077  }
4078 
4079  /* reverse knots */
4080  a = tot;
4081  fp1 = base;
4082  fp2 = fp1 + (a - 1);
4083  a /= 2;
4084  while (fp1 != fp2 && a > 0) {
4085  SWAP(float, *fp1, *fp2);
4086  a--;
4087  fp1++;
4088  fp2--;
4089  }
4090 
4091  /* and make in increasing order again */
4092  a = tot - 1;
4093  fp1 = base;
4094  fp2 = tempf = MEM_mallocN(sizeof(float) * tot, "switchdirect");
4095  while (a--) {
4096  fp2[0] = fabsf(fp1[1] - fp1[0]);
4097  fp1++;
4098  fp2++;
4099  }
4100  fp2[0] = 0.0f;
4101 
4102  a = tot - 1;
4103  fp1 = base;
4104  fp2 = tempf;
4105  fp1[0] = 0.0;
4106  fp1++;
4107  while (a--) {
4108  fp1[0] = fp1[-1] + fp2[0];
4109  fp1++;
4110  fp2++;
4111  }
4112  MEM_freeN(tempf);
4113 }
4114 
4115 static void rotate_direction_nurb(Nurb *nu)
4116 {
4117  BPoint *bp1, *bp2, *temp;
4118  int u, v;
4119 
4120  SWAP(int, nu->pntsu, nu->pntsv);
4121  SWAP(short, nu->orderu, nu->orderv);
4122  SWAP(short, nu->resolu, nu->resolv);
4123  SWAP(short, nu->flagu, nu->flagv);
4124 
4125  SWAP(float *, nu->knotsu, nu->knotsv);
4127 
4128  temp = MEM_dupallocN(nu->bp);
4129  bp1 = nu->bp;
4130  for (v = 0; v < nu->pntsv; v++) {
4131  for (u = 0; u < nu->pntsu; u++, bp1++) {
4132  bp2 = temp + (nu->pntsu - u - 1) * (nu->pntsv) + v;
4133  *bp1 = *bp2;
4134  }
4135  }
4136 
4137  MEM_freeN(temp);
4138 }
4139 
4140 static bool is_u_selected(Nurb *nu, int u)
4141 {
4142  BPoint *bp;
4143  int v;
4144 
4145  /* what about resolu == 2? */
4146  bp = &nu->bp[u];
4147  for (v = 0; v < nu->pntsv - 1; v++, bp += nu->pntsu) {
4148  if ((v != 0) && (bp->f1 & SELECT)) {
4149  return true;
4150  }
4151  }
4152 
4153  return false;
4154 }
4155 
4156 typedef struct NurbSort {
4157  struct NurbSort *next, *prev;
4159  float vec[3];
4161 
4162 static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb, ListBase *nsortbase)
4163 {
4164  ListBase nbase = {NULL, NULL};
4165  NurbSort *nus, *nustest, *headdo, *taildo;
4166  BPoint *bp;
4167  float dist, headdist, taildist;
4168  int a;
4169 
4170  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4171  if (ED_curve_nurb_select_check(v3d, nu)) {
4172 
4173  nus = (NurbSort *)MEM_callocN(sizeof(NurbSort), "sort");
4174  BLI_addhead(&nbase, nus);
4175  nus->nu = nu;
4176 
4177  bp = nu->bp;
4178  a = nu->pntsu;
4179  while (a--) {
4180  add_v3_v3(nus->vec, bp->vec);
4181  bp++;
4182  }
4183  mul_v3_fl(nus->vec, 1.0f / (float)nu->pntsu);
4184  }
4185  }
4186 
4187  /* just add the first one */
4188  nus = nbase.first;
4189  BLI_remlink(&nbase, nus);
4190  BLI_addtail(nsortbase, nus);
4191 
4192  /* now add, either at head or tail, the closest one */
4193  while (nbase.first) {
4194 
4195  headdist = taildist = 1.0e30;
4196  headdo = taildo = NULL;
4197 
4198  nustest = nbase.first;
4199  while (nustest) {
4200  dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase->first)->vec);
4201 
4202  if (dist < headdist) {
4203  headdist = dist;
4204  headdo = nustest;
4205  }
4206  dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase->last)->vec);
4207 
4208  if (dist < taildist) {
4209  taildist = dist;
4210  taildo = nustest;
4211  }
4212  nustest = nustest->next;
4213  }
4214 
4215  if (headdist < taildist) {
4216  BLI_remlink(&nbase, headdo);
4217  BLI_addhead(nsortbase, headdo);
4218  }
4219  else {
4220  BLI_remlink(&nbase, taildo);
4221  BLI_addtail(nsortbase, taildo);
4222  }
4223  }
4224 }
4225 
4226 enum {
4231 };
4232 
4233 static bool merge_2_nurb(Curve *cu, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
4234 {
4235  BPoint *bp, *bp1, *bp2, *temp;
4236  float len1, len2;
4237  int origu, u, v;
4238 
4239  /* first nurbs will be changed to make u = resolu-1 selected */
4240  /* 2nd nurbs will be changed to make u = 0 selected */
4241 
4242  /* first nurbs: u = resolu-1 selected */
4243 
4244  if (is_u_selected(nu1, nu1->pntsu - 1)) {
4245  /* pass */
4246  }
4247  else {
4248  /* For 2D curves blender uses (orderv = 0). It doesn't make any sense mathematically. */
4249  /* but after rotating (orderu = 0) will be confusing. */
4250  if (nu1->orderv == 0) {
4251  nu1->orderv = 1;
4252  }
4253 
4254  rotate_direction_nurb(nu1);
4255  if (is_u_selected(nu1, nu1->pntsu - 1)) {
4256  /* pass */
4257  }
4258  else {
4259  rotate_direction_nurb(nu1);
4260  if (is_u_selected(nu1, nu1->pntsu - 1)) {
4261  /* pass */
4262  }
4263  else {
4264  rotate_direction_nurb(nu1);
4265  if (is_u_selected(nu1, nu1->pntsu - 1)) {
4266  /* pass */
4267  }
4268  else {
4269  /* rotate again, now its OK! */
4270  if (nu1->pntsv != 1) {
4271  rotate_direction_nurb(nu1);
4272  }
4273  return true;
4274  }
4275  }
4276  }
4277  }
4278 
4279  /* 2nd nurbs: u = 0 selected */
4280  if (is_u_selected(nu2, 0)) {
4281  /* pass */
4282  }
4283  else {
4284  if (nu2->orderv == 0) {
4285  nu2->orderv = 1;
4286  }
4287  rotate_direction_nurb(nu2);
4288  if (is_u_selected(nu2, 0)) {
4289  /* pass */
4290  }
4291  else {
4292  rotate_direction_nurb(nu2);
4293  if (is_u_selected(nu2, 0)) {
4294  /* pass */
4295  }
4296  else {
4297  rotate_direction_nurb(nu2);
4298  if (is_u_selected(nu2, 0)) {
4299  /* pass */
4300  }
4301  else {
4302  /* rotate again, now its OK! */
4303  if (nu1->pntsu == 1) {
4304  rotate_direction_nurb(nu1);
4305  }
4306  if (nu2->pntsv != 1) {
4307  rotate_direction_nurb(nu2);
4308  }
4309  return true;
4310  }
4311  }
4312  }
4313  }
4314 
4315  if (nu1->pntsv != nu2->pntsv) {
4316  return false;
4317  }
4318 
4319  /* ok, now nu1 has the rightmost column and nu2 the leftmost column selected */
4320  /* maybe we need a 'v' flip of nu2? */
4321 
4322  bp1 = &nu1->bp[nu1->pntsu - 1];
4323  bp2 = nu2->bp;
4324  len1 = 0.0;
4325 
4326  for (v = 0; v < nu1->pntsv; v++, bp1 += nu1->pntsu, bp2 += nu2->pntsu) {
4327  len1 += len_v3v3(bp1->vec, bp2->vec);
4328  }
4329 
4330  bp1 = &nu1->bp[nu1->pntsu - 1];
4331  bp2 = &nu2->bp[nu2->pntsu * (nu2->pntsv - 1)];
4332  len2 = 0.0;
4333 
4334  for (v = 0; v < nu1->pntsv; v++, bp1 += nu1->pntsu, bp2 -= nu2->pntsu) {
4335  len2 += len_v3v3(bp1->vec, bp2->vec);
4336  }
4337 
4338  /* merge */
4339  origu = nu1->pntsu;
4340  nu1->pntsu += nu2->pntsu;
4341  if (nu1->orderu < 3 && nu1->orderu < nu1->pntsu) {
4342  nu1->orderu++;
4343  }
4344  if (nu1->orderv < 3 && nu1->orderv < nu1->pntsv) {
4345  nu1->orderv++;
4346  }
4347  temp = nu1->bp;
4348  nu1->bp = MEM_mallocN(nu1->pntsu * nu1->pntsv * sizeof(BPoint), "mergeBP");
4349 
4350  bp = nu1->bp;
4351  bp1 = temp;
4352 
4353  for (v = 0; v < nu1->pntsv; v++) {
4354 
4355  /* switch direction? */
4356  if (len1 < len2) {
4357  bp2 = &nu2->bp[v * nu2->pntsu];
4358  }
4359  else {
4360  bp2 = &nu2->bp[(nu1->pntsv - v - 1) * nu2->pntsu];
4361  }
4362 
4363  for (u = 0; u < nu1->pntsu; u++, bp++) {
4364  if (u < origu) {
4365  keyIndex_updateBP(cu->editnurb, bp1, bp, 1);
4366  *bp = *bp1;
4367  bp1++;
4369  }
4370  else {
4371  keyIndex_updateBP(cu->editnurb, bp2, bp, 1);
4372  *bp = *bp2;
4373  bp2++;
4374  }
4375  }
4376  }
4377 
4378  if (nu1->type == CU_NURBS) {
4379  /* merge knots */
4380  BKE_nurb_knot_calc_u(nu1);
4381 
4382  /* make knots, for merged curved for example */
4383  BKE_nurb_knot_calc_v(nu1);
4384  }
4385 
4386  MEM_freeN(temp);
4387  BLI_remlink(editnurb, nu2);
4388  BKE_nurb_free(nu2);
4389  return true;
4390 }
4391 
4392 static int merge_nurb(View3D *v3d, Object *obedit)
4393 {
4394  Curve *cu = obedit->data;
4395  ListBase *editnurb = object_editcurve_get(obedit);
4396  NurbSort *nus1, *nus2;
4397  bool ok = true;
4398  ListBase nsortbase = {NULL, NULL};
4399 
4400  make_selection_list_nurb(v3d, editnurb, &nsortbase);
4401 
4402  if (nsortbase.first == nsortbase.last) {
4403  BLI_freelistN(&nsortbase);
4405  }
4406 
4407  nus1 = nsortbase.first;
4408  nus2 = nus1->next;
4409 
4410  /* resolution match, to avoid uv rotations */
4411  if (nus1->nu->pntsv == 1) {
4412  if (ELEM(nus1->nu->pntsu, nus2->nu->pntsu, nus2->nu->pntsv)) {
4413  /* pass */
4414  }
4415  else {
4416  ok = false;
4417  }
4418  }
4419  else if (nus2->nu->pntsv == 1) {
4420  if (ELEM(nus2->nu->pntsu, nus1->nu->pntsu, nus1->nu->pntsv)) {
4421  /* pass */
4422  }
4423  else {
4424  ok = false;
4425  }
4426  }
4427  else if (nus1->nu->pntsu == nus2->nu->pntsu || nus1->nu->pntsv == nus2->nu->pntsv) {
4428  /* pass */
4429  }
4430  else if (nus1->nu->pntsu == nus2->nu->pntsv || nus1->nu->pntsv == nus2->nu->pntsu) {
4431  /* pass */
4432  }
4433  else {
4434  ok = false;
4435  }
4436 
4437  if (ok == false) {
4438  BLI_freelistN(&nsortbase);
4440  }
4441 
4442  while (nus2) {
4443  /* There is a change a few curves merged properly, but not all.
4444  * In this case we still update the curve, yet report the error. */
4445  ok &= merge_2_nurb(cu, editnurb, nus1->nu, nus2->nu);
4446  nus2 = nus2->next;
4447  }
4448 
4449  BLI_freelistN(&nsortbase);
4451 
4453 }
4454 
4456 {
4457  Main *bmain = CTX_data_main(C);
4458  ViewLayer *view_layer = CTX_data_view_layer(C);
4459  View3D *v3d = CTX_wm_view3d(C);
4460 
4461  struct {
4462  int changed;
4463  int unselected;
4464  int error_selected_few;
4465  int error_resolution;
4466  int error_generic;
4467  } status = {0};
4468 
4469  uint objects_len;
4471  view_layer, CTX_wm_view3d(C), &objects_len);
4472  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4473  Object *obedit = objects[ob_index];
4474  Curve *cu = obedit->data;
4475 
4476  if (!ED_curve_select_check(v3d, cu->editnurb)) {
4477  status.unselected++;
4478  continue;
4479  }
4480 
4481  ListBase *nubase = object_editcurve_get(obedit);
4482  Nurb *nu, *nu1 = NULL, *nu2 = NULL;
4483  BPoint *bp;
4484  bool ok = false;
4485 
4486  /* first decide if this is a surface merge! */
4487  if (obedit->type == OB_SURF) {
4488  nu = nubase->first;
4489  }
4490  else {
4491  nu = NULL;
4492  }
4493 
4494  while (nu) {
4495  const int nu_select_num = ED_curve_nurb_select_count(v3d, nu);
4496  if (nu_select_num) {
4497 
4498  if (nu->pntsu > 1 && nu->pntsv > 1) {
4499  break;
4500  }
4501 
4502  if (nu_select_num > 1) {
4503  break;
4504  }
4505  /* only 1 selected, not first or last, a little complex, but intuitive */
4506  if (nu->pntsv == 1) {
4507  if ((nu->bp->f1 & SELECT) || (nu->bp[nu->pntsu - 1].f1 & SELECT)) {
4508  /* pass */
4509  }
4510  else {
4511  break;
4512  }
4513  }
4514  }
4515  nu = nu->next;
4516  }
4517 
4518  if (nu) {
4519  int merge_result = merge_nurb(v3d, obedit);
4520  switch (merge_result) {
4521  case CURVE_MERGE_OK:
4522  status.changed++;
4523  goto curve_merge_tag_object;
4525  status.error_resolution++;
4526  goto curve_merge_tag_object;
4528  status.error_selected_few++;
4529  break;
4531  status.error_resolution++;
4532  break;
4533  }
4534  continue;
4535  }
4536 
4537  /* find both nurbs and points, nu1 will be put behind nu2 */
4538  for (nu = nubase->first; nu; nu = nu->next) {
4539  if (nu->pntsu == 1) {
4540  nu->flagu &= ~CU_NURB_CYCLIC;
4541  }
4542 
4543  if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic */
4544  if (nu->type == CU_BEZIER) {
4545  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &(nu->bezt[nu->pntsu - 1]))) {
4546  /* Last point is selected, preferred for nu2 */
4547  if (nu2 == NULL) {
4548  nu2 = nu;
4549  }
4550  else if (nu1 == NULL) {
4551  nu1 = nu;
4552 
4553  /* Just in case both of first/last CV are selected check
4554  * whether we really need to switch the direction.
4555  */
4556  if (!BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nu1->bezt)) {
4558  keyData_switchDirectionNurb(cu, nu1);
4559  }
4560  }
4561  }
4562  else if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nu->bezt)) {
4563  /* First point is selected, preferred for nu1 */
4564  if (nu1 == NULL) {
4565  nu1 = nu;
4566  }
4567  else if (nu2 == NULL) {
4568  nu2 = nu;
4569 
4570  /* Just in case both of first/last CV are selected check
4571  * whether we really need to switch the direction.
4572  */
4573  if (!BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &(nu->bezt[nu2->pntsu - 1]))) {
4575  keyData_switchDirectionNurb(cu, nu2);
4576  }
4577  }
4578  }
4579  }
4580  else if (nu->pntsv == 1) {
4581  /* Same logic as above: if first point is selected spline is
4582  * preferred for nu1, if last point is selected spline is
4583  * preferred for u2u.
4584  */
4585 
4586  bp = nu->bp;
4587  if (bp[nu->pntsu - 1].f1 & SELECT) {
4588  if (nu2 == NULL) {
4589  nu2 = nu;
4590  }
4591  else if (nu1 == NULL) {
4592  nu1 = nu;
4593 
4594  if ((bp->f1 & SELECT) == 0) {
4597  }
4598  }
4599  }
4600  else if (bp->f1 & SELECT) {
4601  if (nu1 == NULL) {
4602  nu1 = nu;
4603  }
4604  else if (nu2 == NULL) {
4605  nu2 = nu;
4606 
4607  if ((bp[nu->pntsu - 1].f1 & SELECT) == 0) {
4610  }
4611  }
4612  }
4613  }
4614  }
4615 
4616  if (nu1 && nu2) {
4617  /* Got second spline, no need to loop over rest of the splines. */
4618  break;
4619  }
4620  }
4621 
4622  if ((nu1 && nu2) && (nu1 != nu2)) {
4623  if (nu1->type == nu2->type) {
4624  if (nu1->type == CU_BEZIER) {
4625  BezTriple *bezt = (BezTriple *)MEM_mallocN((nu1->pntsu + nu2->pntsu) * sizeof(BezTriple),
4626  "addsegmentN");
4627  ED_curve_beztcpy(cu->editnurb, bezt, nu2->bezt, nu2->pntsu);
4628  ED_curve_beztcpy(cu->editnurb, bezt + nu2->pntsu, nu1->bezt, nu1->pntsu);
4629 
4630  MEM_freeN(nu1->bezt);
4631  nu1->bezt = bezt;
4632  nu1->pntsu += nu2->pntsu;
4633  BLI_remlink(nubase, nu2);
4634  keyIndex_delNurb(cu->editnurb, nu2);
4635  BKE_nurb_free(nu2);
4636  nu2 = NULL;
4637  BKE_nurb_handles_calc(nu1);
4638  }
4639  else {
4640  bp = (BPoint *)MEM_mallocN((nu1->pntsu + nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
4641  ED_curve_bpcpy(cu->editnurb, bp, nu2->bp, nu2->pntsu);
4642  ED_curve_bpcpy(cu->editnurb, bp + nu2->pntsu, nu1->bp, nu1->pntsu);
4643  MEM_freeN(nu1->bp);
4644  nu1->bp = bp;
4645 
4646  /* a = nu1->pntsu + nu1->orderu; */ /* UNUSED */
4647 
4648  nu1->pntsu += nu2->pntsu;
4649  BLI_remlink(nubase, nu2);
4650 
4651  /* now join the knots */
4652  if (nu1->type == CU_NURBS) {
4653  if (nu1->knotsu != NULL) {
4654  MEM_freeN(nu1->knotsu);
4655  nu1->knotsu = NULL;
4656  }
4657 
4658  BKE_nurb_knot_calc_u(nu1);
4659  }
4660  keyIndex_delNurb(cu->editnurb, nu2);
4661  BKE_nurb_free(nu2);
4662  nu2 = NULL;
4663  }
4664 
4665  BKE_curve_nurb_active_set(cu, nu1); /* for selected */
4666  ok = true;
4667  }
4668  }
4669  else if ((nu1 && !nu2) || (!nu1 && nu2)) {
4670  if (nu2) {
4671  SWAP(Nurb *, nu1, nu2);
4672  }
4673 
4674  if (!(nu1->flagu & CU_NURB_CYCLIC) && nu1->pntsu > 1) {
4675  if (nu1->type == CU_BEZIER && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nu1->bezt) &&
4676  BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu1->bezt[nu1->pntsu - 1])) {
4677  nu1->flagu |= CU_NURB_CYCLIC;
4678  BKE_nurb_handles_calc(nu1);
4679  ok = true;
4680  }
4681  else if (ELEM(nu1->type, CU_NURBS, CU_POLY) && nu1->bp->f1 & SELECT &&
4682  (nu1->bp[nu1->pntsu - 1].f1 & SELECT)) {
4683  nu1->flagu |= CU_NURB_CYCLIC;
4684  BKE_nurb_knot_calc_u(nu1);
4685  ok = true;
4686  }
4687  }
4688  }
4689 
4690  if (!ok) {
4691  status.error_generic++;
4692  continue;
4693  }
4694 
4695  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
4697  }
4698 
4699  status.changed++;
4700 
4701  curve_merge_tag_object:
4703  DEG_id_tag_update(obedit->data, 0);
4704  }
4705  MEM_freeN(objects);
4706 
4707  if (status.unselected == objects_len) {
4708  BKE_report(op->reports, RPT_ERROR, "No points were selected");
4709  return OPERATOR_CANCELLED;
4710  }
4711 
4712  const int tot_errors = status.error_selected_few + status.error_resolution +
4713  status.error_generic;
4714  if (tot_errors > 0) {
4715  /* Some curves changed, but some curves failed: don't explain why it failed. */
4716  if (status.changed) {
4717  BKE_reportf(op->reports,
4718  RPT_INFO,
4719  tot_errors == 1 ? "%d curve could not make segments" :
4720  "%d curves could not make segments",
4721  tot_errors);
4722  return OPERATOR_FINISHED;
4723  }
4724 
4725  /* All curves failed: If there is more than one error give a generic error report. */
4726  if (((status.error_selected_few ? 1 : 0) + (status.error_resolution ? 1 : 0) +
4727  (status.error_generic ? 1 : 0)) > 1) {
4728  BKE_report(op->reports, RPT_ERROR, "Could not make new segments");
4729  }
4730 
4731  /* All curves failed due to the same error. */
4732  if (status.error_selected_few) {
4733  BKE_report(op->reports, RPT_ERROR, "Too few selections to merge");
4734  }
4735  else if (status.error_resolution) {
4736  BKE_report(op->reports, RPT_ERROR, "Resolution does not match");
4737  }
4738  else {
4739  BLI_assert(status.error_generic);
4740  BKE_report(op->reports, RPT_ERROR, "Cannot make segment");
4741  }
4742  return OPERATOR_CANCELLED;
4743  }
4744 
4745  return OPERATOR_FINISHED;
4746 }
4747 
4749 {
4750  /* identifiers */
4751  ot->name = "Make Segment";
4752  ot->idname = "CURVE_OT_make_segment";
4753  ot->description = "Join two curves by their selected ends";
4754 
4755  /* api callbacks */
4758 
4759  /* flags */
4761 }
4762 
4765 /* -------------------------------------------------------------------- */
4770  bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
4771 {
4773  ViewContext vc;
4774  Nurb *nu;
4775  BezTriple *bezt = NULL;
4776  BPoint *bp = NULL;
4777  Base *basact = NULL;
4778  short hand;
4779 
4782  copy_v2_v2_int(vc.mval, mval);
4783 
4784  if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) {
4785  Object *obedit = basact->object;
4786  Curve *cu = obedit->data;
4787  ListBase *editnurb = object_editcurve_get(obedit);
4788  const void *vert = BKE_curve_vert_active_get(cu);
4789 
4790  if (!extend && !deselect && !toggle) {
4791  uint objects_len = 0;
4793  vc.view_layer, vc.v3d, &objects_len);
4794  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
4795  Object *ob_iter = objects[ob_index];
4796 
4797  ED_curve_deselect_all(((Curve *)ob_iter->data)->editnurb);
4798 
4801  }
4802  MEM_freeN(objects);
4803  }
4804 
4805  if (extend) {
4806  if (bezt) {
4807  if (hand == 1) {
4809  }
4810  else {
4811  if (hand == 0) {
4812  bezt->f1 |= SELECT;
4813  }
4814  else {
4815  bezt->f3 |= SELECT;
4816  }
4817  }
4818  BKE_curve_nurb_vert_active_set(cu, nu, bezt);
4819  }
4820  else {
4822  BKE_curve_nurb_vert_active_set(cu, nu, bp);
4823  }
4824  }
4825  else if (deselect) {
4826  if (bezt) {
4827  if (hand == 1) {
4829  if (bezt == vert) {
4830  cu->actvert = CU_ACT_NONE;
4831  }
4832  }
4833  else if (hand == 0) {
4834  bezt->f1 &= ~SELECT;
4835  }
4836  else {
4837  bezt->f3 &= ~SELECT;
4838  }
4839  }
4840  else {
4842  if (bp == vert) {
4843  cu->actvert = CU_ACT_NONE;
4844  }
4845  }
4846  }
4847  else if (toggle) {
4848  if (bezt) {
4849  if (hand == 1) {
4850  if (bezt->f2 & SELECT) {
4852  if (bezt == vert) {
4853  cu->actvert = CU_ACT_NONE;
4854  }
4855  }
4856  else {
4858  BKE_curve_nurb_vert_active_set(cu, nu, bezt);
4859  }
4860  }
4861  else if (hand == 0) {
4862  bezt->f1 ^= SELECT;
4863  }
4864  else {
4865  bezt->f3 ^= SELECT;
4866  }
4867  }
4868  else {
4869  if (bp->f1 & SELECT) {
4871  if (bp == vert) {
4872  cu->actvert = CU_ACT_NONE;
4873  }
4874  }
4875  else {
4877  BKE_curve_nurb_vert_active_set(cu, nu, bp);
4878  }
4879  }
4880  }
4881  else {
4882  BKE_nurbList_flag_set(editnurb, SELECT, false);
4883 
4884  if (bezt) {
4885 
4886  if (hand == 1) {
4888  }
4889  else {
4890  if (hand == 0) {
4891  bezt->f1 |= SELECT;
4892  }
4893  else {
4894  bezt->f3 |= SELECT;
4895  }
4896  }
4897  BKE_curve_nurb_vert_active_set(cu, nu, bezt);
4898  }
4899  else {
4901  BKE_curve_nurb_vert_active_set(cu, nu, bp);
4902  }
4903  }
4904 
4905  if (nu != BKE_curve_nurb_active_get(cu)) {
4906  cu->actvert = CU_ACT_NONE;
4907  BKE_curve_nurb_active_set(cu, nu);
4908  }
4909 
4910  if (vc.view_layer->basact != basact) {
4911  ED_object_base_activate(C, basact);
4912  }
4913 
4916 
4917  return true;
4918  }
4919 
4920  return false;
4921 }
4922 
4925 /* -------------------------------------------------------------------- */
4929 /* 'cent' is in object space and 'dvec' in worldspace.
4930  */
4932  float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3])
4933 {
4934  Curve *cu = (Curve *)obedit->data;
4935  ListBase *editnurb = object_editcurve_get(obedit);
4936  float cmat[3][3], tmat[3][3], imat[3][3];
4937  float bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3];
4938  float persmat[3][3], persinv[3][3];
4939  bool ok, changed = false;
4940  int a;
4941 
4942  copy_m3_m4(persmat, viewmat);
4943  invert_m3_m3(persinv, persmat);
4944 
4945  /* imat and center and size */
4946  copy_m3_m4(bmat, obedit->obmat);
4947  invert_m3_m3(imat, bmat);
4948 
4949  axis_angle_to_mat3(cmat, axis, M_PI / 4.0);
4950  mul_m3_m3m3(tmat, cmat, bmat);
4951  mul_m3_m3m3(rotmat, imat, tmat);
4952 
4953  unit_m3(scalemat1);
4954  scalemat1[0][0] = M_SQRT2;
4955  scalemat1[1][1] = M_SQRT2;
4956 
4957  mul_m3_m3m3(tmat, persmat, bmat);
4958  mul_m3_m3m3(cmat, scalemat1, tmat);
4959  mul_m3_m3m3(tmat, persinv, cmat);
4960  mul_m3_m3m3(scalemat1, imat, tmat);
4961 
4962  unit_m3(scalemat2);
4963  scalemat2[0][0] /= (float)M_SQRT2;
4964  scalemat2[1][1] /= (float)M_SQRT2;
4965 
4966  mul_m3_m3m3(tmat, persmat, bmat);
4967  mul_m3_m3m3(cmat, scalemat2, tmat);
4968  mul_m3_m3m3(tmat, persinv, cmat);
4969  mul_m3_m3m3(scalemat2, imat, tmat);
4970 
4971  ok = true;
4972 
4973  for (a = 0; a < 7; a++) {
4975 
4976  if (ok == false) {
4977  return changed;
4978  }
4979 
4980  changed = true;
4981 
4982  rotateflagNurb(editnurb, SELECT, cent, rotmat);
4983 
4984  if ((a & 1) == 0) {
4985  rotateflagNurb(editnurb, SELECT, cent, scalemat1);
4986  weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2);
4987  }
4988  else {
4989  rotateflagNurb(editnurb, SELECT, cent, scalemat2);
4990  weightflagNurb(editnurb, SELECT, 4.0 / M_SQRT2);
4991  }
4992  }
4993 
4994  if (ok) {
4995  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4996  if (ED_curve_nurb_select_check(v3d, nu)) {
4997  nu->orderv = 4;
4998  nu->flagv |= CU_NURB_CYCLIC;
5000  }
5001  }
5002  }
5003 
5004  return changed;
5005 }
5006 
5007 static int spin_exec(bContext *C, wmOperator *op)
5008 {
5009  Main *bmain = CTX_data_main(C);
5010  ViewLayer *view_layer = CTX_data_view_layer(C);
5011  View3D *v3d = CTX_wm_view3d(C);
5013  float cent[3], axis[3], viewmat[4][4];
5014  int ok = -1;
5015 
5016  RNA_float_get_array(op->ptr, "center", cent);
5017  RNA_float_get_array(op->ptr, "axis", axis);
5018 
5019  if (rv3d) {
5020  copy_m4_m4(viewmat, rv3d->viewmat);
5021  }
5022  else {
5023  unit_m4(viewmat);
5024  }
5025 
5026  uint objects_len;
5028  view_layer, CTX_wm_view3d(C), &objects_len);
5029  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5030  Object *obedit = objects[ob_index];
5031  Curve *cu = (Curve *)obedit->data;
5032 
5033  if (!ED_curve_select_check(v3d, cu->editnurb)) {
5034  continue;
5035  }
5036 
5037  invert_m4_m4(obedit->imat, obedit->obmat);
5038  mul_m4_v3(obedit->imat, cent);
5039 
5040  if (!ed_editnurb_spin(viewmat, v3d, obedit, axis, cent)) {
5041  ok = MAX2(ok, 0);
5042  continue;
5043  }
5044 
5045  ok = 1;
5046  if (ED_curve_updateAnimPaths(bmain, cu)) {
5048  }
5049 
5051  DEG_id_tag_update(obedit->data, 0);
5052  }
5053  MEM_freeN(objects);
5054 
5055  if (ok == 0) {
5056  BKE_report(op->reports, RPT_ERROR, "Cannot spin");
5057  }
5058  return OPERATOR_FINISHED;
5059 }
5060 
5061 static int spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
5062 {
5065  float axis[3] = {0.0f, 0.0f, 1.0f};
5066 
5067  if (rv3d) {
5068  copy_v3_v3(axis, rv3d->viewinv[2]);
5069  }
5070 
5071  RNA_float_set_array(op->ptr, "center", scene->cursor.location);
5072  RNA_float_set_array(op->ptr, "axis", axis);
5073 
5074  return spin_exec(C, op);
5075 }
5076 
5078 {
5079  /* identifiers */
5080  ot->name = "Spin";
5081  ot->idname = "CURVE_OT_spin";
5082  ot->description = "Extrude selected boundary row around pivot point and current view axis";
5083 
5084  /* api callbacks */
5085  ot->exec = spin_exec;
5086  ot->invoke = spin_invoke;
5088 
5089  /* flags */
5091 
5093  "center",
5094  3,
5095  NULL,
5098  "Center",
5099  "Center in global view space",
5100  -1000.0f,
5101  1000.0f);
5103  ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
5104 }
5105 
5108 /* -------------------------------------------------------------------- */
5112 static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
5113 {
5114  bool changed = false;
5115 
5116  Nurb *cu_actnu;
5117  union {
5118  BezTriple *bezt;
5119  BPoint *bp;
5120  void *p;
5121  } cu_actvert;
5122 
5123  if (BLI_listbase_is_empty(&editnurb->nurbs)) {
5124  return changed;
5125  }
5126 
5127  BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p);
5128  int act_offset = 0;
5129 
5130  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
5131  BLI_assert(nu->pntsu > 0);
5132  int i;
5133  int pnt_len = nu->pntsu;
5134  int new_points = 0;
5135  int offset = 0;
5136  bool is_prev_selected = false;
5137  bool duplic_first = false;
5138  bool duplic_last = false;
5139  if (nu->type == CU_BEZIER) {
5140  BezTriple *bezt, *bezt_prev = NULL;
5141  BezTriple bezt_stack;
5142  bool is_cyclic = false;
5143  if (pnt_len == 1) {
5144  /* Single point extrusion.
5145  * Keep `is_prev_selected` false to force extrude. */
5146  bezt_prev = &nu->bezt[0];
5147  }
5148  else if (nu->flagu & CU_NURB_CYCLIC) {
5149  is_cyclic = true;
5150  bezt_prev = &nu->bezt[pnt_len - 1];
5151  is_prev_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev);
5152  }
5153  else {
5154  duplic_first = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[0]) &&
5155  BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[1]);
5156 
5157  duplic_last = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[pnt_len - 2]) &&
5158  BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[pnt_len - 1]);
5159 
5160  if (duplic_first) {
5161  bezt_stack = nu->bezt[0];
5162  BEZT_DESEL_ALL(&bezt_stack);
5163  bezt_prev = &bezt_stack;
5164  }
5165  if (duplic_last) {
5166  new_points++;
5167  }
5168  }
5169  i = pnt_len;
5170  for (bezt = &nu->bezt[0]; i--; bezt++) {
5171  bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
5172  if (bezt_prev && is_prev_selected != is_selected) {
5173  new_points++;
5174  }
5175  if (bezt == cu_actvert.bezt) {
5176  act_offset = new_points;
5177  }
5178  bezt_prev = bezt;
5179  is_prev_selected = is_selected;
5180  }
5181 
5182  if (new_points) {
5183  if (pnt_len == 1) {
5184  /* Single point extrusion.
5185  * Set `is_prev_selected` as false to force extrude. */
5186  BLI_assert(bezt_prev == &nu->bezt[0]);
5187  is_prev_selected = false;
5188  }
5189  else if (is_cyclic) {
5190  BLI_assert(bezt_prev == &nu->bezt[pnt_len - 1]);
5191  BLI_assert(is_prev_selected == BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev));
5192  }
5193  else if (duplic_first) {
5194  bezt_prev = &bezt_stack;
5195  is_prev_selected = false;
5196  }
5197  else {
5198  bezt_prev = NULL;
5199  }
5200  BezTriple *bezt_src, *bezt_dst, *bezt_src_iter, *bezt_dst_iter;
5201  const int new_len = pnt_len + new_points;
5202 
5203  bezt_src = nu->bezt;
5204  bezt_dst = MEM_mallocN(new_len * sizeof(BezTriple), __func__);
5205  bezt_src_iter = &bezt_src[0];
5206  bezt_dst_iter = &bezt_dst[0];
5207  i = 0;
5208  for (bezt = &nu->bezt[0]; i < pnt_len; i++, bezt++) {
5209  bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
5210  /* While this gets de-selected, selecting here ensures newly created verts are selected.
5211  * without this, the vertices are copied but only the handles are transformed.
5212  * which seems buggy from a user perspective. */
5213  if (is_selected) {
5214  bezt->f2 |= SELECT;
5215  }
5216  if (bezt_prev && is_prev_selected != is_selected) {
5217  int count = i - offset + 1;
5218  if (is_prev_selected) {
5219  ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count - 1);
5220  ED_curve_beztcpy(editnurb, &bezt_dst_iter[count - 1], bezt_prev, 1);
5221  }
5222  else {
5223  ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count);
5224  }
5225  ED_curve_beztcpy(editnurb, &bezt_dst_iter[count], bezt, 1);
5226  BEZT_DESEL_ALL(&bezt_dst_iter[count - 1]);
5227 
5228  bezt_dst_iter += count + 1;
5229  bezt_src_iter += count;
5230  offset = i + 1;
5231  }
5232  bezt_prev = bezt;
5233  is_prev_selected = is_selected;
5234  }
5235 
5236  int remain = pnt_len - offset;
5237  if (remain) {
5238  ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, remain);
5239  }
5240 
5241  if (duplic_last) {
5242  ED_curve_beztcpy(editnurb, &bezt_dst[new_len - 1], &bezt_src[pnt_len - 1], 1);
5243  BEZT_DESEL_ALL(&bezt_dst[new_len - 1]);
5244  }
5245 
5246  MEM_freeN(nu->bezt);
5247  nu->bezt = bezt_dst;
5248  nu->pntsu += new_points;
5249  changed = true;
5250  }
5251  }
5252  else {
5253  BPoint *bp, *bp_prev = NULL;
5254  BPoint bp_stack;
5255  if (pnt_len == 1) {
5256  /* Single point extrusion.
5257  * Reference a `prev_bp` to force extrude. */
5258  bp_prev = &nu->bp[0];
5259  }
5260  else {
5261  duplic_first = (nu->bp[0].f1 & SELECT) && (nu->bp[1].f1 & SELECT);
5262  duplic_last = (nu->bp[pnt_len - 2].f1 & SELECT) && (nu->bp[pnt_len - 1].f1 & SELECT);
5263  if (duplic_first) {
5264  bp_stack = nu->bp[0];
5265  bp_stack.f1 &= ~SELECT;
5266  bp_prev = &bp_stack;
5267  }
5268  if (duplic_last) {
5269  new_points++;
5270  }
5271  }
5272 
5273  i = pnt_len;
5274  for (bp = &nu->bp[0]; i--; bp++) {
5275  bool is_selected = (bp->f1 & SELECT) != 0;
5276  if (bp_prev && is_prev_selected != is_selected) {
5277  new_points++;
5278  }
5279  if (bp == cu_actvert.bp) {
5280  act_offset = new_points;
5281  }
5282  bp_prev = bp;
5283  is_prev_selected = is_selected;
5284  }
5285 
5286  if (new_points) {
5287  BPoint *bp_src, *bp_dst, *bp_src_iter, *bp_dst_iter;
5288  const int new_len = pnt_len + new_points;
5289 
5290  is_prev_selected = false;
5291  if (pnt_len == 1) {
5292  /* Single point extrusion.
5293  * Keep `is_prev_selected` false to force extrude. */
5294  BLI_assert(bp_prev == &nu->bp[0]);
5295  }
5296  else if (duplic_first) {
5297  bp_prev = &bp_stack;
5298  is_prev_selected = false;
5299  }
5300  else {
5301  bp_prev = NULL;
5302  }
5303  bp_src = nu->bp;
5304  bp_dst = MEM_mallocN(new_len * sizeof(BPoint), __func__);
5305  bp_src_iter = &bp_src[0];
5306  bp_dst_iter = &bp_dst[0];
5307  i = 0;
5308  for (bp = &nu->bp[0]; i < pnt_len; i++, bp++) {
5309  bool is_selected = (bp->f1 & SELECT) != 0;
5310  if (bp_prev && is_prev_selected != is_selected) {
5311  int count = i - offset + 1;
5312  if (is_prev_selected) {
5313  ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count - 1);
5314  ED_curve_bpcpy(editnurb, &bp_dst_iter[count - 1], bp_prev, 1);
5315  }
5316  else {
5317  ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count);
5318  }
5319  ED_curve_bpcpy(editnurb, &bp_dst_iter[count], bp, 1);
5320  bp_dst_iter[count - 1].f1 &= ~SELECT;
5321 
5322  bp_dst_iter += count + 1;
5323  bp_src_iter += count;
5324  offset = i + 1;
5325  }
5326  bp_prev = bp;
5327  is_prev_selected = is_selected;
5328  }
5329 
5330  int remain = pnt_len - offset;
5331  if (remain) {
5332  ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, remain);
5333  }
5334 
5335  if (duplic_last) {
5336  ED_curve_bpcpy(editnurb, &bp_dst[new_len - 1], &bp_src[pnt_len - 1], 1);
5337  bp_dst[new_len - 1].f1 &= ~SELECT;
5338  }
5339 
5340  MEM_freeN(nu->bp);
5341  nu->bp = bp_dst;
5342  nu->pntsu += new_points;
5343 
5345  changed = true;
5346  }
5347  }
5348  }
5349 
5350  cu->actvert += act_offset;
5351 
5352  return changed;
5353 }
5354 
5357 /* -------------------------------------------------------------------- */
5362  EditNurb *editnurb,
5363  View3D *v3d,
5364  const float location_init[3])
5365 {
5366  float center[3];
5367  float temp[3];
5368  uint verts_len;
5369  bool changed = false;
5370 
5371  zero_v3(center);
5372  verts_len = 0;
5373 
5374  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
5375  int i;
5376  if (nu->type == CU_BEZIER) {
5377  BezTriple *bezt;
5378 
5379  for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
5380  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
5381  add_v3_v3(center, bezt->vec[1]);
5382  verts_len += 1;
5383  }
5384  }
5385  }
5386  else {
5387  BPoint *bp;
5388 
5389  for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) {
5390  if (bp->f1 & SELECT) {
5391  add_v3_v3(center, bp->vec);
5392  verts_len += 1;
5393  }
5394  }
5395  }
5396  }
5397 
5398  if (verts_len && ed_editcurve_extrude(cu, editnurb, v3d)) {
5399  float ofs[3];
5400  int i;
5401 
5402  mul_v3_fl(center, 1.0f / (float)verts_len);
5403  sub_v3_v3v3(ofs, location_init, center);
5404 
5405  if (CU_IS_2D(cu)) {
5406  ofs[2] = 0.0f;
5407  }
5408 
5409  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
5410  if (nu->type == CU_BEZIER) {
5411  BezTriple *bezt;
5412  for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
5413  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
5414  add_v3_v3(bezt->vec[0], ofs);
5415  add_v3_v3(bezt->vec[1], ofs);
5416  add_v3_v3(bezt->vec[2], ofs);
5417 
5418  if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (i == 0 || i == nu->pntsu - 1)) {
5420  }
5421  }
5422  }
5423 
5425  }
5426  else {
5427  BPoint *bp;
5428 
5429  for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) {
5430  if (bp->f1 & SELECT) {
5431  add_v3_v3(bp->vec, ofs);
5432  }
5433  }
5434  }
5435  }
5436  changed = true;
5437  }
5438  else {
5439  float location[3];
5440 
5441  copy_v3_v3(location, location_init);
5442 
5443  if (CU_IS_2D(cu)) {
5444  location[2] = 0.0f;
5445  }
5446 
5447  /* nothing selected: create a new curve */
5448  Nurb *nu = BKE_curve_nurb_active_get(cu);
5449 
5450  Nurb *nurb_new;
5451  if (!nu) {
5452  /* Bezier as default. */
5453  nurb_new = MEM_callocN(sizeof(Nurb), "BLI_editcurve_addvert new_bezt_nurb 2");
5454  nurb_new->type = CU_BEZIER;
5455  nurb_new->resolu = cu->resolu;
5456  nurb_new->orderu = 4;
5457  nurb_new->flag |= CU_SMOOTH;
5458  BKE_nurb_bezierPoints_add(nurb_new, 1);
5459  }
5460  else {
5461  /* Copy the active nurb settings. */
5462  nurb_new = BKE_nurb_copy(nu, 1, 1);
5463  if (nu->bezt) {
5464  memcpy(nurb_new->bezt, nu->bezt, sizeof(BezTriple));
5465  }
5466  else {
5467  memcpy(nurb_new->bp, nu->bp, sizeof(BPoint));
5468  }
5469  }
5470 
5471  if (nurb_new->type == CU_BEZIER) {
5472  BezTriple *bezt_new = nurb_new->bezt;
5473 
5474  BEZT_SEL_ALL(bezt_new);
5475 
5476  bezt_new->h1 = HD_AUTO;
5477  bezt_new->h2 = HD_AUTO;
5478 
5479  temp[0] = 1.0f;
5480  temp[1] = 0.0f;
5481  temp[2] = 0.0f;
5482 
5483  copy_v3_v3(bezt_new->vec[1], location);
5484  sub_v3_v3v3(bezt_new->vec[0], location, temp);
5485  add_v3_v3v3(bezt_new->vec[2], location, temp);
5486  }
5487  else {
5488  BPoint *bp_new = nurb_new->bp;
5489 
5490  bp_new->f1 |= SELECT;
5491 
5492  copy_v3_v3(bp_new->vec, location);
5493 
5494  BKE_nurb_knot_calc_u(nurb_new);
5495  }
5496 
5497  BLI_addtail(&editnurb->nurbs, nurb_new);
5498  changed = true;
5499  }
5500 
5501  return changed;
5502 }
5503 
5505 {
5506  Main *bmain = CTX_data_main(C);
5507  Object *obedit = CTX_data_edit_object(C);
5508  View3D *v3d = CTX_wm_view3d(C);
5509  Curve *cu = obedit->data;
5510  EditNurb *editnurb = cu->editnurb;
5511  float location[3];
5512  float imat[4][4];
5513 
5514  RNA_float_get_array(op->ptr, "location", location);
5515 
5516  invert_m4_m4(imat, obedit->obmat);
5517  mul_m4_v3(imat, location);
5518 
5519  if (ed_editcurve_addvert(cu, editnurb, v3d, location)) {
5520  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
5522  }
5523 
5526 
5527  DEG_id_tag_update(obedit->data, 0);
5528 
5529  return OPERATOR_FINISHED;
5530  }
5531  return OPERATOR_CANCELLED;
5532 }
5533 
5534 static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
5535 {
5537  ViewContext vc;
5538 
5540 
5541  if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) {
5542  Curve *cu;
5543  float location[3];
5544  const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
5546 
5547  Nurb *nu;
5548  BezTriple *bezt;
5549  BPoint *bp;
5550 
5551  cu = vc.obedit->data;
5552 
5553  ED_curve_nurb_vert_selected_find(cu, vc.v3d, &nu, &bezt, &bp);
5554 
5555  if (bezt) {
5556  mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]);
5557  }
5558  else if (bp) {
5559  mul_v3_m4v3(location, vc.obedit->obmat, bp->vec);
5560  }
5561  else {
5562  copy_v3_v3(location, vc.scene->cursor.location);
5563  }
5564 
5565  ED_view3d_win_to_3d_int(vc.v3d, vc.region, location, event->mval, location);
5566 
5567  if (use_proj) {
5568  const float mval[2] = {UNPACK2(event->mval)};
5569 
5571  vc.scene, 0, vc.region, vc.v3d);
5572 
5574  snap_context,
5575  vc.depsgraph,
5577  &(const struct SnapObjectParams){
5578  .snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
5579  .use_object_edit_cage = false,
5580  },
5581  mval,
5582  NULL,
5583  NULL,
5584  location,
5585  NULL);
5586 
5588  }
5589 
5590  if (CU_IS_2D(cu)) {
5591  const float eps = 1e-6f;
5592 
5593  /* get the view vector to 'location' */
5594  float view_dir[3];
5595  ED_view3d_global_to_vector(vc.rv3d, location, view_dir);
5596 
5597  /* get the plane */
5598  float plane[4];
5599  /* only normalize to avoid precision errors */
5600  normalize_v3_v3(plane, vc.obedit->obmat[2]);
5601  plane[3] = -dot_v3v3(plane, vc.obedit->obmat[3]);
5602 
5603  if (fabsf(dot_v3v3(view_dir, plane)) < eps) {
5604  /* can't project on an aligned plane. */
5605  }
5606  else {
5607  float lambda;
5608  if (isect_ray_plane_v3(location, view_dir, plane, &lambda, false)) {
5609  /* check if we're behind the viewport */
5610  float location_test[3];
5611  madd_v3_v3v3fl(location_test, location, view_dir, lambda);
5612  if ((vc.rv3d->is_persp == false) ||
5613  (mul_project_m4_v3_zfac(vc.rv3d->persmat, location_test) > 0.0f)) {
5614  copy_v3_v3(location, location_test);
5615  }
5616  }
5617  }
5618  }
5619 
5620  RNA_float_set_array(op->ptr, "location", location);
5621  }
5622 
5623  return add_vertex_exec(C, op);
5624 }
5625 
5627 {
5628  /* identifiers */
5629  ot->name = "Add Vertex";
5630  ot->idname = "CURVE_OT_vertex_add";
5631  ot->description = "Add a new control point (linked to only selected end-curve one, if any)";
5632 
5633  /* api callbacks */
5634  ot->exec = add_vertex_exec;
5637 
5638  /* flags */
5640 
5641  /* properties */
5643  "location",
5644  3,
5645  NULL,
5648  "Location",
5649  "Location to add new vertex at",
5650  -1.0e4f,
5651  1.0e4f);
5652 }
5653 
5656 /* -------------------------------------------------------------------- */
5661 {
5662  Main *bmain = CTX_data_main(C);
5663  ViewLayer *view_layer = CTX_data_view_layer(C);
5664  View3D *v3d = CTX_wm_view3d(C);
5665 
5666  uint objects_len;
5668  view_layer, CTX_wm_view3d(C), &objects_len);
5669  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5670  Object *obedit = objects[ob_index];
5671  Curve *cu = obedit->data;
5672  EditNurb *editnurb = cu->editnurb;
5673  bool changed = false;
5674  bool as_curve = false;
5675 
5676  if (!ED_curve_select_check(v3d, cu->editnurb)) {
5677  continue;
5678  }
5679 
5680  /* First test: curve? */
5681  if (obedit->type != OB_CURVE) {
5682  LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
5683  if ((nu->pntsv == 1) && (ED_curve_nurb_select_count(v3d, nu) < nu->pntsu)) {
5684  as_curve = true;
5685  break;
5686  }
5687  }
5688  }
5689 
5690  if (obedit->type == OB_CURVE || as_curve) {
5691  changed = ed_editcurve_extrude(cu, editnurb, v3d);
5692  }
5693  else {
5694  changed = ed_editnurb_extrude_flag(editnurb, SELECT);
5695  }
5696 
5697  if (changed) {
5698  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
5700  }
5701 
5703  DEG_id_tag_update(obedit->data, 0);
5704  }
5705  }
5706  MEM_freeN(objects);
5707  return OPERATOR_FINISHED;
5708 }
5709 
5711 {
5712  /* identifiers */
5713  ot->name = "Extrude";
5714  ot->description = "Extrude selected control point(s)";
5715  ot->idname = "CURVE_OT_extrude";
5716 
5717  /* api callbacks */
5720 
5721  /* flags */
5723 
5724  /* to give to transform */
5726 }
5727 
5730 /* -------------------------------------------------------------------- */
5734 static bool curve_toggle_cyclic(View3D *v3d, ListBase *editnurb, int direction)
5735 {
5736  BezTriple *bezt;
5737  BPoint *bp;
5738  int a;
5739  bool changed = false;
5740 
5741  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
5742  if (nu->pntsu > 1 || nu->pntsv > 1) {
5743  if (nu->type == CU_POLY) {
5744  a = nu->pntsu;
5745  bp = nu->bp;
5746  while (a--) {
5747  if (bp->f1 & SELECT) {
5748  nu->flagu ^= CU_NURB_CYCLIC;
5749  changed = true;
5750  break;
5751  }
5752  bp++;
5753  }
5754  }
5755  else if (nu->type == CU_BEZIER) {
5756  a = nu->pntsu;
5757  bezt = nu->bezt;
5758  while (a--) {
5759  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
5760  nu->flagu ^= CU_NURB_CYCLIC;
5761  changed = true;
5762  break;
5763  }
5764  bezt++;
5765  }
5767  }
5768  else if (nu->pntsv == 1 && nu->type == CU_NURBS) {
5769  if (nu->knotsu) { /* if check_valid_nurb_u fails the knotsu can be NULL */
5770  a = nu->pntsu;
5771  bp = nu->bp;
5772  while (a--) {
5773  if (bp->f1 & SELECT) {
5774  nu->flagu ^= CU_NURB_CYCLIC;
5775  /* 1==u type is ignored for cyclic curves */
5777  changed = true;
5778  break;
5779  }
5780  bp++;
5781  }
5782  }
5783  }
5784  else if (nu->type == CU_NURBS) {
5785  a = nu->pntsu * nu->pntsv;
5786  bp = nu->bp;
5787  while (a--) {
5788 
5789  if (bp->f1 & SELECT) {
5790  if (direction == 0 && nu->pntsu > 1) {
5791  nu->flagu ^= CU_NURB_CYCLIC;
5792  /* 1==u type is ignored for cyclic curves */
5794  changed = true;
5795  }
5796  if (direction == 1 && nu->pntsv > 1) {
5797  nu->flagv ^= CU_NURB_CYCLIC;
5798  /* 2==v type is ignored for cyclic curves */
5800  changed = true;
5801  }
5802  break;
5803  }
5804  bp++;
5805  }
5806  }
5807  }
5808  }
5809  return changed;
5810 }
5811 
5813 {
5814  const int direction = RNA_enum_get(op->ptr, "direction");
5815  View3D *v3d = CTX_wm_view3d(C);
5816  ViewLayer *view_layer = CTX_data_view_layer(C);
5817  bool changed_multi = false;
5818 
5819  uint objects_len;
5821  view_layer, CTX_wm_view3d(C), &objects_len);
5822  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5823  Object *obedit = objects[ob_index];
5824  Curve *cu = obedit->data;
5825 
5826  if (!ED_curve_select_check(v3d, cu->editnurb)) {
5827  continue;
5828  }
5829 
5830  ListBase *editnurb = object_editcurve_get(obedit);
5831  if (curve_toggle_cyclic(v3d, editnurb, direction)) {
5832  changed_multi = true;
5834  DEG_id_tag_update(obedit->data, 0);
5835  }
5836  }
5837  MEM_freeN(objects);
5838 
5839  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
5840 }
5841 
5842 static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
5843 {
5844  Object *obedit = CTX_data_edit_object(C);
5845  ListBase *editnurb = object_editcurve_get(obedit);
5846  uiPopupMenu *pup;
5847  uiLayout *layout;
5848 
5849  if (obedit->type == OB_SURF) {
5850  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
5851  if (nu->pntsu > 1 || nu->pntsv > 1) {
5852  if (nu->type == CU_NURBS) {
5853  pup = UI_popup_menu_begin(C, IFACE_("Direction"), ICON_NONE);
5854  layout = UI_popup_menu_layout(pup);
5855  uiItemsEnumO(layout, op->type->idname, "direction");
5856  UI_popup_menu_end(C, pup);
5857  return OPERATOR_INTERFACE;
5858  }
5859  }
5860  }
5861  }
5862 
5863  return toggle_cyclic_exec(C, op);
5864 }
5865 
5867 {
5868  static const EnumPropertyItem direction_items[] = {
5869  {0, "CYCLIC_U", 0, "Cyclic U", ""},
5870  {1, "CYCLIC_V", 0, "Cyclic V", ""},
5871  {0, NULL, 0, NULL, NULL},
5872  };
5873 
5874  /* identifiers */
5875  ot->name = "Toggle Cyclic";
5876  ot->description = "Make active spline closed/opened loop";
5877  ot->idname = "CURVE_OT_cyclic_toggle";
5878 
5879  /* api callbacks */
5883 
5884  /* flags */
5886 
5887  /* properties */
5888  RNA_def_enum(ot->srna,
5889  "direction",
5890  direction_items,
5891  0,
5892  "Direction",
5893  "Direction to make surface cyclic in");
5894 }
5895 
5898 /* -------------------------------------------------------------------- */
5903 {
5904  ViewLayer *view_layer = CTX_data_view_layer(C);
5905  View3D *v3d = CTX_wm_view3d(C);
5906  int ok = -1;
5907 
5908  uint objects_len = 0;
5910  view_layer, CTX_wm_view3d(C), &objects_len);
5911  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
5912  Object *obedit = objects[ob_index];
5913  Curve *cu = obedit->data;
5914 
5915  if (!ED_curve_select_check(v3d, cu->editnurb)) {
5916  continue;
5917  }
5918 
5919  ListBase newnurb = {NULL, NULL};
5920  adduplicateflagNurb(obedit, v3d, &newnurb, SELECT, false);
5921 
5922  if (BLI_listbase_is_empty(&newnurb)) {
5923  ok = MAX2(ok, 0);
5924  continue;
5925  }
5926 
5927  ok = 1;
5928  BLI_movelisttolist(object_editcurve_get(obedit), &newnurb);
5931  }
5932  MEM_freeN(objects);
5933 
5934  if (ok == 0) {
5935  BKE_report(op->reports, RPT_ERROR, "Cannot duplicate current selection");
5936  return OPERATOR_CANCELLED;
5937  }
5938  return OPERATOR_FINISHED;
5939 }
5940 
5942 {
5943  /* identifiers */
5944  ot->name = "Duplicate Curve";
5945  ot->description = "Duplicate selected control points";
5946  ot->idname = "CURVE_OT_duplicate";
5947 
5948  /* api callbacks */
5949  ot->exec = duplicate_exec;
5951 
5952  /* flags */
5954 }
5955 
5958 /* -------------------------------------------------------------------- */
5962 static bool curve_delete_vertices(Object *obedit, View3D *v3d)
5963 {
5964  if (obedit->type == OB_SURF) {
5965  ed_surf_delete_selected(obedit);
5966  }
5967  else {
5968  ed_curve_delete_selected(obedit, v3d);
5969  }
5970 
5971  return true;
5972 }
5973 
5974 static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split)
5975 {
5976  Curve *cu = obedit->data;
5977  EditNurb *editnurb = cu->editnurb;
5978  ListBase *nubase = &editnurb->nurbs, newnurb = {NULL, NULL};
5979  Nurb *nu1;
5980  BezTriple *bezt, *bezt1, *bezt2;
5981  BPoint *bp, *bp1, *bp2;
5982  int a, b, starta, enda, cut, cyclicut;
5983 
5984  LISTBASE_FOREACH (Nurb *, nu, nubase) {
5985  nu1 = NULL;
5986  starta = enda = cut = -1;
5987  cyclicut = 0;
5988 
5989  if (nu->type == CU_BEZIER) {
5990  for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
5991  if (!BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
5992  enda = a;
5993  if (starta == -1) {
5994  starta = a;
5995  }
5996  if (a < nu->pntsu - 1) {
5997  continue;
5998  }
5999  }
6000  else if (a < nu->pntsu - 1 && !BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt + 1)) {
6001  /* if just single selected point then continue */
6002  continue;
6003  }
6004 
6005  if (starta >= 0) {
6006  /* got selected segment, now check where and copy */
6007  if (starta <= 1 && a == nu->pntsu - 1) {
6008  /* copying all points in spline */
6009  if (starta == 1 && enda != a) {
6010  nu->flagu &= ~CU_NURB_CYCLIC;
6011  }
6012 
6013  starta = 0;
6014  enda = a;
6015  cut = enda - starta + 1;
6016  nu1 = BKE_nurb_copy(nu, cut, 1);
6017  }
6018  else if (starta == 0) {
6019  /* if start of curve copy next end point */
6020  enda++;
6021  cut = enda - starta + 1;
6022  bezt1 = &nu->bezt[nu->pntsu - 1];
6023  bezt2 = &nu->bezt[nu->pntsu - 2];
6024 
6025  if ((nu->flagu & CU_NURB_CYCLIC) && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1) &&
6027  /* check if need to join start of spline to end */
6028  nu1 = BKE_nurb_copy(nu, cut + 1, 1);
6029  ED_curve_beztcpy(editnurb, &nu1->bezt[1], nu->bezt, cut);
6030  starta = nu->pntsu - 1;
6031  cut = 1;
6032  }
6033  else {
6034  if (nu->flagu & CU_NURB_CYCLIC) {
6035  cyclicut = cut;
6036  }
6037  else {
6038  nu1 = BKE_nurb_copy(nu, cut, 1);
6039  }
6040  }
6041  }
6042  else if (enda == nu->pntsu - 1) {
6043  /* if end of curve copy previous start point */
6044  starta--;
6045  cut = enda - starta + 1;
6046  bezt1 = nu->bezt;
6047  bezt2 = &nu->bezt[1];
6048 
6049  if ((nu->flagu & CU_NURB_CYCLIC) && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1) &&
6051  /* check if need to join start of spline to end */
6052  nu1 = BKE_nurb_copy(nu, cut + 1, 1);
6053  ED_curve_beztcpy(editnurb, &nu1->bezt[cut], nu->bezt, 1);
6054  }
6055  else if (cyclicut != 0) {
6056  /* if cyclicut exists it is a cyclic spline, start and end should be connected */
6057  nu1 = BKE_nurb_copy(nu, cut + cyclicut, 1);
6058  ED_curve_beztcpy(editnurb, &nu1->bezt[cut], nu->bezt, cyclicut);
6059  cyclicut = 0;
6060  }
6061  else {
6062  nu1 = BKE_nurb_copy(nu, cut, 1);
6063  }
6064  }
6065  else {
6066  /* mid spline selection, copy adjacent start and end */
6067  starta--;
6068  enda++;
6069  cut = enda - starta + 1;
6070  nu1 = BKE_nurb_copy(nu, cut, 1);
6071  }
6072 
6073  if (nu1 != NULL) {
6074  ED_curve_beztcpy(editnurb, nu1->bezt, &nu->bezt[starta], cut);
6075  BLI_addtail(&newnurb, nu1);
6076 
6077  if (starta != 0 || enda != nu->pntsu - 1) {
6078  nu1->flagu &= ~CU_NURB_CYCLIC;
6079  }
6080  nu1 = NULL;
6081  }
6082  starta = enda = -1;
6083  }
6084  }
6085 
6086  if (!split && cut != -1 && nu->pntsu > 2 && !(nu->flagu & CU_NURB_CYCLIC)) {
6087  /* start and points copied if connecting segment was deleted and not cyclic spline */
6088  bezt1 = nu->bezt;
6089  bezt2 = &nu->bezt[1];
6090 
6092  nu1 = BKE_nurb_copy(nu, 1, 1);
6093  ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1);
6094  BLI_addtail(&newnurb, nu1);
6095  }
6096 
6097  bezt1 = &nu->bezt[nu->pntsu - 1];
6098  bezt2 = &nu->bezt[nu->pntsu - 2];
6099 
6101  nu1 = BKE_nurb_copy(nu, 1, 1);
6102  ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1);
6103  BLI_addtail(&newnurb, nu1);
6104  }
6105  }
6106  }
6107  else if (nu->pntsv >= 1) {
6108  int u, v;
6109 
6110  if (isNurbselV(nu, &u, SELECT)) {
6111  for (a = 0, bp = nu->bp; a < nu->pntsu; a++, bp++) {
6112  if (!(bp->f1 & SELECT)) {
6113  enda = a;
6114  if (starta == -1) {
6115  starta = a;
6116  }
6117  if (a < nu->pntsu - 1) {
6118  continue;
6119  }
6120  }
6121  else if (a < nu->pntsu - 1 && !((bp + 1)->f1 & SELECT)) {
6122  /* if just single selected point then continue */
6123  continue;
6124  }
6125 
6126  if (starta >= 0) {
6127  /* got selected segment, now check where and copy */
6128  if (starta <= 1 && a == nu->pntsu - 1) {
6129  /* copying all points in spline */
6130  if (starta == 1 && enda != a) {
6131  nu->flagu &= ~CU_NURB_CYCLIC;
6132  }
6133 
6134  starta = 0;
6135  enda = a;
6136  cut = enda - starta + 1;
6137  nu1 = BKE_nurb_copy(nu, cut, nu->pntsv);
6138  }
6139  else if (starta == 0) {
6140  /* if start of curve copy next end point */
6141  enda++;
6142  cut = enda - starta + 1;
6143  bp1 = &nu->bp[nu->pntsu - 1];
6144  bp2 = &nu->bp[nu->pntsu - 2];
6145 
6146  if ((nu->flagu & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6147  /* check if need to join start of spline to end */
6148  nu1 = BKE_nurb_copy(nu, cut + 1, nu->pntsv);
6149  for (b = 0; b < nu->pntsv; b++) {
6151  editnurb, &nu1->bp[b * nu1->pntsu + 1], &nu->bp[b * nu->pntsu], cut);
6152  }
6153  starta = nu->pntsu - 1;
6154  cut = 1;
6155  }
6156  else {
6157  if (nu->flagu & CU_NURB_CYCLIC) {
6158  cyclicut = cut;
6159  }
6160  else {
6161  nu1 = BKE_nurb_copy(nu, cut, nu->pntsv);
6162  }
6163  }
6164  }
6165  else if (enda == nu->pntsu - 1) {
6166  /* if end of curve copy previous start point */
6167  starta--;
6168  cut = enda - starta + 1;
6169  bp1 = nu->bp;
6170  bp2 = &nu->bp[1];
6171 
6172  if ((nu->flagu & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6173  /* check if need to join start of spline to end */
6174  nu1 = BKE_nurb_copy(nu, cut + 1, nu->pntsv);
6175  for (b = 0; b < nu->pntsv; b++) {
6177  editnurb, &nu1->bp[b * nu1->pntsu + cut], &nu->bp[b * nu->pntsu], 1);
6178  }
6179  }
6180  else if (cyclicut != 0) {
6181  /* if cyclicut exists it is a cyclic spline, start and end should be connected */
6182  nu1 = BKE_nurb_copy(nu, cut + cyclicut, nu->pntsv);
6183  for (b = 0; b < nu->pntsv; b++) {
6185  editnurb, &nu1->bp[b * nu1->pntsu + cut], &nu->bp[b * nu->pntsu], cyclicut);
6186  }
6187  }
6188  else {
6189  nu1 = BKE_nurb_copy(nu, cut, nu->pntsv);
6190  }
6191  }
6192  else {
6193  /* mid spline selection, copy adjacent start and end */
6194  starta--;
6195  enda++;
6196  cut = enda - starta + 1;
6197  nu1 = BKE_nurb_copy(nu, cut, nu->pntsv);
6198  }
6199 
6200  if (nu1 != NULL) {
6201  for (b = 0; b < nu->pntsv; b++) {
6203  editnurb, &nu1->bp[b * nu1->pntsu], &nu->bp[b * nu->pntsu + starta], cut);
6204  }
6205  BLI_addtail(&newnurb, nu1);
6206 
6207  if (starta != 0 || enda != nu->pntsu - 1) {
6208  nu1->flagu &= ~CU_NURB_CYCLIC;
6209  }
6210  nu1 = NULL;
6211  }
6212  starta = enda = -1;
6213  }
6214  }
6215 
6216  if (!split && cut != -1 && nu->pntsu > 2 && !(nu->flagu & CU_NURB_CYCLIC)) {
6217  /* start and points copied if connecting segment was deleted and not cyclic spline */
6218  bp1 = nu->bp;
6219  bp2 = &nu->bp[1];
6220 
6221  if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6222  nu1 = BKE_nurb_copy(nu, 1, nu->pntsv);
6223  for (b = 0; b < nu->pntsv; b++) {
6224  ED_curve_bpcpy(editnurb, &nu1->bp[b], &nu->bp[b * nu->pntsu], 1);
6225  }
6226  BLI_addtail(&newnurb, nu1);
6227  }
6228 
6229  bp1 = &nu->bp[nu->pntsu - 1];
6230  bp2 = &nu->bp[nu->pntsu - 2];
6231 
6232  if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6233  nu1 = BKE_nurb_copy(nu, 1, nu->pntsv);
6234  for (b = 0; b < nu->pntsv; b++) {
6235  ED_curve_bpcpy(editnurb, &nu1->bp[b], &nu->bp[b * nu->pntsu + nu->pntsu - 1], 1);
6236  }
6237  BLI_addtail(&newnurb, nu1);
6238  }
6239  }
6240  }
6241  else if (isNurbselU(nu, &v, SELECT)) {
6242  for (a = 0, bp = nu->bp; a < nu->pntsv; a++, bp += nu->pntsu) {
6243  if (!(bp->f1 & SELECT)) {
6244  enda = a;
6245  if (starta == -1) {
6246  starta = a;
6247  }
6248  if (a < nu->pntsv - 1) {
6249  continue;
6250  }
6251  }
6252  else if (a < nu->pntsv - 1 && !((bp + nu->pntsu)->f1 & SELECT)) {
6253  /* if just single selected point then continue */
6254  continue;
6255  }
6256 
6257  if (starta >= 0) {
6258  /* got selected segment, now check where and copy */
6259  if (starta <= 1 && a == nu->pntsv - 1) {
6260  /* copying all points in spline */
6261  if (starta == 1 && enda != a) {
6262  nu->flagv &= ~CU_NURB_CYCLIC;
6263  }
6264 
6265  starta = 0;
6266  enda = a;
6267  cut = enda - starta + 1;
6268  nu1 = BKE_nurb_copy(nu, nu->pntsu, cut);
6269  }
6270  else if (starta == 0) {
6271  /* if start of curve copy next end point */
6272  enda++;
6273  cut = enda - starta + 1;
6274  bp1 = &nu->bp[nu->pntsv * nu->pntsu - nu->pntsu];
6275  bp2 = &nu->bp[nu->pntsv * nu->pntsu - (nu->pntsu * 2)];
6276 
6277  if ((nu->flagv & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6278  /* check if need to join start of spline to end */
6279  nu1 = BKE_nurb_copy(nu, nu->pntsu, cut + 1);
6280  ED_curve_bpcpy(editnurb, &nu1->bp[nu->pntsu], nu->bp, cut * nu->pntsu);
6281  starta = nu->pntsv - 1;
6282  cut = 1;
6283  }
6284  else {
6285  if (nu->flagv & CU_NURB_CYCLIC) {
6286  cyclicut = cut;
6287  }
6288  else {
6289  nu1 = BKE_nurb_copy(nu, nu->pntsu, cut);
6290  }
6291  }
6292  }
6293  else if (enda == nu->pntsv - 1) {
6294  /* if end of curve copy previous start point */
6295  starta--;
6296  cut = enda - starta + 1;
6297  bp1 = nu->bp;
6298  bp2 = &nu->bp[nu->pntsu];
6299 
6300  if ((nu->flagv & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6301  /* check if need to join start of spline to end */
6302  nu1 = BKE_nurb_copy(nu, nu->pntsu, cut + 1);
6303  ED_curve_bpcpy(editnurb, &nu1->bp[cut * nu->pntsu], nu->bp, nu->pntsu);
6304  }
6305  else if (cyclicut != 0) {
6306  /* if cyclicut exists it is a cyclic spline, start and end should be connected */
6307  nu1 = BKE_nurb_copy(nu, nu->pntsu, cut + cyclicut);
6308  ED_curve_bpcpy(editnurb, &nu1->bp[cut * nu->pntsu], nu->bp, nu->pntsu * cyclicut);
6309  cyclicut = 0;
6310  }
6311  else {
6312  nu1 = BKE_nurb_copy(nu, nu->pntsu, cut);
6313  }
6314  }
6315  else {
6316  /* mid spline selection, copy adjacent start and end */
6317  starta--;
6318  enda++;
6319  cut = enda - starta + 1;
6320  nu1 = BKE_nurb_copy(nu, nu->pntsu, cut);
6321  }
6322 
6323  if (nu1 != NULL) {
6324  ED_curve_bpcpy(editnurb, nu1->bp, &nu->bp[starta * nu->pntsu], cut * nu->pntsu);
6325  BLI_addtail(&newnurb, nu1);
6326 
6327  if (starta != 0 || enda != nu->pntsv - 1) {
6328  nu1->flagv &= ~CU_NURB_CYCLIC;
6329  }
6330  nu1 = NULL;
6331  }
6332  starta = enda = -1;
6333  }
6334  }
6335 
6336  if (!split && cut != -1 && nu->pntsv > 2 && !(nu->flagv & CU_NURB_CYCLIC)) {
6337  /* start and points copied if connecting segment was deleted and not cyclic spline */
6338  bp1 = nu->bp;
6339  bp2 = &nu->bp[nu->pntsu];
6340 
6341  if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6342  nu1 = BKE_nurb_copy(nu, nu->pntsu, 1);
6343  ED_curve_bpcpy(editnurb, nu1->bp, nu->bp, nu->pntsu);
6344  BLI_addtail(&newnurb, nu1);
6345  }
6346 
6347  bp1 = &nu->bp[nu->pntsu * nu->pntsv - nu->pntsu];
6348  bp2 = &nu->bp[nu->pntsu * nu->pntsv - (nu->pntsu * 2)];
6349 
6350  if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) {
6351  nu1 = BKE_nurb_copy(nu, nu->pntsu, 1);
6353  editnurb, nu1->bp, &nu->bp[nu->pntsu * nu->pntsv - nu->pntsu], nu->pntsu);
6354  BLI_addtail(&newnurb, nu1);
6355  }
6356  }
6357  }
6358  else {
6359  /* selection not valid, just copy nurb to new list */
6360  nu1 = BKE_nurb_copy(nu, nu->pntsu, nu->pntsv);
6361  ED_curve_bpcpy(editnurb, nu1->bp, nu->bp, nu->pntsu * nu->pntsv);
6362  BLI_addtail(&newnurb, nu1);
6363  }
6364  }
6365  }
6366 
6367  LISTBASE_FOREACH (Nurb *, nu, &newnurb) {
6368  if (nu->type == CU_BEZIER) {
6369  if (split) {
6370  /* deselect for split operator */
6371  for (b = 0, bezt1 = nu->bezt; b < nu->pntsu; b++, bezt1++) {
6372  select_beztriple(bezt1, DESELECT, SELECT, true);
6373  }
6374  }
6375 
6377  }
6378  else {
6379  if (split) {
6380  /* deselect for split operator */
6381  for (b = 0, bp1 = nu->bp; b < nu->pntsu * nu->pntsv; b++, bp1++) {
6383  }
6384  }
6385 
6388 
6389  if (nu->pntsv > 1) {
6392  }
6393  }
6394  }
6395 
6396  keyIndex_delNurbList(editnurb, nubase);
6397  BKE_nurbList_free(nubase);
6398  BLI_movelisttolist(nubase, &newnurb);
6399 
6400  return true;
6401 }
6402 
6404 {
6405  Main *bmain = CTX_data_main(C);
6406  View3D *v3d = CTX_wm_view3d(C);
6407  eCurveElem_Types type = RNA_enum_get(op->ptr, "type");
6408  ViewLayer *view_layer = CTX_data_view_layer(C);
6409  uint objects_len = 0;
6411  view_layer, CTX_wm_view3d(C), &objects_len);
6412  bool changed_multi = false;
6413 
6414  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6415  Object *obedit = objects[ob_index];
6416  Curve *cu = (Curve *)obedit->data;
6417  bool changed = false;
6418 
6420  continue;
6421  }
6422 
6423  if (type == CURVE_VERTEX) {
6424  changed = curve_delete_vertices(obedit, v3d);
6425  }
6426  else if (type == CURVE_SEGMENT) {
6427  changed = curve_delete_segments(obedit, v3d, false);
6428  }
6429  else {
6430  BLI_assert(0);
6431  }
6432 
6433  if (changed) {
6434  changed_multi = true;
6435  cu->actnu = cu->actvert = CU_ACT_NONE;
6436 
6437  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
6439  }
6440 
6442  DEG_id_tag_update(obedit->data, 0);
6443  }
6444  }
6445  MEM_freeN(objects);
6446 
6447  if (changed_multi) {
6448  return OPERATOR_FINISHED;
6449  }
6450  return OPERATOR_CANCELLED;
6451 }
6452 
6454  {CURVE_VERTEX, "VERT", 0, "Vertices", ""},
6455  {CURVE_SEGMENT, "SEGMENT", 0, "Segments", ""},
6456  {0, NULL, 0, NULL, NULL},
6457 };
6458 
6460  PointerRNA *UNUSED(ptr),
6461  PropertyRNA *UNUSED(prop),
6462  bool *r_free)
6463 {
6464  EnumPropertyItem *item = NULL;
6465  int totitem = 0;
6466 
6467  if (!C) { /* needed for docs and i18n tools */
6468  return curve_delete_type_items;
6469  }
6470 
6473  RNA_enum_item_end(&item, &totitem);
6474  *r_free = true;
6475 
6476  return item;
6477 }
6478 
6480 {
6481  PropertyRNA *prop;
6482 
6483  /* identifiers */
6484  ot->name = "Delete";
6485  ot->description = "Delete selected control points or segments";
6486  ot->idname = "CURVE_OT_delete";
6487 
6488  /* api callbacks */
6492 
6493  /* flags */
6495 
6496  /* properties */
6497  prop = RNA_def_enum(
6498  ot->srna, "type", curve_delete_type_items, 0, "Type", "Which elements to delete");
6501  ot->prop = prop;
6502 }
6503 
6506 /* -------------------------------------------------------------------- */
6510 static bool test_bezt_is_sel_any(const void *bezt_v, void *user_data)
6511 {
6512  View3D *v3d = user_data;
6513  const BezTriple *bezt = bezt_v;
6514  return BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
6515 }
6516 
6518 {
6519  Main *bmain = CTX_data_main(C);
6520  ViewLayer *view_layer = CTX_data_view_layer(C);
6521  View3D *v3d = CTX_wm_view3d(C);
6522 
6523  uint objects_len;
6525  view_layer, CTX_wm_view3d(C), &objects_len);
6526  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6527  Object *obedit = objects[ob_index];
6528  Curve *cu = (Curve *)obedit->data;
6529 
6531  continue;
6532  }
6533 
6534  ListBase *editnurb = object_editcurve_get(obedit);
6535 
6536  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
6537  if ((nu->type == CU_BEZIER) && (nu->pntsu > 2)) {
6538  uint span_step[2] = {nu->pntsu, nu->pntsu};
6539  uint span_len;
6540 
6541  while (BLI_array_iter_span(nu->bezt,
6542  nu->pntsu,
6543  (nu->flagu & CU_NURB_CYCLIC) != 0,
6544  false,
6546  v3d,
6547  span_step,
6548  &span_len)) {
6549  BezTriple *bezt_prev = &nu->bezt[mod_i(span_step[0] - 1, nu->pntsu)];
6550  BezTriple *bezt_next = &nu->bezt[mod_i(span_step[1] + 1, nu->pntsu)];
6551 
6552  int i_span_edge_len = span_len + 1;
6553  const uint dims = 3;
6554 
6555  const uint points_len = ((cu->resolu - 1) * i_span_edge_len) + 1;
6556  float *points = MEM_mallocN(points_len * dims * sizeof(float), __func__);
6557  float *points_stride = points;
6558  const int points_stride_len = (cu->resolu - 1);
6559 
6560  for (int segment = 0; segment < i_span_edge_len; segment++) {
6561  BezTriple *bezt_a = &nu->bezt[mod_i((span_step[0] + segment) - 1, nu->pntsu)];
6562  BezTriple *bezt_b = &nu->bezt[mod_i((span_step[0] + segment), nu->pntsu)];
6563 
6564  for (int axis = 0; axis < dims; axis++) {
6565  BKE_curve_forward_diff_bezier(bezt_a->vec[1][axis],
6566  bezt_a->vec[2][axis],
6567  bezt_b->vec[0][axis],
6568  bezt_b->vec[1][axis],
6569  points_stride + axis,
6570  points_stride_len,
6571  dims * sizeof(float));
6572  }
6573 
6574  points_stride += dims * points_stride_len;
6575  }
6576 
6577  BLI_assert(points_stride + dims == points + (points_len * dims));
6578 
6579  float tan_l[3], tan_r[3], error_sq_dummy;
6580  uint error_index_dummy;
6581 
6582  sub_v3_v3v3(tan_l, bezt_prev->vec[1], bezt_prev->vec[2]);
6583  normalize_v3(tan_l);
6584  sub_v3_v3v3(tan_r, bezt_next->vec[0], bezt_next->vec[1]);
6585  normalize_v3(tan_r);
6586 
6587  curve_fit_cubic_to_points_single_fl(points,
6588  points_len,
6589  NULL,
6590  dims,
6591  FLT_EPSILON,
6592  tan_l,
6593  tan_r,
6594  bezt_prev->vec[2],
6595  bezt_next->vec[0],
6596  &error_sq_dummy,
6597  &error_index_dummy);
6598 
6599  if (!ELEM(bezt_prev->h2, HD_FREE, HD_ALIGN)) {
6600  bezt_prev->h2 = (bezt_prev->h2 == HD_VECT) ? HD_FREE : HD_ALIGN;
6601  }
6602  if (!ELEM(bezt_next->h1, HD_FREE, HD_ALIGN)) {
6603  bezt_next->h1 = (bezt_next->h1 == HD_VECT) ? HD_FREE : HD_ALIGN;
6604  }
6605 
6606  MEM_freeN(points);
6607  }
6608  }
6609  }
6610 
6611  ed_curve_delete_selected(obedit, v3d);
6612 
6613  cu->actnu = cu->actvert = CU_ACT_NONE;
6614 
6615  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
6617  }
6618 
6620  DEG_id_tag_update(obedit->data, 0);
6621  }
6622  MEM_freeN(objects);
6623  return OPERATOR_FINISHED;
6624 }
6625 
6627 {
6628  /* identifiers */
6629  ot->name = "Dissolve Vertices";
6630  ot->description = "Delete selected control points, correcting surrounding handles";
6631  ot->idname = "CURVE_OT_dissolve_verts";
6632 
6633  /* api callbacks */
6636 
6637  /* flags */
6639 }
6640 
6643 /* -------------------------------------------------------------------- */
6647 static bool nurb_bezt_flag_any(const Nurb *nu, const char flag_test)
6648 {
6649  BezTriple *bezt = nu->bezt;
6650  int i;
6651 
6652  for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
6653  if (bezt->f2 & flag_test) {
6654  return true;
6655  }
6656  }
6657 
6658  return false;
6659 }
6660 
6662 {
6663  Main *bmain = CTX_data_main(C);
6664  const float error_sq_max = FLT_MAX;
6665  float ratio = RNA_float_get(op->ptr, "ratio");
6666  bool all_supported_multi = true;
6667 
6668  ViewLayer *view_layer = CTX_data_view_layer(C);
6669  uint objects_len = 0;
6671  view_layer, CTX_wm_view3d(C), &objects_len);
6672  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6673  Object *obedit = objects[ob_index];
6674  Curve *cu = (Curve *)obedit->data;
6675  bool all_supported = true;
6676  bool changed = false;
6677 
6678  {
6679  ListBase *editnurb = object_editcurve_get(obedit);
6680 
6681  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
6682  if (nu->type == CU_BEZIER) {
6683  if ((nu->pntsu > 2) && nurb_bezt_flag_any(nu, SELECT)) {
6684  const int error_target_len = max_ii(2, nu->pntsu * ratio);
6685  if (error_target_len != nu->pntsu) {
6686  BKE_curve_decimate_nurb(nu, cu->resolu, error_sq_max, error_target_len);
6687  changed = true;
6688  }
6689  }
6690  }
6691  else {
6692  all_supported = false;
6693  }
6694  }
6695  }
6696 
6697  if (all_supported == false) {
6698  all_supported_multi = false;
6699  }
6700 
6701  if (changed) {
6702  cu->actnu = cu->actvert = CU_ACT_NONE;
6703  if (ED_curve_updateAnimPaths(bmain, obedit->data)) {
6705  }
6706 
6708  DEG_id_tag_update(obedit->data, 0);
6709  }
6710  }
6711 
6712  if (all_supported_multi == false) {
6713  BKE_report(op->reports, RPT_WARNING, "Only bezier curves are supported");
6714  }
6715 
6716  MEM_freeN(objects);
6717 
6718  return OPERATOR_FINISHED;
6719 }
6720 
6722 {
6723  /* identifiers */
6724  ot->name = "Decimate Curve";
6725  ot->description = "Simplify selected curves";
6726  ot->idname = "CURVE_OT_decimate";
6727 
6728  /* api callbacks */
6731 
6732  /* flags */
6734 
6735  /* properties */
6736  RNA_def_float_factor(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f);
6737 }
6738 
6741 /* -------------------------------------------------------------------- */
6746 {
6747  View3D *v3d = CTX_wm_view3d(C);
6748  ViewLayer *view_layer = CTX_data_view_layer(C);
6749  int clear = (STREQ(op->idname, "CURVE_OT_shade_flat"));
6750  uint objects_len;
6752  view_layer, CTX_wm_view3d(C), &objects_len);
6753  int ret_value = OPERATOR_CANCELLED;
6754 
6755  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6756  Object *obedit = objects[ob_index];
6757  ListBase *editnurb = object_editcurve_get(obedit);
6758 
6759  if (obedit->type != OB_CURVE) {
6760  continue;
6761  }
6762 
6763  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
6764  if (ED_curve_nurb_select_check(v3d, nu)) {
6765  if (!clear) {
6766  nu->flag |= CU_SMOOTH;
6767  }
6768  else {
6769  nu->flag &= ~CU_SMOOTH;
6770  }
6771  }
6772  }
6773 
6775  DEG_id_tag_update(obedit->data, 0);
6776  ret_value = OPERATOR_FINISHED;
6777  }
6778 
6779  MEM_freeN(objects);
6780 
6781  return ret_value;
6782 }
6783 
6785 {
6786  /* identifiers */
6787  ot->name = "Shade Smooth";
6788  ot->idname = "CURVE_OT_shade_smooth";
6789  ot->description = "Set shading to smooth";
6790 
6791  /* api callbacks */
6794 
6795  /* flags */
6797 }
6798 
6800 {
6801  /* identifiers */
6802  ot->name = "Shade Flat";
6803  ot->idname = "CURVE_OT_shade_flat";
6804  ot->description = "Set shading to flat";
6805 
6806  /* api callbacks */
6809 
6810  /* flags */
6812 }
6813 
6816 /* -------------------------------------------------------------------- */
6825 {
6826  Main *bmain = CTX_data_main(C);
6828  Object *ob_active = CTX_data_active_object(C);
6829  Curve *cu;
6830  BezTriple *bezt;
6831  BPoint *bp;
6832  ListBase tempbase;
6833  float imat[4][4], cmat[4][4];
6834  int a;
6835  bool ok = false;
6836 
6837  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
6838  if (ob_iter == ob_active) {
6839  ok = true;
6840  break;
6841  }
6842  }
6843  CTX_DATA_END;
6844 
6845  /* that way the active object is always selected */
6846  if (ok == false) {
6847  BKE_report(op->reports, RPT_WARNING, "Active object is not a selected curve");
6848  return OPERATOR_CANCELLED;
6849  }
6850 
6851  BLI_listbase_clear(&tempbase);
6852 
6853  /* Inverse transform for all selected curves in this object,
6854  * See #object_join_exec for detailed comment on why the safe version is used. */
6855  invert_m4_m4_safe_ortho(imat, ob_active->obmat);
6856 
6857  Curve *cu_active = ob_active->data;
6858 
6859  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
6860  if (ob_iter->type == ob_active->type) {
6861  if (ob_iter != ob_active) {
6862 
6863  cu = ob_iter->data;
6864 
6865  if (cu->nurb.first) {
6866  /* watch it: switch order here really goes wrong */
6867  mul_m4_m4m4(cmat, imat, ob_iter->obmat);
6868 
6869  /* Compensate for different bevel depth. */
6870  bool do_radius = false;
6871  float compensate_radius = 0.0f;
6872  if (cu->ext2 != 0.0f && cu_active->ext2 != 0.0f) {
6873  float compensate_scale = mat4_to_scale(cmat);
6874  compensate_radius = cu->ext2 / cu_active->ext2 * compensate_scale;
6875  do_radius = true;
6876  }
6877 
6878  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
6879  Nurb *newnu = BKE_nurb_duplicate(nu);
6880  if (ob_active->totcol) { /* TODO, merge material lists */
6881  CLAMP(newnu->mat_nr, 0, ob_active->totcol - 1);
6882  }
6883  else {
6884  newnu->mat_nr = 0;
6885  }
6886  BLI_addtail(&tempbase, newnu);
6887 
6888  if ((bezt = newnu->bezt)) {
6889  a = newnu->pntsu;
6890  while (a--) {
6891  /* Compensate for different bevel depth. */
6892  if (do_radius) {
6893  bezt->radius *= compensate_radius;
6894  }
6895 
6896  mul_m4_v3(cmat, bezt->vec[0]);
6897  mul_m4_v3(cmat, bezt->vec[1]);
6898  mul_m4_v3(cmat, bezt->vec[2]);
6899  bezt++;
6900  }
6901  BKE_nurb_handles_calc(newnu);
6902  }
6903  if ((bp = newnu->bp)) {
6904  a = newnu->pntsu * nu->pntsv;
6905  while (a--) {
6906  mul_m4_v3(cmat, bp->vec);
6907  bp++;
6908  }
6909  }
6910  }
6911  }
6912 
6913  ED_object_base_free_and_unlink(bmain, scene, ob_iter);
6914  }
6915  }
6916  }
6917  CTX_DATA_END;
6918 
6919  cu = ob_active->data;
6920  BLI_movelisttolist(&cu->nurb, &tempbase);
6921 
6922  if (ob_active->type == OB_CURVE && CU_IS_2D(cu)) {
6923  /* Account for mixed 2D/3D curves when joining */
6925  }
6926 
6927  DEG_relations_tag_update(bmain); /* because we removed object(s), call before editmode! */
6928 
6931 
6934 
6935  return OPERATOR_FINISHED;
6936 }
6937 
6940 /* -------------------------------------------------------------------- */
6945 {
6946  ViewLayer *view_layer = CTX_data_view_layer(C);
6947  View3D *v3d = CTX_wm_view3d(C);
6948 
6949  uint objects_len;
6951  view_layer, CTX_wm_view3d(C), &objects_len);
6952  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
6953  Object *obedit = objects[ob_index];
6954  Curve *cu = obedit->data;
6955 
6956  if (!ED_curve_select_check(v3d, cu->editnurb)) {
6957  continue;
6958  }
6959 
6960  ListBase *editnurb = object_editcurve_get(obedit);
6961  BezTriple *bezt;
6962  BPoint *bp;
6963  int a;
6964 
6965  LISTBASE_FOREACH (Nurb *, nu, editnurb) {
6966  if (nu->bezt) {
6967  bezt = nu->bezt;
6968  a = nu->pntsu;
6969  while (a--) {
6970  if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
6971  bezt->tilt = 0.0;
6972  }
6973  bezt++;
6974  }
6975  }
6976  else if (nu->bp) {
6977  bp = nu->bp;
6978  a = nu->pntsu * nu->pntsv;
6979  while (a--) {
6980  if (bp->f1 & SELECT) {
6981  bp->tilt = 0.0f;
6982  }
6983  bp++;
6984  }
6985  }
6986  }
6987 
6989  DEG_id_tag_update(obedit->data, 0);
6990  }
6991  MEM_freeN(objects);
6992  return OPERATOR_FINISHED;
6993 }
6994 
6996 {
6997  /* identifiers */
6998  ot->name = "Clear Tilt";
6999  ot->idname = "CURVE_OT_tilt_clear";
7000  ot->description = "Clear the tilt of selected control points";
7001 
7002  /* api callbacks */
7003  ot->exec = clear_tilt_exec;
7005 
7006  /* flags */
7008 }
7009 
7010 void ED_curve_beztcpy(EditNurb *editnurb, BezTriple *dst, BezTriple *src, int count)
7011 {
7012  memcpy(dst, src, count * sizeof(BezTriple));
7013  keyIndex_updateBezt(editnurb, src, dst, count);
7014 }
7015 
7016 void ED_curve_bpcpy(EditNurb *editnurb, BPoint *dst, BPoint *src, int count)
7017 {
7018  memcpy(dst, src, count * sizeof(BPoint));
7019  keyIndex_updateBP(editnurb, src, dst, count);
7020 }
7021 
7024 /* -------------------------------------------------------------------- */
7029 {
7030  Object *object = CTX_data_active_object(C);
7031 
7032  return object && ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT);
7033 }
7034 
7036 {
7037  /* Need to ensure the dependency graph is fully evaluated, so the display list is at a correct
7038  * state. */
7040  (void)depsgraph;
7041 
7042  Object *object = CTX_data_active_object(C);
7043  Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
7044  Curve *curve = (Curve *)object->data;
7045  float min[3], max[3], size[3], loc[3];
7046  int a;
7047 
7048  BLI_assert(object_eval->runtime.curve_cache != NULL);
7049 
7050  INIT_MINMAX(min, max);
7051  BKE_displist_minmax(&object_eval->runtime.curve_cache->disp, min, max);
7052 
7053  mid_v3_v3v3(loc, min, max);
7054 
7055  size[0] = (max[0] - min[0]) / 2.0f;
7056  size[1] = (max[1] - min[1]) / 2.0f;
7057  size[2] = (max[2] - min[2]) / 2.0f;
7058 
7059  for (a = 0; a < 3; a++) {
7060  if (size[a] == 0.0f) {
7061  size[a] = 1.0f;
7062  }
7063  else if (size[a] > 0.0f && size[a] < 0.00001f) {
7064  size[a] = 0.00001f;
7065  }
7066  else if (size[a] < 0.0f && size[a] > -0.00001f) {
7067  size[a] = -0.00001f;
7068  }
7069  }
7070 
7071  copy_v3_v3(curve->loc, loc);
7073 
7074  curve->texflag &= ~CU_AUTOSPACE;
7075 
7078 
7079  return OPERATOR_FINISHED;
7080 }
7081 
7083 {
7084  /* identifiers */
7085  ot->name = "Match Texture Space";
7086  ot->idname = "CURVE_OT_match_texture_space";
7087  ot->description = "Match texture space to object's bounding box";
7088 
7089  /* api callbacks */
7092 
7093  /* flags */
7095 }
7096 
typedef float(TangentPoint)[2]
Blender kernel action and pose functionality.
void BKE_action_groups_reconstruct(struct bAction *act)
Definition: action.c:505
void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu)
Definition: action.c:538
struct AnimData * BKE_animdata_from_id(struct ID *id)
Definition: anim_data.c:96
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:252
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
#define CTX_DATA_END
Definition: BKE_context.h:260
void BKE_nurb_handles_calc(struct Nurb *nu)
Definition: curve.c:4092
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert)
Definition: curve.c:5146
void BKE_nurb_handle_calc_simple(struct Nurb *nu, struct BezTriple *bezt)
Definition: curve.c:4124
void BKE_nurb_direction_switch(struct Nurb *nu)
Definition: curve.c:4544
void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, const bool is_fcurve, const char smoothing)
Definition: curve.c:4069
void BKE_nurb_knot_calc_v(struct Nurb *nu)
Definition: curve.c:1308
#define KNOTSU(nu)
Definition: BKE_curve.h:68
bool BKE_nurb_order_clamp_u(struct Nurb *nu)
Definition: curve.c:4901
struct BezTriple * BKE_nurb_bezt_get_next(struct Nurb *nu, struct BezTriple *bezt)
Definition: curve.c:990
void BKE_nurb_free(struct Nurb *nu)
Definition: curve.c:633
void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, const void *vert)
#define CU_IS_2D(cu)
Definition: BKE_curve.h:83
struct Nurb * BKE_nurb_duplicate(const struct Nurb *nu)
void BKE_curve_nurb_vert_active_validate(struct Curve *cu)
Definition: curve.c:5173
void BKE_curve_editNurb_free(struct Curve *cu)
Definition: curve.c:388
#define KNOTSV(nu)
Definition: BKE_curve.h:70
void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv)
Definition: curve.c:373
struct BPoint * BKE_nurb_bpoint_get_next(struct Nurb *nu, struct BPoint *bp)
Definition: curve.c:1011
void BKE_nurbList_handles_set(struct ListBase *editnurb, const char code)
Definition: curve.c:4333
struct Nurb * BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv)
Definition: curve.c:713
void BKE_nurb_project_2d(struct Nurb *nu)
Definition: curve.c:748
void BKE_curve_dimension_update(struct Curve *cu)
Definition: curve.c:467
void * BKE_curve_vert_active_get(struct Curve *cu)
Definition: curve.c:5107
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition: curve.c:1804
void BKE_nurb_knot_calc_u(struct Nurb *nu)
Definition: curve.c:1303
void BKE_nurbList_handles_recalculate(struct ListBase *editnurb, const bool calc_length, const uint8_t flag)
Definition: curve.c:4418
void BKE_nurbList_free(struct ListBase *lb)
Definition: curve.c:660
struct Nurb * BKE_curve_nurb_active_get(struct Curve *cu)
Definition: curve.c:5100
bool BKE_nurb_type_convert(struct Nurb *nu, const short type, const bool use_handles, const char **r_err_msg)
Definition: curve.c:4932
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
Definition: curve.c:4475
void BKE_nurb_handle_calc_simple_auto(struct Nurb *nu, struct BezTriple *bezt)
Definition: curve.c:4133
bool BKE_nurb_order_clamp_v(struct Nurb *nu)
Definition: curve.c:4915
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number)
Definition: curve.c:945
void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex)
Definition: curve.c:379
void BKE_curve_nurb_active_set(struct Curve *cu, const struct Nurb *nu)
void BKE_curve_decimate_nurb(struct Nurb *nu, const unsigned int resolu, const float error_sq_max, const unsigned int error_target_len)
display list (or rather multi purpose list) stuff.
void BKE_displist_minmax(const struct ListBase *dispbase, float min[3], float max[3])
void BKE_fcurve_free(struct FCurve *fcu)
Definition: fcurve.c:81
struct FCurve * BKE_fcurve_copy(const struct FCurve *fcu)
@ G_DEBUG
Definition: BKE_global.h:133
void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct ListBase *nurb)
bool BKE_keyblock_is_basis(struct Key *key, const int index)
Definition: key.c:2600
int BKE_keyblock_curve_element_count(struct ListBase *nurb)
Definition: key.c:2044
struct KeyBlock * BKE_keyblock_from_object(struct Object *ob)
Definition: key.c:1902
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:430
struct ID * BKE_id_copy(struct Main *bmain, const struct ID *id)
void id_us_min(struct ID *id)
Definition: lib_id.c:297
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
Generic array manipulation API.
#define BLI_array_iter_span(arr, arr_len, use_wrap, use_delimit_bounds, test_fn, user_data, span_step, r_span_len)
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:146
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:150
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
unsigned int BLI_ghash_len(GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:744
void * BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:924
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
GHash * BLI_ghash_ptr_new_ex(const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:180
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define M_SQRT2
Definition: BLI_math_base.h:47
MINLINE int max_ii(int a, int b)
MINLINE int mod_i(int i, int n)
MINLINE float interpf(float a, float b, float t)
#define M_PI
Definition: BLI_math_base.h:38
bool isect_ray_plane_v3(const float ray_origin[3], const float ray_direction[3], const float plane[4], float *r_lambda, const bool clip)
Definition: math_geom.c:1808
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void unit_m3(float m[3][3])
Definition: math_matrix.c:58
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:105
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
Definition: math_matrix.c:3287
void unit_m4(float m[4][4])
Definition: rct.c:1140
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1161
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2196
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:391
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
void interp_v4_v4v4(float r[4], const float a[4], const float b[4], const float t)
Definition: math_vector.c:58
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE void swap_v3_v3(float a[3], float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
size_t size_t char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNPACK2(a)
#define STRPREFIX(a, b)
#define INIT_MINMAX(min, max)
#define SWAP(type, a, b)
#define STREQLEN(a, b, n)
#define UNUSED(x)
#define MAX2(a, b)
#define ELEM(...)
#define IN_RANGE_INCL(a, b, c)
#define STREQ(a, b)
#define IFACE_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:599
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
#define SURF_SEEN
@ CU_BEZIER
@ CU_BSPLINE
@ CU_POLY
@ CU_NURBS
@ CU_CARDINAL
@ CU_SMOOTH
#define BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)
#define BEZT_SEL_ALL(bezt)
struct BPoint BPoint
#define CU_ACT_NONE
#define BEZT_DESEL_ALL(bezt)
@ CU_NURB_CYCLIC
@ CU_AUTOSPACE
@ HD_VECT
@ HD_FREE
@ HD_AUTO
@ HD_ALIGN
struct BezTriple BezTriple
@ KEY_RELATIVE
#define KEYELEM_FLOAT_LEN_BEZTRIPLE
#define KEYELEM_FLOAT_LEN_BPOINT
@ eModifierType_Hook
Object is a sort of wrapper for general info.
@ PARVERT1
@ PARVERT3
@ OB_SURF
@ OB_FONT
@ OB_CURVE
#define SCE_SNAP
#define SCE_SNAP_MODE_FACE
eDupli_ID_Flags
@ USER_DUP_ACT
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
struct Base * ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, const eDupli_ID_Flags dupflag)
Definition: object_add.c:3313
#define OBJECT_ADD_SIZE_MAXF
Definition: ED_object.h:288
void ED_object_base_activate(struct bContext *C, struct Base *base)
void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob)
Definition: object_add.c:1958
void ED_outliner_select_sync_from_object_tag(struct bContext *C)
Definition: outliner_sync.c:56
bool ED_operator_editsurfcurve(struct bContext *C)
Definition: screen_ops.c:541
bool ED_operator_editcurve(struct bContext *C)
Definition: screen_ops.c:560
bool ED_operator_editsurf(struct bContext *C)
Definition: screen_ops.c:580
@ TFM_TRANSLATION
Definition: ED_transform.h:46
SnapObjectContext * ED_transform_snap_object_context_create_view3d(struct Scene *scene, int flag, const struct ARegion *region, const struct View3D *v3d)
bool ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], const float prev_co[3], float *dist_px, float r_loc[3], float r_no[3])
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
#define DESELECT
Definition: ED_types.h:33
void ED_view3d_win_to_3d_int(const struct View3D *v3d, const struct ARegion *region, const float depth_pt[3], const int mval[2], float r_out[3])
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3])
void view3d_operator_needs_opengl(const struct bContext *C)
struct RegionView3D * ED_view3d_context_rv3d(struct bContext *C)
Definition: space_view3d.c:89
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
Group RGB to Bright Vector Camera CLAMP
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
#define NC_GEOM
Definition: WM_types.h:294
#define ND_DRAW
Definition: WM_types.h:362
#define ND_OB_ACTIVE
Definition: WM_types.h:340
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define NC_SCENE
Definition: WM_types.h:279
#define ND_LAYER_CONTENT
Definition: WM_types.h:354
#define ND_SELECT
Definition: WM_types.h:407
#define ND_KEYS
Definition: WM_types.h:364
#define NC_OBJECT
Definition: WM_types.h:280
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define SELECT
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
bool ED_curve_pick_vert(struct ViewContext *vc, short sel, struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle, struct Base **r_base)
void ED_curve_nurb_vert_selected_find(Curve *cu, View3D *v3d, Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp)
eEndPoint_Types
Definition: curve_intern.h:63
eCurveElem_Types
Definition: curve_intern.h:68
@ CURVE_VERTEX
Definition: curve_intern.h:69
@ CURVE_SEGMENT
Definition: curve_intern.h:70
@ HIDDEN
Definition: curve_intern.h:59
Scene scene
Curve curve
const Depsgraph * depsgraph
void * user_data
static bool curve_toggle_cyclic(View3D *v3d, ListBase *editnurb, int direction)
Definition: editcurve.c:5734
#define BEZT_VALUE(bezt)
static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
Definition: editcurve.c:5112
static void keyIndex_updateBP(EditNurb *editnurb, BPoint *bp, BPoint *newbp, int count)
Definition: editcurve.c:342
static int hide_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:3215
static bool isNurbselV(Nurb *nu, int *u, int flag)
Definition: editcurve.c:1655
static int curve_smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:3129
static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split)
Definition: editcurve.c:5974
static void keyIndex_swap(EditNurb *editnurb, void *a, void *b)
Definition: editcurve.c:357
static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit)
Definition: editcurve.c:1176
struct NurbSort NurbSort
void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus)
int ED_curve_join_objects_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:6824
static int add_vertex_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:5504
static BPoint * getKeyIndexOrig_bp(EditNurb *editnurb, BPoint *bp)
Definition: editcurve.c:240
static bool is_u_selected(Nurb *nu, int u)
Definition: editcurve.c:4140
static int shade_smooth_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:6745
bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
Definition: editcurve.c:2005
void CURVE_OT_dissolve_verts(wmOperatorType *ot)
Definition: editcurve.c:6626
static void weightflagNurb(ListBase *editnurb, short flag, float w)
Definition: editcurve.c:1749
ListBase * object_editcurve_get(Object *ob)
Definition: editcurve.c:89
void CURVE_OT_match_texture_space(wmOperatorType *ot)
Definition: editcurve.c:7082
void CURVE_OT_switch_direction(wmOperatorType *ot)
Definition: editcurve.c:2592
static bool test_bezt_is_sel_any(const void *bezt_v, void *user_data)
Definition: editcurve.c:6510
GHash * ED_curve_keyindex_hash_duplicate(GHash *keyindex)
Definition: editcurve.c:536
void CURVE_OT_spline_weight_set(wmOperatorType *ot)
Definition: editcurve.c:2654
static void calc_duplicate_actnurb(const ListBase *editnurb, const ListBase *newnurb, Curve *cu)
Definition: editcurve.c:2121
static bool calc_duplicate_actvert(const ListBase *editnurb, const ListBase *newnurb, Curve *cu, int start, int end, int vert)
Definition: editcurve.c:2126
static int set_spline_type_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:3854
static void keyIndex_updateBezt(EditNurb *editnurb, BezTriple *bezt, BezTriple *newbezt, int count)
Definition: editcurve.c:337
static void keyIndex_switchDirection(EditNurb *editnurb, Nurb *nu)
Definition: editcurve.c:370
void CURVE_OT_extrude(wmOperatorType *ot)
Definition: editcurve.c:5710
void CURVE_OT_make_segment(wmOperatorType *ot)
Definition: editcurve.c:4748
void ED_curve_keyindex_update_nurb(EditNurb *editnurb, Nurb *nu, Nurb *newnu)
Definition: editcurve.c:347
static int smooth_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:2789
static int curve_smooth_tilt_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:3172
void CURVE_OT_hide(wmOperatorType *ot)
Definition: editcurve.c:3293
void CURVE_OT_normals_make_consistent(wmOperatorType *ot)
Definition: editcurve.c:4044
static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, const int bp_offset)
Definition: editcurve.c:2904
static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:7035
static int spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: editcurve.c:5061
void CURVE_OT_shade_smooth(wmOperatorType *ot)
Definition: editcurve.c:6784
void ed_editnurb_translate_flag(ListBase *editnurb, uint8_t flag, const float vec[3], bool is_2d)
Definition: editcurve.c:1708
static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts)
Definition: editcurve.c:3401
static void calc_keyHandles(ListBase *nurb, float *key)
Definition: editcurve.c:572
void ED_curve_beztcpy(EditNurb *editnurb, BezTriple *dst, BezTriple *src, int count)
Definition: editcurve.c:7010
#define BP_VALUE(bp)
static CVKeyIndex * init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index)
Definition: editcurve.c:136
static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
Definition: editcurve.c:641
void CURVE_OT_delete(wmOperatorType *ot)
Definition: editcurve.c:6479
static void rotateflagNurb(ListBase *editnurb, short flag, const float cent[3], const float rotmat[3][3])
Definition: editcurve.c:1682
void ED_curve_editnurb_make(Object *obedit)
Definition: editcurve.c:1289
static void bezt_to_key(BezTriple *bezt, float *key)
Definition: editcurve.c:565
@ CURVE_MERGE_ERR_RESOLUTION_ALL
Definition: editcurve.c:4229
@ CURVE_MERGE_OK
Definition: editcurve.c:4227
@ CURVE_MERGE_ERR_FEW_SELECTION
Definition: editcurve.c:4228
@ CURVE_MERGE_ERR_RESOLUTION_SOME
Definition: editcurve.c:4230
void CURVE_OT_spin(wmOperatorType *ot)
Definition: editcurve.c:5077
static bool nurb_bezt_flag_any(const Nurb *nu, const char flag_test)
Definition: editcurve.c:6647
static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb, ListBase *nsortbase)
Definition: editcurve.c:4162
static int set_handle_type_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:3954
void CURVE_OT_spline_type_set(wmOperatorType *ot)
Definition: editcurve.c:3915
static bool match_texture_space_poll(bContext *C)
Definition: editcurve.c:7028
void CURVE_OT_shade_flat(wmOperatorType *ot)
Definition: editcurve.c:6799
static int curve_decimate_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:6661
static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
Definition: editcurve.c:1867
static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
Definition: editcurve.c:521
void ED_curve_editnurb_free(Object *obedit)
Definition: editcurve.c:1334
static bool isNurbselU(Nurb *nu, int *v, int flag)
Definition: editcurve.c:1628
void CURVE_OT_vertex_add(wmOperatorType *ot)
Definition: editcurve.c:5626
static CVKeyIndex * getCVKeyIndex(EditNurb *editnurb, const void *cv)
Definition: editcurve.c:219
static int reveal_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:3317
static int merge_nurb(View3D *v3d, Object *obedit)
Definition: editcurve.c:4392
static void smooth_single_bp(BPoint *bp, const BPoint *bp_orig_prev, const BPoint *bp_orig_next, float factor)
Definition: editcurve.c:2771
static void adduplicateflagNurb(Object *obedit, View3D *v3d, ListBase *newnurb, const uint8_t flag, const bool split)
Definition: editcurve.c:2142
static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
Definition: editcurve.c:251
static int curve_smooth_weight_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:3086
static void switch_keys_direction(Curve *cu, Nurb *actnu)
Definition: editcurve.c:473
static void key_to_bezt(float *key, BezTriple *basebezt, BezTriple *bezt)
Definition: editcurve.c:557
static bool curve_is_animated(Curve *cu)
Definition: editcurve.c:895
static int * init_index_map(Object *obedit, int *r_old_totvert)
Definition: editcurve.c:1111
static int make_segment_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:4455
static int curve_split_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:1494
int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
Definition: editcurve.c:1078
static void switchdirection_knots(float *base, int tot)
Definition: editcurve.c:4070
static int duplicate_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:5902
static bool curve_delete_vertices(Object *obedit, View3D *v3d)
Definition: editcurve.c:5962
void CURVE_OT_separate(wmOperatorType *ot)
Definition: editcurve.c:1472
void CURVE_OT_smooth_tilt(wmOperatorType *ot)
Definition: editcurve.c:3194
static void keyIndex_delNurbList(EditNurb *editnurb, ListBase *nubase)
Definition: editcurve.c:308
void CURVE_OT_reveal(wmOperatorType *ot)
Definition: editcurve.c:3373
static int spin_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:5007
static int subdivide_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:3793
static int toggle_cyclic_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:5812
void CURVE_OT_cyclic_toggle(wmOperatorType *ot)
Definition: editcurve.c:5866
bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
Definition: editcurve.c:4769
static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, View3D *v3d, const float location_init[3])
Definition: editcurve.c:5361
void CURVE_OT_duplicate(wmOperatorType *ot)
Definition: editcurve.c:5941
static void smooth_single_bezt(BezTriple *bezt, const BezTriple *bezt_orig_prev, const BezTriple *bezt_orig_next, float factor)
Definition: editcurve.c:2746
static CVKeyIndex * popCVKeyIndex(EditNurb *editnurb, const void *cv)
Definition: editcurve.c:224
static void keyIndex_updateCV(EditNurb *editnurb, char *cv, char *newcv, int count, int size)
Definition: editcurve.c:315
static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:5660
void CURVE_OT_smooth_radius(wmOperatorType *ot)
Definition: editcurve.c:3151
void ED_curve_editnurb_load(Main *bmain, Object *obedit)
Definition: editcurve.c:1251
void ED_curve_bpcpy(EditNurb *editnurb, BPoint *dst, BPoint *src, int count)
Definition: editcurve.c:7016
static int set_goal_weight_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:2613
static int curve_normals_make_consistent_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:4016
static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
Definition: editcurve.c:151
static BezTriple * getKeyIndexOrig_bezt(EditNurb *editnurb, const BezTriple *bezt)
Definition: editcurve.c:229
void CURVE_OT_smooth(wmOperatorType *ot)
Definition: editcurve.c:2879
static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
Definition: editcurve.c:953
static void rotate_direction_nurb(Nurb *nu)
Definition: editcurve.c:4115
bool ed_editnurb_spin(float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3])
Definition: editcurve.c:4931
static int separate_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:1347
void CURVE_OT_split(wmOperatorType *ot)
Definition: editcurve.c:1545
static int clear_tilt_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:6944
static const EnumPropertyItem * rna_curve_delete_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
Definition: editcurve.c:6459
static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu)
Definition: editcurve.c:941
static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:2551
static int set_radius_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:2679
void CURVE_OT_smooth_weight(wmOperatorType *ot)
Definition: editcurve.c:3108
static void fcurve_path_rename(AnimData *adt, const char *orig_rna_path, const char *rna_path, ListBase *orig_curves, ListBase *curves)
Definition: editcurve.c:902
void CURVE_OT_radius_set(wmOperatorType *ot)
Definition: editcurve.c:2720
static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: editcurve.c:5842
static bool isNurbselUV(const Nurb *nu, uint8_t flag, int *r_u, int *r_v)
Definition: editcurve.c:1566
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: editcurve.c:5534
static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp)
Definition: editcurve.c:271
static void ed_surf_delete_selected(Object *obedit)
Definition: editcurve.c:1769
static int curve_delete_exec(bContext *C, wmOperator *op)
Definition: editcurve.c:6403
static bool merge_2_nurb(Curve *cu, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
Definition: editcurve.c:4233
void CURVE_OT_decimate(wmOperatorType *ot)
Definition: editcurve.c:6721
static const EnumPropertyItem curve_delete_type_items[]
Definition: editcurve.c:6453
void CURVE_OT_handle_type_set(wmOperatorType *ot)
Definition: editcurve.c:3981
void CURVE_OT_subdivide(wmOperatorType *ot)
Definition: editcurve.c:3826
static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
Definition: editcurve.c:280
static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt)
Definition: editcurve.c:262
static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
Definition: editcurve.c:6517
void CURVE_OT_tilt_clear(wmOperatorType *ot)
Definition: editcurve.c:6995
bool ED_curve_select_check(View3D *v3d, struct EditNurb *editnurb)
bool ED_curve_nurb_select_check(View3D *v3d, Nurb *nu)
int ED_curve_nurb_select_count(View3D *v3d, Nurb *nu)
bool ED_curve_deselect_all(EditNurb *editnurb)
int count
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
static void clear(Message *msg)
Definition: msgfmt.c:294
static unsigned c
Definition: RandGen.cpp:97
Segment< FEdge *, Vec3r > segment
static unsigned a[3]
Definition: RandGen.cpp:92
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
const btScalar eps
Definition: poly34.cpp:11
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3851
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:4133
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4470
PropertyRNA * RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3883
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3819
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
Definition: rna_define.c:4455
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
#define min(a, b)
Definition: sort.c:51
unsigned char uint8_t
Definition: stdint.h:81
bAction * action
ListBase drivers
short hide
float weight
uint8_t f1
float vec[4]
float radius
float tilt
struct Object * object
float vec[3][3]
int key_index
Definition: BKE_curve.h:64
int vertex_index
Definition: BKE_curve.h:64
void * orig_cv
Definition: BKE_curve.h:63
int pt_index
Definition: BKE_curve.h:64
bool switched
Definition: BKE_curve.h:65
int nu_index
Definition: BKE_curve.h:64
ListBase disp
Definition: BKE_curve.h:49
float loc[3]
short resolu
struct Key * key
EditNurb * editnurb
short texflag
ListBase nurb
float ext2
float size[3]
struct GHash * keyindex
ListBase nurbs
bActionGroup * grp
char * rna_path
int elemsize
Definition: DNA_key_types.h:96
char type
ListBase block
KeyBlock * refkey
Definition: DNA_key_types.h:88
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase objects
Definition: BKE_main.h:148
Nurb * nu
Definition: editcurve.c:4158
struct NurbSort * next
Definition: editcurve.c:4157
float vec[3]
Definition: editcurve.c:4159
struct NurbSort * prev
Definition: editcurve.c:4157
short flagu
short orderu
struct Nurb * next
short orderv
float * knotsu
short flag
short type
float * knotsv
BezTriple * bezt
BPoint * bp
short resolu
short resolv
short hide
short flagv
short mat_nr
struct CurveCache * curve_cache
float imat[4][4]
short shapenr
Object_Runtime runtime
float obmat[4][4]
void * data
float persmat[4][4]
float viewmat[4][4]
float viewinv[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
const struct View3D * v3d
struct Depsgraph * depsgraph
Definition: ED_view3d.h:75
int mval[2]
Definition: ED_view3d.h:85
struct Scene * scene
Definition: ED_view3d.h:76
struct ARegion * region
Definition: ED_view3d.h:80
struct ViewLayer * view_layer
Definition: ED_view3d.h:77
struct Object * obedit
Definition: ED_view3d.h:79
struct View3D * v3d
Definition: ED_view3d.h:81
struct RegionView3D * rv3d
Definition: ED_view3d.h:83
struct Base * basact
ListBase curves
int mval[2]
Definition: WM_types.h:583
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition: svm_invert.h:19
float max
const EnumPropertyItem rna_enum_transform_mode_types[]
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
#define G(x, y, z)
uint len
void WM_cursor_wait(bool val)
Definition: wm_cursors.c:226
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_operators.c:982