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