Blender V4.3
curve.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath> /* floor */
10#include <cstdlib>
11#include <cstring>
12#include <optional>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_blenlib.h"
17#include "BLI_endian_switch.h"
18#include "BLI_ghash.h"
19#include "BLI_index_range.hh"
20#include "BLI_math_base_safe.h"
21#include "BLI_math_geom.h"
22#include "BLI_math_matrix.h"
23#include "BLI_math_rotation.h"
24#include "BLI_math_solvers.h"
25#include "BLI_math_vector.h"
27#include "BLI_string.h"
28#include "BLI_utildefines.h"
29#include "BLT_translation.hh"
30
31/* Allow using deprecated functionality for .blend file I/O. */
32#define DNA_DEPRECATED_ALLOW
33
34#include "DNA_anim_types.h"
35#include "DNA_curve_types.h"
36#include "DNA_defaults.h"
37#include "DNA_material_types.h"
38
39/* For dereferencing pointers. */
40#include "DNA_key_types.h"
41#include "DNA_object_types.h"
42#include "DNA_vfont_types.h"
43
44#include "BKE_curve.hh"
45#include "BKE_curveprofile.h"
46#include "BKE_idtype.hh"
47#include "BKE_key.hh"
48#include "BKE_lib_id.hh"
49#include "BKE_lib_query.hh"
50#include "BKE_object_types.hh"
51#include "BKE_vfont.hh"
52
53#include "DEG_depsgraph.hh"
55
56#include "BLO_read_write.hh"
57
58using blender::float3;
60
61/* globals */
62
63/* local */
64// static CLG_LogRef LOG = {"bke.curve"};
65
73
74static void curve_init_data(ID *id)
75{
76 Curve *curve = (Curve *)id;
77
79
81}
82
83static void curve_copy_data(Main *bmain,
84 std::optional<Library *> owner_library,
85 ID *id_dst,
86 const ID *id_src,
87 const int flag)
88{
89 Curve *curve_dst = (Curve *)id_dst;
90 const Curve *curve_src = (const Curve *)id_src;
91
92 BLI_listbase_clear(&curve_dst->nurb);
93 BKE_nurbList_duplicate(&(curve_dst->nurb), &(curve_src->nurb));
94
95 curve_dst->mat = (Material **)MEM_dupallocN(curve_src->mat);
96
97 curve_dst->str = (char *)MEM_dupallocN(curve_src->str);
98 curve_dst->strinfo = (CharInfo *)MEM_dupallocN(curve_src->strinfo);
99 curve_dst->tb = (TextBox *)MEM_dupallocN(curve_src->tb);
100 curve_dst->batch_cache = nullptr;
101
102 curve_dst->bevel_profile = BKE_curveprofile_copy(curve_src->bevel_profile);
103
104 if (curve_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
105 BKE_id_copy_in_lib(bmain,
106 owner_library,
107 &curve_src->key->id,
108 &curve_dst->id,
109 reinterpret_cast<ID **>(&curve_dst->key),
110 flag);
111 }
112
113 curve_dst->editnurb = nullptr;
114 curve_dst->editfont = nullptr;
115}
116
117static void curve_free_data(ID *id)
118{
119 Curve *curve = (Curve *)id;
120
122
123 BKE_nurbList_free(&curve->nurb);
124
125 if (!curve->edit_data_from_original) {
127
129 }
130
132
133 MEM_SAFE_FREE(curve->mat);
134 MEM_SAFE_FREE(curve->str);
135 MEM_SAFE_FREE(curve->strinfo);
136 MEM_SAFE_FREE(curve->tb);
137}
138
160
161static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_address)
162{
163 Curve *cu = (Curve *)id;
164
165 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
166 cu->editnurb = nullptr;
167 cu->editfont = nullptr;
168 cu->batch_cache = nullptr;
169
170 /* write LibData */
171 BLO_write_id_struct(writer, Curve, id_address, &cu->id);
172 BKE_id_blend_write(writer, &cu->id);
173
174 /* direct data */
175 BLO_write_pointer_array(writer, cu->totcol, cu->mat);
176
177 if (cu->vfont) {
178 BLO_write_string(writer, cu->str);
179 BLO_write_struct_array(writer, CharInfo, cu->len_char32 + 1, cu->strinfo);
180 BLO_write_struct_array(writer, TextBox, cu->totbox, cu->tb);
181 }
182 else {
183 /* is also the order of reading */
184 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
185 BLO_write_struct(writer, Nurb, nu);
186 }
187 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
188 if (nu->type == CU_BEZIER) {
189 BLO_write_struct_array(writer, BezTriple, nu->pntsu, nu->bezt);
190 }
191 else {
192 BLO_write_struct_array(writer, BPoint, nu->pntsu * nu->pntsv, nu->bp);
193 if (nu->knotsu) {
194 BLO_write_float_array(writer, KNOTSU(nu), nu->knotsu);
195 }
196 if (nu->knotsv) {
197 BLO_write_float_array(writer, KNOTSV(nu), nu->knotsv);
198 }
199 }
200 }
201 }
202
203 if (cu->bevel_profile != nullptr) {
205 }
206}
207
208static void curve_blend_read_data(BlendDataReader *reader, ID *id)
209{
210 Curve *cu = (Curve *)id;
211
212 /* Protect against integer overflow vulnerability. */
213 CLAMP(cu->len_char32, 0, INT_MAX - 4);
214
215 BLO_read_pointer_array(reader, cu->totcol, (void **)&cu->mat);
216
217 BLO_read_string(reader, &cu->str);
218 BLO_read_struct_array(reader, CharInfo, cu->len_char32 + 1, &cu->strinfo);
219 BLO_read_struct_array(reader, TextBox, cu->totbox, &cu->tb);
220
221 if (cu->vfont == nullptr) {
222 BLO_read_struct_list(reader, Nurb, &(cu->nurb));
223 }
224 else {
225 cu->nurb.first = cu->nurb.last = nullptr;
226
227 TextBox *tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
228 if (cu->tb) {
229 memcpy(tb, cu->tb, cu->totbox * sizeof(TextBox));
230 MEM_freeN(cu->tb);
231 cu->tb = tb;
232 }
233 else {
234 cu->totbox = 1;
235 cu->actbox = 1;
236 cu->tb = tb;
237 cu->tb[0].w = cu->linewidth;
238 }
239 if (cu->wordspace == 0.0f) {
240 cu->wordspace = 1.0f;
241 }
242 }
243
244 cu->editnurb = nullptr;
245 cu->editfont = nullptr;
246 cu->batch_cache = nullptr;
247
248 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
249 BLO_read_struct_array(reader, BezTriple, nu->pntsu, &nu->bezt);
250 BLO_read_struct_array(reader, BPoint, nu->pntsu * nu->pntsv, &nu->bp);
251 BLO_read_float_array(reader, KNOTSU(nu), &nu->knotsu);
252 BLO_read_float_array(reader, KNOTSV(nu), &nu->knotsv);
253 if (cu->vfont == nullptr) {
254 nu->charidx = 0;
255 }
256 }
258
260 if (cu->bevel_profile != nullptr) {
262 }
263}
264
266 /*id_code*/ ID_CU_LEGACY,
267 /*id_filter*/ FILTER_ID_CU_LEGACY,
268 /*dependencies_id_types*/ FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_VF | FILTER_ID_KE,
269 /*main_listbase_index*/ INDEX_ID_CU_LEGACY,
270 /*struct_size*/ sizeof(Curve),
271 /*name*/ "Curve",
272 /*name_plural*/ N_("curves"),
273 /*translation_context*/ BLT_I18NCONTEXT_ID_CURVE_LEGACY,
275 /*asset_type_info*/ nullptr,
276
277 /*init_data*/ curve_init_data,
278 /*copy_data*/ curve_copy_data,
279 /*free_data*/ curve_free_data,
280 /*make_local*/ nullptr,
281 /*foreach_id*/ curve_foreach_id,
282 /*foreach_cache*/ nullptr,
283 /*foreach_path*/ nullptr,
284 /*owner_pointer_get*/ nullptr,
285
286 /*blend_write*/ curve_blend_write,
287 /*blend_read_data*/ curve_blend_read_data,
288 /*blend_read_after_liblink*/ nullptr,
289
290 /*blend_read_undo_preserve*/ nullptr,
291
292 /*lib_override_apply_post*/ nullptr,
293};
294
296{
297 if (cu->editfont) {
298 EditFont *ef = cu->editfont;
299
300 if (ef->textbuf) {
301 MEM_freeN(ef->textbuf);
302 }
303 if (ef->textbufinfo) {
305 }
306 if (ef->selboxes) {
307 MEM_freeN(ef->selboxes);
308 }
309
310 MEM_freeN(ef);
311 cu->editfont = nullptr;
312 }
313}
314
316{
317 CVKeyIndex *index = (CVKeyIndex *)val;
318 MEM_freeN(index->orig_cv);
319 MEM_freeN(val);
320}
321
322void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
323{
324 BLI_assert(keyindex != nullptr);
326}
327
329{
330 if (!(*keyindex)) {
331 return;
332 }
334 *keyindex = nullptr;
335}
336
338{
339 if (cu->editnurb) {
342 MEM_freeN(cu->editnurb);
343 cu->editnurb = nullptr;
344 }
345}
346
347void BKE_curve_init(Curve *cu, const short curve_type)
348{
349 curve_init_data(&cu->id);
350
351 cu->type = curve_type;
352
353 if (cu->type == OB_FONT) {
354 cu->flag |= CU_FRONT | CU_BACK;
355 cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
356 cu->vfont->id.us += 4;
357
358 const char *str = DATA_("Text");
359 size_t len_bytes;
360 size_t len_char32 = BLI_strlen_utf8_ex(str, &len_bytes);
361
362 cu->str = static_cast<char *>(MEM_malloc_arrayN(len_bytes + 1, sizeof(char), "str"));
363 BLI_strncpy(cu->str, str, len_bytes + 1);
364
365 cu->len = len_bytes;
366 cu->len_char32 = cu->pos = len_char32;
367
368 cu->strinfo = static_cast<CharInfo *>(
369 MEM_calloc_arrayN((len_char32 + 1), sizeof(CharInfo), "strinfo new"));
370
371 cu->totbox = cu->actbox = 1;
372 cu->tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
373 cu->tb[0].w = cu->tb[0].h = 0.0;
374 }
375 else if (cu->type == OB_SURF) {
376 cu->flag |= CU_3D;
377 cu->resolu = 4;
378 cu->resolv = 4;
379 }
380 cu->bevel_profile = nullptr;
381 /* Initialize the offset to 1.0, to compensate for it being set to -1.0
382 * in the property getter. */
383 cu->offset = 1.0f;
384}
385
386Curve *BKE_curve_add(Main *bmain, const char *name, int type)
387{
388 Curve *cu;
389
390 /* We cannot use #BKE_id_new here as we need some custom initialization code. */
391 cu = (Curve *)BKE_libblock_alloc(bmain, ID_CU_LEGACY, name, 0);
392
393 BKE_curve_init(cu, type);
394
395 return cu;
396}
397
399{
400 if (cu->editnurb) {
401 return &cu->editnurb->nurbs;
402 }
403
404 return nullptr;
405}
406
408{
409 if (cu->editnurb) {
410 return &cu->editnurb->nurbs;
411 }
412
413 return nullptr;
414}
415
416short BKE_curve_type_get(const Curve *cu)
417{
418 int type = cu->type;
419
420 if (cu->vfont) {
421 return OB_FONT;
422 }
423
424 if (!cu->type) {
425 type = OB_CURVES_LEGACY;
426
427 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
428 if (nu->pntsv > 1) {
429 type = OB_SURF;
430 }
431 }
432 }
433
434 return type;
435}
436
438{
439 ListBase *nurbs = BKE_curve_nurbs_get(cu);
440 bool is_2d = CU_IS_2D(cu);
441
442 LISTBASE_FOREACH (Nurb *, nu, nurbs) {
443 if (is_2d) {
445 }
446
447 /* since the handles are moved they need to be auto-located again */
448 if (nu->type == CU_BEZIER) {
450 }
451 }
452}
453
455{
456 ob->type = BKE_curve_type_get((Curve *)ob->data);
457
458 if (ob->type == OB_CURVES_LEGACY) {
459 Curve *cu = (Curve *)ob->data;
460 if (CU_IS_2D(cu)) {
462 }
463 }
464}
465
467{
469 std::optional<blender::Bounds<blender::float3>> bounds = BKE_curve_minmax(cu, true);
470 if (!bounds) {
472 }
473
474 float texspace_location[3], texspace_size[3];
475 mid_v3_v3v3(texspace_location, bounds->min, bounds->max);
476
477 texspace_size[0] = (bounds->max[0] - bounds->min[0]) / 2.0f;
478 texspace_size[1] = (bounds->max[1] - bounds->min[1]) / 2.0f;
479 texspace_size[2] = (bounds->max[2] - bounds->min[2]) / 2.0f;
480
481 for (int a = 0; a < 3; a++) {
482 if (texspace_size[a] == 0.0f) {
483 texspace_size[a] = 1.0f;
484 }
485 else if (texspace_size[a] > 0.0f && texspace_size[a] < 0.00001f) {
486 texspace_size[a] = 0.00001f;
487 }
488 else if (texspace_size[a] < 0.0f && texspace_size[a] > -0.00001f) {
489 texspace_size[a] = -0.00001f;
490 }
491 }
492
493 copy_v3_v3(cu->texspace_location, texspace_location);
494 copy_v3_v3(cu->texspace_size, texspace_size);
495
497 }
498}
499
508
509bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
510{
511 int tot = 0;
512
513 LISTBASE_FOREACH (Nurb *, nu, nurb) {
514 int tot_nu;
515 if (nu->type == CU_BEZIER) {
516 tot_nu = nu->pntsu;
517 if (index - tot < tot_nu) {
518 copy_v3_v3(r_co, nu->bezt[index - tot].vec[1]);
519 return true;
520 }
521 }
522 else {
523 tot_nu = nu->pntsu * nu->pntsv;
524 if (index - tot < tot_nu) {
525 copy_v3_v3(r_co, nu->bp[index - tot].vec);
526 return true;
527 }
528 }
529 tot += tot_nu;
530 }
531
532 return false;
533}
534
536{
537 int tot = 0;
538
539 LISTBASE_FOREACH (const Nurb *, nu, nurb) {
540 if (nu->bezt) {
541 tot += 3 * nu->pntsu;
542 }
543 else if (nu->bp) {
544 tot += nu->pntsu * nu->pntsv;
545 }
546 }
547
548 return tot;
549}
550
552{
553 int tot = 0;
554
555 LISTBASE_FOREACH (Nurb *, nu, nurb) {
556 if (nu->bezt) {
557 tot += nu->pntsu;
558 }
559 else if (nu->bp) {
560 tot += nu->pntsu * nu->pntsv;
561 }
562 }
563
564 return tot;
565}
566
567/* **************** NURBS ROUTINES ******************** */
568
570{
571 if (nu == nullptr) {
572 return;
573 }
574
575 if (nu->bezt) {
576 MEM_freeN(nu->bezt);
577 }
578 nu->bezt = nullptr;
579 if (nu->bp) {
580 MEM_freeN(nu->bp);
581 }
582 nu->bp = nullptr;
583 if (nu->knotsu) {
584 MEM_freeN(nu->knotsu);
585 }
586 nu->knotsu = nullptr;
587 if (nu->knotsv) {
588 MEM_freeN(nu->knotsv);
589 }
590 nu->knotsv = nullptr;
591 // if (nu->trim.first) freeNurblist(&(nu->trim));
592
593 MEM_freeN(nu);
594}
595
597{
598 if (lb == nullptr) {
599 return;
600 }
601
602 LISTBASE_FOREACH_MUTABLE (Nurb *, nu, lb) {
603 BKE_nurb_free(nu);
604 }
606}
607
609{
610 Nurb *newnu;
611 int len;
612
613 newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb");
614 if (newnu == nullptr) {
615 return nullptr;
616 }
617 *newnu = blender::dna::shallow_copy(*nu);
618
619 if (nu->bezt) {
620 newnu->bezt = (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2");
621 memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple));
622 }
623 else {
624 len = nu->pntsu * nu->pntsv;
625 newnu->bp = (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
626 memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
627
628 newnu->knotsu = newnu->knotsv = nullptr;
629
630 if (nu->knotsu) {
631 len = KNOTSU(nu);
632 if (len) {
633 newnu->knotsu = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
634 memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
635 }
636 }
637 if (nu->pntsv > 1 && nu->knotsv) {
638 len = KNOTSV(nu);
639 if (len) {
640 newnu->knotsv = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
641 memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
642 }
643 }
644 }
645 return newnu;
646}
647
648Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
649{
650 Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
651 *newnu = blender::dna::shallow_copy(*src);
652
653 if (pntsu == 1) {
654 std::swap(pntsu, pntsv);
655 }
656 newnu->pntsu = pntsu;
657 newnu->pntsv = pntsv;
658
659 /* caller can manually handle these arrays */
660 newnu->knotsu = nullptr;
661 newnu->knotsv = nullptr;
662
663 if (src->bezt) {
664 newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
665 }
666 else {
667 newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3");
668 }
669
670 return newnu;
671}
672
674{
676
677 LISTBASE_FOREACH (const Nurb *, nu, lb2) {
678 Nurb *nurb_new = BKE_nurb_duplicate(nu);
679 BLI_addtail(lb1, nurb_new);
680 }
681}
682
684{
685 BezTriple *bezt;
686 BPoint *bp;
687 int a;
688
689 if (nu->type == CU_BEZIER) {
690 a = nu->pntsu;
691 bezt = nu->bezt;
692 while (a--) {
693 bezt->vec[0][2] = 0.0;
694 bezt->vec[1][2] = 0.0;
695 bezt->vec[2][2] = 0.0;
696 bezt++;
697 }
698 }
699 else {
700 a = nu->pntsu * nu->pntsv;
701 bp = nu->bp;
702 while (a--) {
703 bp->vec[2] = 0.0;
704 bp++;
705 }
706 }
707}
708
709static void calc_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
710{
711 BezTriple *bezt;
712 BPoint *bp;
713 int a;
714 float point[3];
715
716 if (nu->type == CU_BEZIER) {
717 a = nu->pntsu;
718 bezt = nu->bezt;
719 while (a--) {
720 if (use_radius) {
721 float radius_vector[3];
722 radius_vector[0] = radius_vector[1] = radius_vector[2] = bezt->radius;
723
724 add_v3_v3v3(point, bezt->vec[1], radius_vector);
726
727 sub_v3_v3v3(point, bezt->vec[1], radius_vector);
729 }
730 else {
731 minmax_v3v3_v3(min, max, bezt->vec[1]);
732 }
733 minmax_v3v3_v3(min, max, bezt->vec[0]);
734 minmax_v3v3_v3(min, max, bezt->vec[2]);
735 bezt++;
736 }
737 }
738 else {
739 a = nu->pntsu * nu->pntsv;
740 bp = nu->bp;
741 while (a--) {
742 if (nu->pntsv == 1 && use_radius) {
743 float radius_vector[3];
744 radius_vector[0] = radius_vector[1] = radius_vector[2] = bp->radius;
745
746 add_v3_v3v3(point, bp->vec, radius_vector);
748
749 sub_v3_v3v3(point, bp->vec, radius_vector);
751 }
752 else {
753 /* Surfaces doesn't use bevel, so no need to take radius into account. */
754 minmax_v3v3_v3(min, max, bp->vec);
755 }
756 bp++;
757 }
758 }
759}
760
761float BKE_nurb_calc_length(const Nurb *nu, int resolution)
762{
763 BezTriple *bezt, *prevbezt;
764 BPoint *bp, *prevbp;
765 int a, b;
766 float length = 0.0f;
767 int resolu = resolution ? resolution : nu->resolu;
768 int pntsu = nu->pntsu;
769 float *points, *pntsit, *prevpntsit;
770
771 if (nu->type == CU_POLY) {
772 a = nu->pntsu - 1;
773 bp = nu->bp;
774 if (nu->flagu & CU_NURB_CYCLIC) {
775 a++;
776 prevbp = nu->bp + (nu->pntsu - 1);
777 }
778 else {
779 prevbp = bp;
780 bp++;
781 }
782
783 while (a--) {
784 length += len_v3v3(prevbp->vec, bp->vec);
785 prevbp = bp;
786 bp++;
787 }
788 }
789 else if (nu->type == CU_BEZIER) {
790 points = (float *)MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
791 a = nu->pntsu - 1;
792 bezt = nu->bezt;
793 if (nu->flagu & CU_NURB_CYCLIC) {
794 a++;
795 prevbezt = nu->bezt + (nu->pntsu - 1);
796 }
797 else {
798 prevbezt = bezt;
799 bezt++;
800 }
801
802 while (a--) {
803 if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
804 length += len_v3v3(prevbezt->vec[1], bezt->vec[1]);
805 }
806 else {
807 for (int j = 0; j < 3; j++) {
808 BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
809 prevbezt->vec[2][j],
810 bezt->vec[0][j],
811 bezt->vec[1][j],
812 points + j,
813 resolu,
814 sizeof(float[3]));
815 }
816
817 prevpntsit = pntsit = points;
818 b = resolu;
819 while (b--) {
820 pntsit += 3;
821 length += len_v3v3(prevpntsit, pntsit);
822 prevpntsit = pntsit;
823 }
824 }
825 prevbezt = bezt;
826 bezt++;
827 }
828
829 MEM_freeN(points);
830 }
831 else if (nu->type == CU_NURBS) {
832 if (nu->pntsv == 1) {
833 /* important to zero for BKE_nurb_makeCurve. */
834 points = (float *)MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
835
836 BKE_nurb_makeCurve(nu, points, nullptr, nullptr, nullptr, resolu, sizeof(float[3]));
837
838 if (nu->flagu & CU_NURB_CYCLIC) {
839 b = pntsu * resolu + 1;
840 prevpntsit = points + 3 * (pntsu * resolu - 1);
841 pntsit = points;
842 }
843 else {
844 b = (pntsu - 1) * resolu;
845 prevpntsit = points;
846 pntsit = points + 3;
847 }
848
849 while (--b > 0) {
850 length += len_v3v3(prevpntsit, pntsit);
851 prevpntsit = pntsit;
852 pntsit += 3;
853 }
854
855 MEM_freeN(points);
856 }
857 }
858
859 return length;
860}
861
862void BKE_nurb_points_add(Nurb *nu, int number)
863{
864 nu->bp = (BPoint *)MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
865
866 BPoint *bp;
867 int i;
868 for (i = 0, bp = &nu->bp[nu->pntsu]; i < number; i++, bp++) {
869 bp->radius = 1.0f;
870 }
871
872 nu->pntsu += number;
873}
874
875void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
876{
877 BezTriple *bezt;
878 int i;
879
880 nu->bezt = (BezTriple *)MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
881
882 for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
883 bezt->radius = 1.0f;
884 }
885
886 nu->pntsu += number;
887}
888
889int BKE_nurb_index_from_uv(Nurb *nu, int u, int v)
890{
891 const int totu = nu->pntsu;
892 const int totv = nu->pntsv;
893
894 if (nu->flagu & CU_NURB_CYCLIC) {
895 u = mod_i(u, totu);
896 }
897 else if (u < 0 || u >= totu) {
898 return -1;
899 }
900
901 if (nu->flagv & CU_NURB_CYCLIC) {
902 v = mod_i(v, totv);
903 }
904 else if (v < 0 || v >= totv) {
905 return -1;
906 }
907
908 return (v * totu) + u;
909}
910
911void BKE_nurb_index_to_uv(Nurb *nu, int index, int *r_u, int *r_v)
912{
913 const int totu = nu->pntsu;
914 const int totv = nu->pntsv;
915 BLI_assert(index >= 0 && index < (nu->pntsu * nu->pntsv));
916 *r_u = (index % totu);
917 *r_v = (index / totu) % totv;
918}
919
921{
922 BezTriple *bezt_next;
923
924 BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
925
926 if (bezt == &nu->bezt[nu->pntsu - 1]) {
927 if (nu->flagu & CU_NURB_CYCLIC) {
928 bezt_next = nu->bezt;
929 }
930 else {
931 bezt_next = nullptr;
932 }
933 }
934 else {
935 bezt_next = bezt + 1;
936 }
937
938 return bezt_next;
939}
940
942{
943 BPoint *bp_next;
944
945 BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
946
947 if (bp == &nu->bp[nu->pntsu - 1]) {
948 if (nu->flagu & CU_NURB_CYCLIC) {
949 bp_next = nu->bp;
950 }
951 else {
952 bp_next = nullptr;
953 }
954 }
955 else {
956 bp_next = bp + 1;
957 }
958
959 return bp_next;
960}
961
963{
964 BezTriple *bezt_prev;
965
966 BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
967 BLI_assert(nu->pntsv <= 1);
968
969 if (bezt == nu->bezt) {
970 if (nu->flagu & CU_NURB_CYCLIC) {
971 bezt_prev = &nu->bezt[nu->pntsu - 1];
972 }
973 else {
974 bezt_prev = nullptr;
975 }
976 }
977 else {
978 bezt_prev = bezt - 1;
979 }
980
981 return bezt_prev;
982}
983
985{
986 BPoint *bp_prev;
987
988 BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
989 BLI_assert(nu->pntsv == 1);
990
991 if (bp == nu->bp) {
992 if (nu->flagu & CU_NURB_CYCLIC) {
993 bp_prev = &nu->bp[nu->pntsu - 1];
994 }
995 else {
996 bp_prev = nullptr;
997 }
998 }
999 else {
1000 bp_prev = bp - 1;
1001 }
1002
1003 return bp_prev;
1004}
1005
1006void BKE_nurb_bezt_calc_normal(Nurb * /*nu*/, BezTriple *bezt, float r_normal[3])
1007{
1008 /* calculate the axis matrix from the spline */
1009 float dir_prev[3], dir_next[3];
1010
1011 sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
1012 sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
1013
1014 normalize_v3(dir_prev);
1015 normalize_v3(dir_next);
1016
1017 add_v3_v3v3(r_normal, dir_prev, dir_next);
1018 normalize_v3(r_normal);
1019}
1020
1021void BKE_nurb_bezt_calc_plane(Nurb *nu, BezTriple *bezt, float r_plane[3])
1022{
1023 float dir_prev[3], dir_next[3];
1024
1025 sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
1026 sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
1027
1028 normalize_v3(dir_prev);
1029 normalize_v3(dir_next);
1030
1031 cross_v3_v3v3(r_plane, dir_prev, dir_next);
1032 if (normalize_v3(r_plane) < FLT_EPSILON) {
1033 BezTriple *bezt_prev = BKE_nurb_bezt_get_prev(nu, bezt);
1034 BezTriple *bezt_next = BKE_nurb_bezt_get_next(nu, bezt);
1035
1036 if (bezt_prev) {
1037 sub_v3_v3v3(dir_prev, bezt_prev->vec[1], bezt->vec[1]);
1038 normalize_v3(dir_prev);
1039 }
1040 if (bezt_next) {
1041 sub_v3_v3v3(dir_next, bezt->vec[1], bezt_next->vec[1]);
1042 normalize_v3(dir_next);
1043 }
1044 cross_v3_v3v3(r_plane, dir_prev, dir_next);
1045 }
1046
1047 /* matches with bones more closely */
1048 {
1049 float dir_mid[3], tvec[3];
1050 add_v3_v3v3(dir_mid, dir_prev, dir_next);
1051 cross_v3_v3v3(tvec, r_plane, dir_mid);
1052 copy_v3_v3(r_plane, tvec);
1053 }
1054
1055 normalize_v3(r_plane);
1056}
1057
1058void BKE_nurb_bpoint_calc_normal(Nurb *nu, BPoint *bp, float r_normal[3])
1059{
1060 BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
1061 BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
1062
1063 zero_v3(r_normal);
1064
1065 if (bp_prev) {
1066 float dir_prev[3];
1067 sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
1068 normalize_v3(dir_prev);
1069 add_v3_v3(r_normal, dir_prev);
1070 }
1071 if (bp_next) {
1072 float dir_next[3];
1073 sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
1074 normalize_v3(dir_next);
1075 add_v3_v3(r_normal, dir_next);
1076 }
1077
1078 normalize_v3(r_normal);
1079}
1080
1081void BKE_nurb_bpoint_calc_plane(Nurb *nu, BPoint *bp, float r_plane[3])
1082{
1083 BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
1084 BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
1085
1086 float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f};
1087
1088 if (bp_prev) {
1089 sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
1090 normalize_v3(dir_prev);
1091 }
1092 if (bp_next) {
1093 sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
1094 normalize_v3(dir_next);
1095 }
1096 cross_v3_v3v3(r_plane, dir_prev, dir_next);
1097
1098 /* matches with bones more closely */
1099 {
1100 float dir_mid[3], tvec[3];
1101 add_v3_v3v3(dir_mid, dir_prev, dir_next);
1102 cross_v3_v3v3(tvec, r_plane, dir_mid);
1103 copy_v3_v3(r_plane, tvec);
1104 }
1105
1106 normalize_v3(r_plane);
1107}
1108
1109/* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
1110
1111static void calcknots(float *knots, const int pnts, const short order, const short flag)
1112{
1113 const bool is_cyclic = flag & CU_NURB_CYCLIC;
1114 const bool is_bezier = flag & CU_NURB_BEZIER;
1115 const bool is_end_point = flag & CU_NURB_ENDPOINT;
1116 /* Inner knots are always repeated once except on Bezier case. */
1117 const int repeat_inner = is_bezier ? order - 1 : 1;
1118 /* How many times to repeat 0.0 at the beginning of knot. */
1119 const int head = is_end_point ? (order - (is_cyclic ? 1 : 0)) :
1120 (is_bezier ? min_ii(2, repeat_inner) : 1);
1121 /* Number of knots replicating widths of the starting knots.
1122 * Covers both Cyclic and EndPoint cases. */
1123 const int tail = is_cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
1124
1125 const int knot_count = pnts + order + (is_cyclic ? order - 1 : 0);
1126
1127 int r = head;
1128 float current = 0.0f;
1129
1130 const int offset = is_end_point && is_cyclic ? 1 : 0;
1131 if (offset) {
1132 knots[0] = current;
1133 current += 1.0f;
1134 }
1135
1136 for (const int i : IndexRange(offset, knot_count - offset - tail)) {
1137 knots[i] = current;
1138 r--;
1139 if (r == 0) {
1140 current += 1.0f;
1141 r = repeat_inner;
1142 }
1143 }
1144
1145 const int tail_index = knot_count - tail;
1146 for (const int i : IndexRange(tail)) {
1147 knots[tail_index + i] = current + (knots[i] - knots[0]);
1148 }
1149}
1150
1151static void makeknots(Nurb *nu, short uv)
1152{
1153 if (nu->type == CU_NURBS) {
1154 if (uv == 1) {
1155 if (nu->knotsu) {
1156 MEM_freeN(nu->knotsu);
1157 }
1158 if (BKE_nurb_check_valid_u(nu)) {
1159 nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
1160 calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
1161 }
1162 else {
1163 nu->knotsu = nullptr;
1164 }
1165 }
1166 else if (uv == 2) {
1167 if (nu->knotsv) {
1168 MEM_freeN(nu->knotsv);
1169 }
1170 if (BKE_nurb_check_valid_v(nu)) {
1171 nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
1172 calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
1173 }
1174 else {
1175 nu->knotsv = nullptr;
1176 }
1177 }
1178 }
1179}
1180
1182{
1183 makeknots(nu, 1);
1184}
1185
1187{
1188 makeknots(nu, 2);
1189}
1190
1191static void basisNurb(
1192 float t, short order, int pnts, const float *knots, float *basis, int *start, int *end)
1193{
1194 float d, e;
1195 int i, i1 = 0, i2 = 0, j, orderpluspnts, opp2, o2;
1196
1197 orderpluspnts = order + pnts;
1198 opp2 = orderpluspnts - 1;
1199
1200 /* this is for float inaccuracy */
1201 if (t < knots[0]) {
1202 t = knots[0];
1203 }
1204 else if (t > knots[opp2]) {
1205 t = knots[opp2];
1206 }
1207
1208 /* this part is order '1' */
1209 o2 = order + 1;
1210 for (i = 0; i < opp2; i++) {
1211 if (knots[i] != knots[i + 1] && t >= knots[i] && t <= knots[i + 1]) {
1212 basis[i] = 1.0;
1213 i1 = i - o2;
1214 if (i1 < 0) {
1215 i1 = 0;
1216 }
1217 i2 = i;
1218 i++;
1219 while (i < opp2) {
1220 basis[i] = 0.0;
1221 i++;
1222 }
1223 break;
1224 }
1225
1226 basis[i] = 0.0;
1227 }
1228 basis[i] = 0.0;
1229
1230 /* this is order 2, 3, ... */
1231 for (j = 2; j <= order; j++) {
1232
1233 if (i2 + j >= orderpluspnts) {
1234 i2 = opp2 - j;
1235 }
1236
1237 for (i = i1; i <= i2; i++) {
1238 if (basis[i] != 0.0f) {
1239 d = ((t - knots[i]) * basis[i]) / (knots[i + j - 1] - knots[i]);
1240 }
1241 else {
1242 d = 0.0f;
1243 }
1244
1245 if (basis[i + 1] != 0.0f) {
1246 e = ((knots[i + j] - t) * basis[i + 1]) / (knots[i + j] - knots[i + 1]);
1247 }
1248 else {
1249 e = 0.0;
1250 }
1251
1252 basis[i] = d + e;
1253 }
1254 }
1255
1256 *start = 1000;
1257 *end = 0;
1258
1259 for (i = i1; i <= i2; i++) {
1260 if (basis[i] > 0.0f) {
1261 *end = i;
1262 if (*start == 1000) {
1263 *start = i;
1264 }
1265 }
1266 }
1267}
1268
1269void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
1270{
1271 BPoint *bp;
1272 float *basisu, *basis, *basisv, *sum, *fp, *in;
1273 float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv;
1274 int i, j, iofs, jofs, cycl, len, curu, curv;
1275 int istart, iend, jsta, jen, *jstart, *jend, ratcomp;
1276
1277 int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv;
1278
1279 if (nu->knotsu == nullptr || nu->knotsv == nullptr) {
1280 return;
1281 }
1282 if (nu->orderu > nu->pntsu) {
1283 return;
1284 }
1285 if (nu->orderv > nu->pntsv) {
1286 return;
1287 }
1288 if (coord_array == nullptr) {
1289 return;
1290 }
1291
1292 /* allocate and initialize */
1293 len = totu * totv;
1294 if (len == 0) {
1295 return;
1296 }
1297
1298 sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1");
1299
1300 bp = nu->bp;
1301 i = nu->pntsu * nu->pntsv;
1302 ratcomp = 0;
1303 while (i--) {
1304 if (bp->vec[3] != 1.0f) {
1305 ratcomp = 1;
1306 break;
1307 }
1308 bp++;
1309 }
1310
1311 fp = nu->knotsu;
1312 ustart = fp[nu->orderu - 1];
1313 if (nu->flagu & CU_NURB_CYCLIC) {
1314 uend = fp[nu->pntsu + nu->orderu - 1];
1315 }
1316 else {
1317 uend = fp[nu->pntsu];
1318 }
1319 ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1);
1320
1321 basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3");
1322
1323 fp = nu->knotsv;
1324 vstart = fp[nu->orderv - 1];
1325
1326 if (nu->flagv & CU_NURB_CYCLIC) {
1327 vend = fp[nu->pntsv + nu->orderv - 1];
1328 }
1329 else {
1330 vend = fp[nu->pntsv];
1331 }
1332 vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1);
1333
1334 len = KNOTSV(nu);
1335 basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3");
1336 jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
1337 jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
1338
1339 /* Pre-calculation of `basisv` and `jstart`, `jend`. */
1340 if (nu->flagv & CU_NURB_CYCLIC) {
1341 cycl = nu->orderv - 1;
1342 }
1343 else {
1344 cycl = 0;
1345 }
1346 v = vstart;
1347 basis = basisv;
1348 curv = totv;
1349 while (curv--) {
1350 basisNurb(v, nu->orderv, nu->pntsv + cycl, nu->knotsv, basis, jstart + curv, jend + curv);
1351 basis += KNOTSV(nu);
1352 v += vstep;
1353 }
1354
1355 if (nu->flagu & CU_NURB_CYCLIC) {
1356 cycl = nu->orderu - 1;
1357 }
1358 else {
1359 cycl = 0;
1360 }
1361 in = coord_array;
1362 u = ustart;
1363 curu = totu;
1364 while (curu--) {
1365 basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
1366
1367 basis = basisv;
1368 curv = totv;
1369 while (curv--) {
1370 jsta = jstart[curv];
1371 jen = jend[curv];
1372
1373 /* calculate sum */
1374 sumdiv = 0.0;
1375 fp = sum;
1376
1377 for (j = jsta; j <= jen; j++) {
1378
1379 if (j >= nu->pntsv) {
1380 jofs = (j - nu->pntsv);
1381 }
1382 else {
1383 jofs = j;
1384 }
1385 bp = nu->bp + nu->pntsu * jofs + istart - 1;
1386
1387 for (i = istart; i <= iend; i++, fp++) {
1388 if (i >= nu->pntsu) {
1389 iofs = i - nu->pntsu;
1390 bp = nu->bp + nu->pntsu * jofs + iofs;
1391 }
1392 else {
1393 bp++;
1394 }
1395
1396 if (ratcomp) {
1397 *fp = basisu[i] * basis[j] * bp->vec[3];
1398 sumdiv += *fp;
1399 }
1400 else {
1401 *fp = basisu[i] * basis[j];
1402 }
1403 }
1404 }
1405
1406 if (ratcomp) {
1407 fp = sum;
1408 for (j = jsta; j <= jen; j++) {
1409 for (i = istart; i <= iend; i++, fp++) {
1410 *fp /= sumdiv;
1411 }
1412 }
1413 }
1414
1415 zero_v3(in);
1416
1417 /* one! (1.0) real point now */
1418 fp = sum;
1419 for (j = jsta; j <= jen; j++) {
1420
1421 if (j >= nu->pntsv) {
1422 jofs = (j - nu->pntsv);
1423 }
1424 else {
1425 jofs = j;
1426 }
1427 bp = nu->bp + nu->pntsu * jofs + istart - 1;
1428
1429 for (i = istart; i <= iend; i++, fp++) {
1430 if (i >= nu->pntsu) {
1431 iofs = i - nu->pntsu;
1432 bp = nu->bp + nu->pntsu * jofs + iofs;
1433 }
1434 else {
1435 bp++;
1436 }
1437
1438 if (*fp != 0.0f) {
1439 madd_v3_v3fl(in, bp->vec, *fp);
1440 }
1441 }
1442 }
1443
1444 in += 3;
1445 basis += KNOTSV(nu);
1446 }
1447 u += ustep;
1448 if (rowstride != 0) {
1449 in = (float *)(((uchar *)in) + (rowstride - 3 * totv * sizeof(*in)));
1450 }
1451 }
1452
1453 /* free */
1454 MEM_freeN(sum);
1455 MEM_freeN(basisu);
1456 MEM_freeN(basisv);
1457 MEM_freeN(jstart);
1458 MEM_freeN(jend);
1459}
1460
1462 float *coord_array,
1463 float *tilt_array,
1464 float *radius_array,
1465 float *weight_array,
1466 int resolu,
1467 int stride)
1468{
1469 const float eps = 1e-6f;
1470 BPoint *bp;
1471 float u, ustart, uend, ustep, sumdiv;
1472 float *basisu, *sum, *fp;
1473 float *coord_fp = coord_array, *tilt_fp = tilt_array, *radius_fp = radius_array,
1474 *weight_fp = weight_array;
1475 int i, len, istart, iend, cycl;
1476
1477 if (nu->knotsu == nullptr) {
1478 return;
1479 }
1480 if (nu->orderu > nu->pntsu) {
1481 return;
1482 }
1483 if (coord_array == nullptr) {
1484 return;
1485 }
1486
1487 /* allocate and initialize */
1488 len = nu->pntsu;
1489 if (len == 0) {
1490 return;
1491 }
1492 sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1");
1493
1494 resolu = (resolu * SEGMENTSU(nu));
1495
1496 if (resolu == 0) {
1497 MEM_freeN(sum);
1498 return;
1499 }
1500
1501 fp = nu->knotsu;
1502 ustart = fp[nu->orderu - 1];
1503 if (nu->flagu & CU_NURB_CYCLIC) {
1504 uend = fp[nu->pntsu + nu->orderu - 1];
1505 }
1506 else {
1507 uend = fp[nu->pntsu];
1508 }
1509 ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1));
1510
1511 basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3");
1512
1513 if (nu->flagu & CU_NURB_CYCLIC) {
1514 cycl = nu->orderu - 1;
1515 }
1516 else {
1517 cycl = 0;
1518 }
1519
1520 u = ustart;
1521 while (resolu--) {
1522 basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
1523
1524 /* calc sum */
1525 sumdiv = 0.0;
1526 fp = sum;
1527 bp = nu->bp + istart - 1;
1528 for (i = istart; i <= iend; i++, fp++) {
1529 if (i >= nu->pntsu) {
1530 bp = nu->bp + (i - nu->pntsu);
1531 }
1532 else {
1533 bp++;
1534 }
1535
1536 *fp = basisu[i] * bp->vec[3];
1537 sumdiv += *fp;
1538 }
1539 if ((sumdiv != 0.0f) && (sumdiv < 1.0f - eps || sumdiv > 1.0f + eps)) {
1540 /* is normalizing needed? */
1541 fp = sum;
1542 for (i = istart; i <= iend; i++, fp++) {
1543 *fp /= sumdiv;
1544 }
1545 }
1546
1547 zero_v3(coord_fp);
1548
1549 /* one! (1.0) real point */
1550 fp = sum;
1551 bp = nu->bp + istart - 1;
1552 for (i = istart; i <= iend; i++, fp++) {
1553 if (i >= nu->pntsu) {
1554 bp = nu->bp + (i - nu->pntsu);
1555 }
1556 else {
1557 bp++;
1558 }
1559
1560 if (*fp != 0.0f) {
1561 madd_v3_v3fl(coord_fp, bp->vec, *fp);
1562
1563 if (tilt_fp) {
1564 (*tilt_fp) += (*fp) * bp->tilt;
1565 }
1566
1567 if (radius_fp) {
1568 (*radius_fp) += (*fp) * bp->radius;
1569 }
1570
1571 if (weight_fp) {
1572 (*weight_fp) += (*fp) * bp->weight;
1573 }
1574 }
1575 }
1576
1577 coord_fp = (float *)POINTER_OFFSET(coord_fp, stride);
1578
1579 if (tilt_fp) {
1580 tilt_fp = (float *)POINTER_OFFSET(tilt_fp, stride);
1581 }
1582 if (radius_fp) {
1583 radius_fp = (float *)POINTER_OFFSET(radius_fp, stride);
1584 }
1585 if (weight_fp) {
1586 weight_fp = (float *)POINTER_OFFSET(weight_fp, stride);
1587 }
1588
1589 u += ustep;
1590 }
1591
1592 /* free */
1593 MEM_freeN(sum);
1594 MEM_freeN(basisu);
1595}
1596
1598 const uint resolu,
1599 const bool is_cyclic,
1600 const bool use_cyclic_duplicate_endpoint)
1601{
1602 const uint segments = bezt_array_len - (is_cyclic ? 0 : 1);
1603 const uint points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1);
1604 return points_len;
1605}
1606
1608 const uint bezt_array_len,
1609 const uint resolu,
1610 const bool is_cyclic,
1611 const bool use_cyclic_duplicate_endpoint,
1612 /* array params */
1613 const uint axis,
1614 const uint stride,
1615 float *r_points)
1616{
1617 const uint points_len = BKE_curve_calc_coords_axis_len(
1618 bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint);
1619 float *r_points_offset = r_points;
1620
1621 const uint resolu_stride = resolu * stride;
1622 const uint bezt_array_last = bezt_array_len - 1;
1623
1624 for (uint i = 0; i < bezt_array_last; i++) {
1625 const BezTriple *bezt_curr = &bezt_array[i];
1626 const BezTriple *bezt_next = &bezt_array[i + 1];
1627 BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis],
1628 bezt_curr->vec[2][axis],
1629 bezt_next->vec[0][axis],
1630 bezt_next->vec[1][axis],
1631 r_points_offset,
1632 int(resolu),
1633 stride);
1634 r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
1635 }
1636
1637 if (is_cyclic) {
1638 const BezTriple *bezt_curr = &bezt_array[bezt_array_last];
1639 const BezTriple *bezt_next = &bezt_array[0];
1640 BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis],
1641 bezt_curr->vec[2][axis],
1642 bezt_next->vec[0][axis],
1643 bezt_next->vec[1][axis],
1644 r_points_offset,
1645 int(resolu),
1646 stride);
1647 r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
1648 if (use_cyclic_duplicate_endpoint) {
1649 *r_points_offset = *r_points;
1650 r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
1651 }
1652 }
1653 else {
1654 float *r_points_last = (float *)POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
1655 *r_points_last = bezt_array[bezt_array_last].vec[1][axis];
1656 r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
1657 }
1658
1659 BLI_assert((float *)POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
1660 UNUSED_VARS_NDEBUG(points_len);
1661}
1662
1664 float q0, float q1, float q2, float q3, float *p, int it, int stride)
1665{
1666 float rt0, rt1, rt2, rt3, f;
1667 int a;
1668
1669 f = float(it);
1670 rt0 = q0;
1671 rt1 = 3.0f * (q1 - q0) / f;
1672 f *= f;
1673 rt2 = 3.0f * (q0 - 2.0f * q1 + q2) / f;
1674 f *= it;
1675 rt3 = (q3 - q0 + 3.0f * (q1 - q2)) / f;
1676
1677 q0 = rt0;
1678 q1 = rt1 + rt2 + rt3;
1679 q2 = 2 * rt2 + 6 * rt3;
1680 q3 = 6 * rt3;
1681
1682 for (a = 0; a <= it; a++) {
1683 *p = q0;
1684 p = (float *)POINTER_OFFSET(p, stride);
1685 q0 += q1;
1686 q1 += q2;
1687 q2 += q3;
1688 }
1689}
1690
1692 float q0, float q1, float q2, float q3, float *p, int it, int stride)
1693{
1694 float rt0, rt1, rt2, f;
1695 int a;
1696
1697 f = 1.0f / float(it);
1698
1699 rt0 = 3.0f * (q1 - q0);
1700 rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
1701 rt2 = 6.0f * (q0 + q2) - 12.0f * q1;
1702
1703 q0 = rt0;
1704 q1 = f * (rt1 + rt2);
1705 q2 = 2.0f * f * rt1;
1706
1707 for (a = 0; a <= it; a++) {
1708 *p = q0;
1709 p = (float *)POINTER_OFFSET(p, stride);
1710 q0 += q1;
1711 q1 += q2;
1712 }
1713}
1714
1715static void forward_diff_bezier_cotangent(const float p0[3],
1716 const float p1[3],
1717 const float p2[3],
1718 const float p3[3],
1719 float p[3],
1720 int it,
1721 int stride)
1722{
1723 /* note that these are not perpendicular to the curve
1724 * they need to be rotated for this,
1725 *
1726 * This could also be optimized like BKE_curve_forward_diff_bezier */
1727 for (int a = 0; a <= it; a++) {
1728 float t = float(a) / float(it);
1729
1730 for (int i = 0; i < 3; i++) {
1731 p[i] = (-6.0f * t + 6.0f) * p0[i] + (18.0f * t - 12.0f) * p1[i] +
1732 (-18.0f * t + 6.0f) * p2[i] + (6.0f * t) * p3[i];
1733 }
1734 normalize_v3(p);
1735 p = (float *)POINTER_OFFSET(p, stride);
1736 }
1737}
1738
1739static int cu_isectLL(const float v1[3],
1740 const float v2[3],
1741 const float v3[3],
1742 const float v4[3],
1743 short cox,
1744 short coy,
1745 float *lambda,
1746 float *mu,
1747 float vec[3])
1748{
1749 /* return:
1750 * -1: collinear
1751 * 0: no intersection of segments
1752 * 1: exact intersection of segments
1753 * 2: cross-intersection of segments
1754 */
1755 float deler;
1756
1757 deler = (v1[cox] - v2[cox]) * (v3[coy] - v4[coy]) - (v3[cox] - v4[cox]) * (v1[coy] - v2[coy]);
1758 if (deler == 0.0f) {
1759 return -1;
1760 }
1761
1762 *lambda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]);
1763 *lambda = -(*lambda / deler);
1764
1765 deler = v3[coy] - v4[coy];
1766 if (deler == 0) {
1767 deler = v3[cox] - v4[cox];
1768 *mu = -(*lambda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler;
1769 }
1770 else {
1771 *mu = -(*lambda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler;
1772 }
1773 vec[cox] = *lambda * (v2[cox] - v1[cox]) + v1[cox];
1774 vec[coy] = *lambda * (v2[coy] - v1[coy]) + v1[coy];
1775
1776 if (*lambda >= 0.0f && *lambda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) {
1777 if (*lambda == 0.0f || *lambda == 1.0f || *mu == 0.0f || *mu == 1.0f) {
1778 return 1;
1779 }
1780 return 2;
1781 }
1782 return 0;
1783}
1784
1785static bool bevelinside(const BevList *bl1, const BevList *bl2)
1786{
1787 /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */
1788 /* returns '1' if correct hole. */
1789 BevPoint *bevp, *prevbevp;
1790 float min, max, vec[3], hvec1[3], hvec2[3], lab, mu;
1791 int nr, links = 0, rechts = 0, mode;
1792
1793 /* take first vertex of possible hole */
1794
1795 bevp = bl2->bevpoints;
1796 hvec1[0] = bevp->vec[0];
1797 hvec1[1] = bevp->vec[1];
1798 hvec1[2] = 0.0;
1799 copy_v3_v3(hvec2, hvec1);
1800 hvec2[0] += 1000;
1801
1802 /* test it with all edges of potential surrounding poly */
1803 /* count number of transitions left-right. */
1804
1805 bevp = bl1->bevpoints;
1806 nr = bl1->nr;
1807 prevbevp = bevp + (nr - 1);
1808
1809 while (nr--) {
1810 min = prevbevp->vec[1];
1811 max = bevp->vec[1];
1812 if (max < min) {
1813 min = max;
1814 max = prevbevp->vec[1];
1815 }
1816 if (min != max) {
1817 if (min <= hvec1[1] && max >= hvec1[1]) {
1818 /* there's a transition, calc intersection point */
1819 mode = cu_isectLL(prevbevp->vec, bevp->vec, hvec1, hvec2, 0, 1, &lab, &mu, vec);
1820 /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition
1821 * only allow for one situation: we choose lab= 1.0
1822 */
1823 if (mode >= 0 && lab != 0.0f) {
1824 if (vec[0] < hvec1[0]) {
1825 links++;
1826 }
1827 else {
1828 rechts++;
1829 }
1830 }
1831 }
1832 }
1833 prevbevp = bevp;
1834 bevp++;
1835 }
1836
1837 return (links & 1) && (rechts & 1);
1838}
1839
1842 float left;
1843 int dir;
1844};
1845
1846static int vergxcobev(const void *a1, const void *a2)
1847{
1848 const BevelSort *x1 = (BevelSort *)a1, *x2 = (BevelSort *)a2;
1849
1850 if (x1->left > x2->left) {
1851 return 1;
1852 }
1853 if (x1->left < x2->left) {
1854 return -1;
1855 }
1856 return 0;
1857}
1858
1859/* this function cannot be replaced with atan2, but why? */
1860
1862 float x1, float y1, float x2, float y2, float *r_sina, float *r_cosa)
1863{
1864 float t01, t02, x3, y3;
1865
1866 t01 = sqrtf(x1 * x1 + y1 * y1);
1867 t02 = sqrtf(x2 * x2 + y2 * y2);
1868 if (t01 == 0.0f) {
1869 t01 = 1.0f;
1870 }
1871 if (t02 == 0.0f) {
1872 t02 = 1.0f;
1873 }
1874
1875 x1 /= t01;
1876 y1 /= t01;
1877 x2 /= t02;
1878 y2 /= t02;
1879
1880 t02 = x1 * x2 + y1 * y2;
1881 if (fabsf(t02) >= 1.0f) {
1882 t02 = M_PI_2;
1883 }
1884 else {
1885 t02 = safe_acosf(t02) / 2.0f;
1886 }
1887
1888 t02 = sinf(t02);
1889 if (t02 == 0.0f) {
1890 t02 = 1.0f;
1891 }
1892
1893 x3 = x1 - x2;
1894 y3 = y1 - y2;
1895 if (x3 == 0 && y3 == 0) {
1896 x3 = y1;
1897 y3 = -x1;
1898 }
1899 else {
1900 t01 = sqrtf(x3 * x3 + y3 * y3);
1901 x3 /= t01;
1902 y3 /= t01;
1903 }
1904
1905 *r_sina = -y3 / t02;
1906 *r_cosa = x3 / t02;
1907}
1908
1909static void tilt_bezpart(const BezTriple *prevbezt,
1910 const BezTriple *bezt,
1911 const Nurb *nu,
1912 float *tilt_array,
1913 float *radius_array,
1914 float *weight_array,
1915 int resolu,
1916 int stride)
1917{
1918 const BezTriple *pprev, *next, *last;
1919 float fac, dfac, t[4];
1920 int a;
1921
1922 if (tilt_array == nullptr && radius_array == nullptr) {
1923 return;
1924 }
1925
1926 last = nu->bezt + (nu->pntsu - 1);
1927
1928 /* returns a point */
1929 if (prevbezt == nu->bezt) {
1930 if (nu->flagu & CU_NURB_CYCLIC) {
1931 pprev = last;
1932 }
1933 else {
1934 pprev = prevbezt;
1935 }
1936 }
1937 else {
1938 pprev = prevbezt - 1;
1939 }
1940
1941 /* next point */
1942 if (bezt == last) {
1943 if (nu->flagu & CU_NURB_CYCLIC) {
1944 next = nu->bezt;
1945 }
1946 else {
1947 next = bezt;
1948 }
1949 }
1950 else {
1951 next = bezt + 1;
1952 }
1953
1954 fac = 0.0;
1955 dfac = 1.0f / float(resolu);
1956
1957 for (a = 0; a < resolu; a++, fac += dfac) {
1958 if (tilt_array) {
1959 if (nu->tilt_interp == KEY_CU_EASE) {
1960 /* May as well support for tilt also 2.47 ease interp. */
1961 *tilt_array = prevbezt->tilt +
1962 (bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
1963 }
1964 else {
1966 *tilt_array = t[0] * pprev->tilt + t[1] * prevbezt->tilt + t[2] * bezt->tilt +
1967 t[3] * next->tilt;
1968 }
1969
1970 tilt_array = (float *)POINTER_OFFSET(tilt_array, stride);
1971 }
1972
1973 if (radius_array) {
1974 if (nu->radius_interp == KEY_CU_EASE) {
1975 /* Support 2.47 ease interp
1976 * NOTE: this only takes the 2 points into account,
1977 * giving much more localized results to changes in radius, sometimes you want that. */
1978 *radius_array = prevbezt->radius + (bezt->radius - prevbezt->radius) *
1979 (3.0f * fac * fac - 2.0f * fac * fac * fac);
1980 }
1981 else {
1982
1983 /* reuse interpolation from tilt if we can */
1984 if (tilt_array == nullptr || nu->tilt_interp != nu->radius_interp) {
1986 }
1987 *radius_array = t[0] * pprev->radius + t[1] * prevbezt->radius + t[2] * bezt->radius +
1988 t[3] * next->radius;
1989 }
1990
1991 radius_array = (float *)POINTER_OFFSET(radius_array, stride);
1992 }
1993
1994 if (weight_array) {
1995 /* Basic interpolation for now, could copy tilt interp too. */
1996 *weight_array = prevbezt->weight + (bezt->weight - prevbezt->weight) *
1997 (3.0f * fac * fac - 2.0f * fac * fac * fac);
1998
1999 weight_array = (float *)POINTER_OFFSET(weight_array, stride);
2000 }
2001 }
2002}
2003
2004/* `make_bevel_list_3D_*` functions, at a minimum these must
2005 * fill in the #BevPoint.quat and #BevPoint.dir values. */
2006
2009{
2010 BevPoint *bevp2, *bevp1, *bevp0;
2011 int nr;
2012 const bool is_cyclic = bl->poly != -1;
2013
2014 if (is_cyclic) {
2015 bevp2 = bl->bevpoints;
2016 bevp1 = bevp2 + (bl->nr - 1);
2017 bevp0 = bevp1 - 1;
2018 nr = bl->nr;
2019 }
2020 else {
2021 /* If spline is not cyclic, direction of first and
2022 * last bevel points matches direction of CV handle.
2023 *
2024 * This is getting calculated earlier when we know
2025 * CV's handles and here we might simply skip evaluation
2026 * of direction for this guys.
2027 */
2028
2029 bevp0 = bl->bevpoints;
2030 bevp1 = bevp0 + 1;
2031 bevp2 = bevp1 + 1;
2032
2033 nr = bl->nr - 2;
2034 }
2035
2036 while (nr--) {
2037 /* totally simple */
2038 bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
2039
2040 bevp0 = bevp1;
2041 bevp1 = bevp2;
2042 bevp2++;
2043 }
2044
2045 /* In the unlikely situation that handles define a zeroed direction,
2046 * calculate it from the adjacent points, see #80742.
2047 *
2048 * Only do this as a fallback since we typically want the end-point directions
2049 * to be exactly aligned with the handles at the end-point, see #83117. */
2050 if (is_cyclic == false) {
2051 bevp0 = &bl->bevpoints[0];
2052 bevp1 = &bl->bevpoints[1];
2053 if (UNLIKELY(is_zero_v3(bevp0->dir))) {
2054 sub_v3_v3v3(bevp0->dir, bevp1->vec, bevp0->vec);
2055 if (normalize_v3(bevp0->dir) == 0.0f) {
2056 copy_v3_v3(bevp0->dir, bevp1->dir);
2057 }
2058 }
2059
2060 bevp0 = &bl->bevpoints[bl->nr - 2];
2061 bevp1 = &bl->bevpoints[bl->nr - 1];
2062 if (UNLIKELY(is_zero_v3(bevp1->dir))) {
2063 sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp0->vec);
2064 if (normalize_v3(bevp1->dir) == 0.0f) {
2065 copy_v3_v3(bevp1->dir, bevp0->dir);
2066 }
2067 }
2068 }
2069}
2071{
2072 BevPoint *bevp2, *bevp1, *bevp0;
2073 int nr;
2074
2075 bevp2 = bl->bevpoints;
2076 bevp1 = bevp2 + (bl->nr - 1);
2077 bevp0 = bevp1 - 1;
2078
2079 nr = bl->nr;
2080 while (nr--) {
2081 if (angle_normalized_v3v3(bevp0->tan, bevp1->tan) > DEG2RADF(90.0f)) {
2082 negate_v3(bevp1->tan);
2083 }
2084
2085 bevp0 = bevp1;
2086 bevp1 = bevp2;
2087 bevp2++;
2088 }
2089}
2090/* apply user tilt */
2092{
2093 BevPoint *bevp2, *bevp1;
2094 int nr;
2095 float q[4];
2096
2097 bevp2 = bl->bevpoints;
2098 bevp1 = bevp2 + (bl->nr - 1);
2099
2100 nr = bl->nr;
2101 while (nr--) {
2102 axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
2103 mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
2104 normalize_qt(bevp1->quat);
2105
2106 bevp1 = bevp2;
2107 bevp2++;
2108 }
2109}
2110
2115{
2116 BevPoint *bevp2, *bevp1, *bevp0;
2117 int nr;
2118
2119 float q[4];
2120 float bevp0_quat[4];
2121 int a;
2122
2123 for (a = 0; a < smooth_iter; a++) {
2124 bevp2 = bl->bevpoints;
2125 bevp1 = bevp2 + (bl->nr - 1);
2126 bevp0 = bevp1 - 1;
2127
2128 nr = bl->nr;
2129
2130 if (bl->poly == -1) { /* check its not cyclic */
2131 /* Skip the first point. */
2132 // bevp0 = bevp1;
2133 bevp1 = bevp2;
2134 bevp2++;
2135 nr--;
2136
2137 bevp0 = bevp1;
2138 bevp1 = bevp2;
2139 bevp2++;
2140 nr--;
2141 }
2142
2143 copy_qt_qt(bevp0_quat, bevp0->quat);
2144
2145 while (nr--) {
2146 /* Interpolate quaternions. */
2147 float zaxis[3] = {0, 0, 1}, cross[3], q2[4];
2148 interp_qt_qtqt(q, bevp0_quat, bevp2->quat, 0.5);
2149 normalize_qt(q);
2150
2151 mul_qt_v3(q, zaxis);
2152 cross_v3_v3v3(cross, zaxis, bevp1->dir);
2154 normalize_qt(q2);
2155
2156 copy_qt_qt(bevp0_quat, bevp1->quat);
2157 mul_qt_qtqt(q, q2, q);
2158 interp_qt_qtqt(bevp1->quat, bevp1->quat, q, 0.5);
2159 normalize_qt(bevp1->quat);
2160
2161 // bevp0 = bevp1; /* UNUSED */
2162 bevp1 = bevp2;
2163 bevp2++;
2164 }
2165 }
2166}
2167
2169{
2170 BevPoint *bevp = bl->bevpoints;
2171 int nr = bl->nr;
2172
2174
2175 while (nr--) {
2176 vec_to_quat(bevp->quat, bevp->dir, 5, 1);
2177 bevp++;
2178 }
2179}
2180
2181static void minimum_twist_between_two_points(BevPoint *bevp_curr, const BevPoint *bevp_prev)
2182{
2183 float angle = angle_normalized_v3v3(bevp_prev->dir, bevp_curr->dir);
2184
2185 if (angle > 0.0f) { /* otherwise we can keep as is */
2186 float q[4];
2187 float cross_tmp[3];
2188 cross_v3_v3v3(cross_tmp, bevp_prev->dir, bevp_curr->dir);
2189 axis_angle_to_quat(q, cross_tmp, angle);
2190 mul_qt_qtqt(bevp_curr->quat, q, bevp_prev->quat);
2191 }
2192 else {
2193 copy_qt_qt(bevp_curr->quat, bevp_prev->quat);
2194 }
2195}
2196
2198{
2199 BevPoint *bevp2, *bevp1, *bevp0; /* Standard for all make_bevel_list_3D_* functions. */
2200 int nr;
2201 float q[4];
2202 const bool is_cyclic = bl->poly != -1;
2203 /* NOTE(@ideasman42): For non-cyclic curves only initialize the first direction
2204 * (via `vec_to_quat`), necessary for symmetry, see #71137.
2205 * Otherwise initialize the first and second points before propagating rotation forward.
2206 * This is historical as changing this can cause significantly different output.
2207 * Specifically: `deform_modifiers` test: (`CurveMeshDeform`).
2208 *
2209 * While it would seem correct to only use the first point for non-cyclic curves as well
2210 * the end-points direction is initialized from the input handles (instead of the directions
2211 * between points), there is often a bigger difference in the first and second directions
2212 * than you'd otherwise expect. So using only the first direction breaks compatibility
2213 * enough it's best to leave it as-is. */
2214 const int nr_init = bl->nr - (is_cyclic ? 1 : 2);
2215
2217
2218 bevp2 = bl->bevpoints;
2219 bevp1 = bevp2 + (bl->nr - 1);
2220 bevp0 = bevp1 - 1;
2221
2222 nr = bl->nr;
2223 while (nr--) {
2224
2225 if (nr >= nr_init) {
2226 /* Initialize the rotation, otherwise propagate the previous rotation forward. */
2227 vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
2228 }
2229 else {
2231 }
2232
2233 bevp0 = bevp1;
2234 bevp1 = bevp2;
2235 bevp2++;
2236 }
2237
2238 if (bl->poly != -1) { /* check for cyclic */
2239
2240 /* Need to correct for the start/end points not matching
2241 * do this by calculating the tilt angle difference, then apply
2242 * the rotation gradually over the entire curve.
2243 *
2244 * Note that the split is between last and second last, rather than first/last as you'd expect.
2245 *
2246 * real order is like this
2247 * 0,1,2,3,4 --> 1,2,3,4,0
2248 *
2249 * This is why we compare last with second last.
2250 */
2251 float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
2252
2253 BevPoint *bevp_first;
2254 BevPoint *bevp_last;
2255
2256 bevp_first = bl->bevpoints;
2257 bevp_first += bl->nr - 1;
2258 bevp_last = bevp_first;
2259 bevp_last--;
2260
2261 /* Quaternions and vectors are normalized, should not need to re-normalize. */
2262 mul_qt_v3(bevp_first->quat, vec_1);
2263 mul_qt_v3(bevp_last->quat, vec_2);
2264 normalize_v3(vec_1);
2265 normalize_v3(vec_2);
2266
2267 /* align the vector, can avoid this and it looks 98% OK but
2268 * better to align the angle quat roll's before comparing */
2269 {
2270 cross_v3_v3v3(cross_tmp, bevp_last->dir, bevp_first->dir);
2271 angle = angle_normalized_v3v3(bevp_first->dir, bevp_last->dir);
2272 axis_angle_to_quat(q, cross_tmp, angle);
2273 mul_qt_v3(q, vec_2);
2274 }
2275
2276 angle = angle_normalized_v3v3(vec_1, vec_2);
2277
2278 /* flip rotation if needs be */
2279 cross_v3_v3v3(cross_tmp, vec_1, vec_2);
2280 normalize_v3(cross_tmp);
2281 if (angle_normalized_v3v3(bevp_first->dir, cross_tmp) < DEG2RADF(90.0f)) {
2282 angle = -angle;
2283 }
2284
2285 bevp2 = bl->bevpoints;
2286 bevp1 = bevp2 + (bl->nr - 1);
2287 bevp0 = bevp1 - 1;
2288
2289 nr = bl->nr;
2290 while (nr--) {
2291 ang_fac = angle * (1.0f - (float(nr) / bl->nr)); /* also works */
2292
2293 axis_angle_to_quat(q, bevp1->dir, ang_fac);
2294 mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
2295
2296 bevp0 = bevp1;
2297 bevp1 = bevp2;
2298 bevp2++;
2299 }
2300 }
2301 else {
2302 /* Need to correct quat for the first/last point,
2303 * this is so because previously it was only calculated
2304 * using its own direction, which might not correspond
2305 * the twist of neighbor point.
2306 */
2307 bevp1 = bl->bevpoints;
2308 bevp0 = bevp1 + 1;
2310
2311 bevp2 = bl->bevpoints;
2312 bevp1 = bevp2 + (bl->nr - 1);
2313 bevp0 = bevp1 - 1;
2315 }
2316}
2317
2319{
2320 BevPoint *bevp2, *bevp1, *bevp0; /* Standard for all make_bevel_list_3D_* functions. */
2321 int nr;
2322
2323 float bevp0_tan[3];
2324
2327
2328 /* correct the tangents */
2329 bevp2 = bl->bevpoints;
2330 bevp1 = bevp2 + (bl->nr - 1);
2331 bevp0 = bevp1 - 1;
2332
2333 nr = bl->nr;
2334 while (nr--) {
2335 float cross_tmp[3];
2336 cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
2337 cross_v3_v3v3(bevp1->tan, cross_tmp, bevp1->dir);
2338 normalize_v3(bevp1->tan);
2339
2340 bevp0 = bevp1;
2341 bevp1 = bevp2;
2342 bevp2++;
2343 }
2344
2345 /* now for the real twist calc */
2346 bevp2 = bl->bevpoints;
2347 bevp1 = bevp2 + (bl->nr - 1);
2348 bevp0 = bevp1 - 1;
2349
2350 copy_v3_v3(bevp0_tan, bevp0->tan);
2351
2352 nr = bl->nr;
2353 while (nr--) {
2354 /* make perpendicular, modify tan in place, is ok */
2355 float cross_tmp[3];
2356 const float zero[3] = {0, 0, 0};
2357
2358 cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
2359 normalize_v3(cross_tmp);
2360 tri_to_quat(bevp1->quat, zero, cross_tmp, bevp1->tan); /* XXX: could be faster. */
2361
2362 // bevp0 = bevp1; /* UNUSED */
2363 bevp1 = bevp2;
2364 bevp2++;
2365 }
2366}
2367
2368static void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode)
2369{
2370 switch (twist_mode) {
2371 case CU_TWIST_TANGENT:
2373 break;
2374 case CU_TWIST_MINIMUM:
2376 break;
2377 default: /* CU_TWIST_Z_UP default, pre 2.49c */
2379 break;
2380 }
2381
2382 if (smooth_iter) {
2384 }
2385
2387}
2388
2389/* only for 2 points */
2391{
2392 float q[4];
2393
2394 BevPoint *bevp2 = bl->bevpoints;
2395 BevPoint *bevp1 = bevp2 + 1;
2396
2397 /* simple quat/dir */
2398 sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp2->vec);
2399 normalize_v3(bevp1->dir);
2400
2401 vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
2402 axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
2403 mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
2404 normalize_qt(bevp1->quat);
2405
2406 copy_v3_v3(bevp2->dir, bevp1->dir);
2407 vec_to_quat(bevp2->quat, bevp2->dir, 5, 1);
2408 axis_angle_to_quat(q, bevp2->dir, bevp2->tilt);
2409 mul_qt_qtqt(bevp2->quat, q, bevp2->quat);
2410 normalize_qt(bevp2->quat);
2411}
2412
2413/* only for 2 points */
2415{
2416 BevPoint *bevp2 = bl->bevpoints;
2417 BevPoint *bevp1 = bevp2 + 1;
2418
2419 const float x1 = bevp1->vec[0] - bevp2->vec[0];
2420 const float y1 = bevp1->vec[1] - bevp2->vec[1];
2421
2422 calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa));
2423 bevp2->sina = bevp1->sina;
2424 bevp2->cosa = bevp1->cosa;
2425
2426 /* fill in dir & quat */
2428}
2429
2431{
2432 /* NOTE(@ideasman42): `bevp->dir` and `bevp->quat` are not needed for beveling but are
2433 * used when making a path from a 2D curve, therefore they need to be set. */
2434
2435 BevPoint *bevp0, *bevp1, *bevp2;
2436 int nr;
2437
2438 if (bl->poly != -1) {
2439 bevp2 = bl->bevpoints;
2440 bevp1 = bevp2 + (bl->nr - 1);
2441 bevp0 = bevp1 - 1;
2442 nr = bl->nr;
2443 }
2444 else {
2445 bevp0 = bl->bevpoints;
2446 bevp1 = bevp0 + 1;
2447 bevp2 = bevp1 + 1;
2448
2449 nr = bl->nr - 2;
2450 }
2451
2452 while (nr--) {
2453 const float x1 = bevp1->vec[0] - bevp0->vec[0];
2454 const float x2 = bevp1->vec[0] - bevp2->vec[0];
2455 const float y1 = bevp1->vec[1] - bevp0->vec[1];
2456 const float y2 = bevp1->vec[1] - bevp2->vec[1];
2457
2458 calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
2459
2460 /* from: make_bevel_list_3D_zup, could call but avoid a second loop.
2461 * no need for tricky tilt calculation as with 3D curves */
2462 bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
2463 vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
2464 /* done with inline make_bevel_list_3D_zup */
2465
2466 bevp0 = bevp1;
2467 bevp1 = bevp2;
2468 bevp2++;
2469 }
2470
2471 /* correct non-cyclic cases */
2472 if (bl->poly == -1) {
2473 BevPoint *bevp;
2474 float angle;
2475
2476 /* first */
2477 bevp = bl->bevpoints;
2478 angle = atan2f(bevp->dir[0], bevp->dir[1]) - float(M_PI_2);
2479 bevp->sina = sinf(angle);
2480 bevp->cosa = cosf(angle);
2481 vec_to_quat(bevp->quat, bevp->dir, 5, 1);
2482
2483 /* last */
2484 bevp = bl->bevpoints;
2485 bevp += (bl->nr - 1);
2486 angle = atan2f(bevp->dir[0], bevp->dir[1]) - float(M_PI_2);
2487 bevp->sina = sinf(angle);
2488 bevp->cosa = cosf(angle);
2489 vec_to_quat(bevp->quat, bevp->dir, 5, 1);
2490 }
2491}
2492
2494{
2495 if (nu->pntsu > 1) {
2496 BPoint *first_bp = nu->bp, *last_bp = nu->bp + (nu->pntsu - 1);
2497 BevPoint *first_bevp, *last_bevp;
2498
2499 first_bevp = bl->bevpoints;
2500 last_bevp = first_bevp + (bl->nr - 1);
2501
2502 sub_v3_v3v3(first_bevp->dir, (first_bp + 1)->vec, first_bp->vec);
2503 normalize_v3(first_bevp->dir);
2504
2505 sub_v3_v3v3(last_bevp->dir, last_bp->vec, (last_bp - 1)->vec);
2506 normalize_v3(last_bevp->dir);
2507 }
2508}
2509
2511{
2512 LISTBASE_FOREACH_MUTABLE (BevList *, bl, bev) {
2513 if (bl->seglen != nullptr) {
2514 MEM_freeN(bl->seglen);
2515 }
2516 if (bl->segbevcount != nullptr) {
2517 MEM_freeN(bl->segbevcount);
2518 }
2519 if (bl->bevpoints != nullptr) {
2520 MEM_freeN(bl->bevpoints);
2521 }
2522 MEM_freeN(bl);
2523 }
2524
2525 BLI_listbase_clear(bev);
2526}
2527
2528void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
2529{
2530 /* - Convert all curves to polys, with indication of resolution and flags for double-vertices.
2531 * - Possibly; do a smart vertex removal (in case #Nurb).
2532 * - Separate in individual blocks with #BoundBox.
2533 * - Auto-hole detection.
2534 */
2535
2536 /* This function needs an object, because of `tflag` and `upflag`. */
2537 Curve *cu = (Curve *)ob->data;
2538 BezTriple *bezt, *prevbezt;
2539 BPoint *bp;
2540 BevList *blnew;
2541 BevPoint *bevp2, *bevp1 = nullptr, *bevp0;
2542 const float threshold = 0.00001f;
2543 float min, inp;
2544 float *seglen = nullptr;
2545 BevelSort *sortdata, *sd, *sd1;
2546 int a, b, nr, poly, resolu = 0, len = 0, segcount;
2547 int *segbevcount;
2548 bool do_tilt, do_radius, do_weight;
2549 bool is_editmode = false;
2550 ListBase *bev;
2551
2552 /* segbevcount also requires seglen. */
2553 const bool need_seglen = ELEM(
2556
2557 bev = &ob->runtime->curve_cache->bev;
2558
2559#if 0
2560 /* do we need to calculate the radius for each point? */
2561 do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 :
2562 1;
2563#endif
2564
2565 /* STEP 1: MAKE POLYS */
2566
2567 BKE_curve_bevelList_free(&ob->runtime->curve_cache->bev);
2568 if (cu->editnurb && ob->type != OB_FONT) {
2569 is_editmode = true;
2570 }
2571
2572 LISTBASE_FOREACH (const Nurb *, nu, nurbs) {
2573 if (nu->hide && is_editmode) {
2574 continue;
2575 }
2576
2577 /* check we are a single point? also check we are not a surface and that the orderu is sane,
2578 * enforced in the UI but can go wrong possibly */
2579 if (!BKE_nurb_check_valid_u(nu)) {
2580 BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), "makeBevelList1");
2581 bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
2582 BLI_addtail(bev, bl);
2583 bl->nr = 0;
2584 bl->charidx = nu->charidx;
2585 continue;
2586 }
2587
2588 /* Tilt, as the rotation angle of curve control points, is only calculated for 3D curves,
2589 * (since this transformation affects the 3D space). */
2590 do_tilt = (cu->flag & CU_3D) != 0;
2591
2592 /* Normal display uses the radius, better just to calculate them. */
2593 do_radius = CU_DO_RADIUS(cu, nu);
2594
2595 do_weight = true;
2596
2597 BevPoint *bevp;
2598
2599 if (for_render && cu->resolu_ren != 0) {
2600 resolu = cu->resolu_ren;
2601 }
2602 else {
2603 resolu = nu->resolu;
2604 }
2605
2606 segcount = SEGMENTSU(nu);
2607
2608 if (nu->type == CU_POLY) {
2609 len = nu->pntsu;
2610 BevList *bl = MEM_cnew<BevList>(__func__);
2611 bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
2612 if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
2613 bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
2614 bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
2615 }
2616 BLI_addtail(bev, bl);
2617
2618 bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
2619 bl->nr = len;
2620 bl->dupe_nr = 0;
2621 bl->charidx = nu->charidx;
2622 bevp = bl->bevpoints;
2623 bevp->offset = 0;
2624 bp = nu->bp;
2625 seglen = bl->seglen;
2626 segbevcount = bl->segbevcount;
2627
2628 while (len--) {
2629 copy_v3_v3(bevp->vec, bp->vec);
2630 bevp->tilt = bp->tilt;
2631 bevp->radius = bp->radius;
2632 bevp->weight = bp->weight;
2633 bp++;
2634 if (seglen != nullptr && len != 0) {
2635 *seglen = len_v3v3(bevp->vec, bp->vec);
2636 bevp++;
2637 bevp->offset = *seglen;
2638 if (*seglen > threshold) {
2639 *segbevcount = 1;
2640 }
2641 else {
2642 *segbevcount = 0;
2643 }
2644 seglen++;
2645 segbevcount++;
2646 }
2647 else {
2648 bevp++;
2649 }
2650 }
2651
2652 if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
2654 }
2655 }
2656 else if (nu->type == CU_BEZIER) {
2657 /* in case last point is not cyclic */
2658 len = segcount * resolu + 1;
2659
2660 BevList *bl = MEM_cnew<BevList>(__func__);
2661 bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
2662 if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
2663 bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
2664 bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
2665 }
2666 BLI_addtail(bev, bl);
2667
2668 bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
2669 bl->charidx = nu->charidx;
2670
2671 bevp = bl->bevpoints;
2672 seglen = bl->seglen;
2673 segbevcount = bl->segbevcount;
2674
2675 bevp->offset = 0;
2676 if (seglen != nullptr) {
2677 *seglen = 0;
2678 *segbevcount = 0;
2679 }
2680
2681 a = nu->pntsu - 1;
2682 bezt = nu->bezt;
2683 if (nu->flagu & CU_NURB_CYCLIC) {
2684 a++;
2685 prevbezt = nu->bezt + (nu->pntsu - 1);
2686 }
2687 else {
2688 prevbezt = bezt;
2689 bezt++;
2690 }
2691
2692 sub_v3_v3v3(bevp->dir, prevbezt->vec[2], prevbezt->vec[1]);
2693 normalize_v3(bevp->dir);
2694
2695 BLI_assert(segcount >= a);
2696
2697 while (a--) {
2698 if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
2699
2700 copy_v3_v3(bevp->vec, prevbezt->vec[1]);
2701 bevp->tilt = prevbezt->tilt;
2702 bevp->radius = prevbezt->radius;
2703 bevp->weight = prevbezt->weight;
2704 bevp->dupe_tag = false;
2705 bevp++;
2706 bl->nr++;
2707 bl->dupe_nr = 1;
2708 if (seglen != nullptr) {
2709 *seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
2710 bevp->offset = *seglen;
2711 seglen++;
2712 /* match segbevcount to the cleaned up bevel lists (see STEP 2) */
2713 if (bevp->offset > threshold) {
2714 *segbevcount = 1;
2715 }
2716 segbevcount++;
2717 }
2718 }
2719 else {
2720 /* Always do all three, to prevent data hanging around. */
2721 int j;
2722
2723 /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
2724 for (j = 0; j < 3; j++) {
2725 BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
2726 prevbezt->vec[2][j],
2727 bezt->vec[0][j],
2728 bezt->vec[1][j],
2729 &(bevp->vec[j]),
2730 resolu,
2731 sizeof(BevPoint));
2732 }
2733
2734 /* If both arrays are `nullptr` do nothing. */
2735 tilt_bezpart(prevbezt,
2736 bezt,
2737 nu,
2738 do_tilt ? &bevp->tilt : nullptr,
2739 do_radius ? &bevp->radius : nullptr,
2740 do_weight ? &bevp->weight : nullptr,
2741 resolu,
2742 sizeof(BevPoint));
2743
2744 if (cu->twist_mode == CU_TWIST_TANGENT) {
2746 prevbezt->vec[2],
2747 bezt->vec[0],
2748 bezt->vec[1],
2749 bevp->tan,
2750 resolu,
2751 sizeof(BevPoint));
2752 }
2753
2754 /* `seglen`. */
2755 if (seglen != nullptr) {
2756 *seglen = 0;
2757 *segbevcount = 0;
2758 for (j = 0; j < resolu; j++) {
2759 bevp0 = bevp;
2760 bevp++;
2761 bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
2762 /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */
2763 if (bevp->offset > threshold) {
2764 *seglen += bevp->offset;
2765 *segbevcount += 1;
2766 }
2767 }
2768 seglen++;
2769 segbevcount++;
2770 }
2771 else {
2772 bevp += resolu;
2773 }
2774 bl->nr += resolu;
2775 }
2776 prevbezt = bezt;
2777 bezt++;
2778 }
2779
2780 if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic: endpoint */
2781 copy_v3_v3(bevp->vec, prevbezt->vec[1]);
2782 bevp->tilt = prevbezt->tilt;
2783 bevp->radius = prevbezt->radius;
2784 bevp->weight = prevbezt->weight;
2785
2786 sub_v3_v3v3(bevp->dir, prevbezt->vec[1], prevbezt->vec[0]);
2787 normalize_v3(bevp->dir);
2788
2789 bl->nr++;
2790 }
2791 }
2792 else if (nu->type == CU_NURBS) {
2793 if (nu->pntsv == 1) {
2794 len = (resolu * segcount);
2795
2796 BevList *bl = MEM_cnew<BevList>(__func__);
2797 bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
2798 if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
2799 bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
2800 bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
2801 }
2802 BLI_addtail(bev, bl);
2803 bl->nr = len;
2804 bl->dupe_nr = 0;
2805 bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
2806 bl->charidx = nu->charidx;
2807
2808 bevp = bl->bevpoints;
2809 seglen = bl->seglen;
2810 segbevcount = bl->segbevcount;
2811
2813 &bevp->vec[0],
2814 do_tilt ? &bevp->tilt : nullptr,
2815 do_radius ? &bevp->radius : nullptr,
2816 do_weight ? &bevp->weight : nullptr,
2817 resolu,
2818 sizeof(BevPoint));
2819
2820 /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
2821 if (seglen != nullptr) {
2822 nr = segcount;
2823 bevp0 = bevp;
2824 bevp++;
2825 while (nr) {
2826 int j;
2827 *seglen = 0;
2828 *segbevcount = 0;
2829 /* We keep last bevel segment zero-length. */
2830 for (j = 0; j < ((nr == 1) ? (resolu - 1) : resolu); j++) {
2831 bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
2832 if (bevp->offset > threshold) {
2833 *seglen += bevp->offset;
2834 *segbevcount += 1;
2835 }
2836 bevp0 = bevp;
2837 bevp++;
2838 }
2839 seglen++;
2840 segbevcount++;
2841 nr--;
2842 }
2843 }
2844
2845 if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
2847 }
2848 }
2849 }
2850 }
2851
2852 /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
2853 LISTBASE_FOREACH (BevList *, bl, bev) {
2854 if (bl->nr == 0) { /* null bevel items come from single points */
2855 continue;
2856 }
2857
2858 /* Scale the threshold so high resolution shapes don't get over reduced, see: #49850. */
2859 const float threshold_resolu = 0.00001f / resolu;
2860 const bool is_cyclic = bl->poly != -1;
2861 nr = bl->nr;
2862 if (is_cyclic) {
2863 bevp1 = bl->bevpoints;
2864 bevp0 = bevp1 + (nr - 1);
2865 }
2866 else {
2867 bevp0 = bl->bevpoints;
2868 bevp0->offset = 0;
2869 bevp1 = bevp0 + 1;
2870 }
2871 nr--;
2872 while (nr--) {
2873 if (seglen != nullptr) {
2874 if (fabsf(bevp1->offset) < threshold) {
2875 bevp0->dupe_tag = true;
2876 bl->dupe_nr++;
2877 }
2878 }
2879 else {
2880 if (compare_v3v3(bevp0->vec, bevp1->vec, threshold_resolu)) {
2881 bevp0->dupe_tag = true;
2882 bl->dupe_nr++;
2883 }
2884 }
2885 bevp0 = bevp1;
2886 bevp1++;
2887 }
2888 }
2889
2890 LISTBASE_FOREACH_MUTABLE (BevList *, bl, bev) {
2891 if (bl->nr == 0 || bl->dupe_nr == 0) {
2892 continue;
2893 }
2894
2895 nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */
2896 blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4");
2897 memcpy(blnew, bl, sizeof(BevList));
2898 blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
2899 if (!blnew->bevpoints) {
2900 MEM_freeN(blnew);
2901 break;
2902 }
2903 blnew->segbevcount = bl->segbevcount;
2904 blnew->seglen = bl->seglen;
2905 blnew->nr = 0;
2906 BLI_remlink(bev, bl);
2907 BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */
2908 bevp0 = bl->bevpoints;
2909 bevp1 = blnew->bevpoints;
2910 nr = bl->nr;
2911 while (nr--) {
2912 if (bevp0->dupe_tag == 0) {
2913 memcpy(bevp1, bevp0, sizeof(BevPoint));
2914 bevp1++;
2915 blnew->nr++;
2916 }
2917 bevp0++;
2918 }
2919 if (bl->bevpoints != nullptr) {
2920 MEM_freeN(bl->bevpoints);
2921 }
2922 MEM_freeN(bl);
2923 blnew->dupe_nr = 0;
2924 }
2925
2926 /* STEP 3: POLYS COUNT AND AUTOHOLE */
2927 poly = 0;
2928 LISTBASE_FOREACH (BevList *, bl, bev) {
2929 if (bl->nr && bl->poly >= 0) {
2930 poly++;
2931 bl->poly = poly;
2932 bl->hole = 0;
2933 }
2934 }
2935
2936 /* find extreme left points, also test (turning) direction */
2937 if (poly > 0) {
2938 sd = sortdata = (BevelSort *)MEM_malloc_arrayN(poly, sizeof(BevelSort), __func__);
2939 LISTBASE_FOREACH (BevList *, bl, bev) {
2940 if (bl->poly > 0) {
2941 BevPoint *bevp;
2942
2943 bevp = bl->bevpoints;
2944 bevp1 = bl->bevpoints;
2945 min = bevp1->vec[0];
2946 nr = bl->nr;
2947 while (nr--) {
2948 if (min > bevp->vec[0]) {
2949 min = bevp->vec[0];
2950 bevp1 = bevp;
2951 }
2952 bevp++;
2953 }
2954 sd->bl = bl;
2955 sd->left = min;
2956
2957 bevp = bl->bevpoints;
2958 if (bevp1 == bevp) {
2959 bevp0 = bevp + (bl->nr - 1);
2960 }
2961 else {
2962 bevp0 = bevp1 - 1;
2963 }
2964 bevp = bevp + (bl->nr - 1);
2965 if (bevp1 == bevp) {
2966 bevp2 = bl->bevpoints;
2967 }
2968 else {
2969 bevp2 = bevp1 + 1;
2970 }
2971
2972 inp = ((bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) +
2973 (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0]));
2974
2975 if (inp > 0.0f) {
2976 sd->dir = 1;
2977 }
2978 else {
2979 sd->dir = 0;
2980 }
2981
2982 sd++;
2983 }
2984 }
2985 qsort(sortdata, poly, sizeof(BevelSort), vergxcobev);
2986
2987 sd = sortdata + 1;
2988 for (a = 1; a < poly; a++, sd++) {
2989 BevList *bl = sd->bl; /* is bl a hole? */
2990 sd1 = sortdata + (a - 1);
2991 for (b = a - 1; b >= 0; b--, sd1--) { /* all polys to the left */
2992 if (sd1->bl->charidx == bl->charidx) { /* for text, only check matching char */
2993 if (bevelinside(sd1->bl, bl)) {
2994 bl->hole = 1 - sd1->bl->hole;
2995 break;
2996 }
2997 }
2998 }
2999 }
3000
3001 /* turning direction */
3002 if (CU_IS_2D(cu)) {
3003 sd = sortdata;
3004 for (a = 0; a < poly; a++, sd++) {
3005 if (sd->bl->hole == sd->dir) {
3006 BevList *bl = sd->bl;
3007 bevp1 = bl->bevpoints;
3008 bevp2 = bevp1 + (bl->nr - 1);
3009 nr = bl->nr / 2;
3010 while (nr--) {
3011 std::swap(*bevp1, *bevp2);
3012 bevp1++;
3013 bevp2--;
3014 }
3015 }
3016 }
3017 }
3018 MEM_freeN(sortdata);
3019 }
3020
3021 /* STEP 4: 2D-COSINES or 3D ORIENTATION */
3022 if (CU_IS_2D(cu)) {
3023 /* 2D Curves */
3024 LISTBASE_FOREACH (BevList *, bl, bev) {
3025 if (bl->nr < 2) {
3026 BevPoint *bevp = bl->bevpoints;
3027 unit_qt(bevp->quat);
3028 }
3029 else if (bl->nr == 2) { /* 2 points, treat separately. */
3031 }
3032 else {
3034 }
3035 }
3036 }
3037 else {
3038 /* 3D Curves */
3039 LISTBASE_FOREACH (BevList *, bl, bev) {
3040 if (bl->nr < 2) {
3041 BevPoint *bevp = bl->bevpoints;
3042 unit_qt(bevp->quat);
3043 }
3044 else if (bl->nr == 2) { /* 2 points, treat separately. */
3046 }
3047 else {
3048 make_bevel_list_3D(bl, int(resolu * cu->twist_smooth), cu->twist_mode);
3049 }
3050 }
3051 }
3052}
3053
3054/* ****************** HANDLES ************** */
3055
3057 const BezTriple *prev,
3058 const BezTriple *next,
3059 eBezTriple_Flag handle_sel_flag,
3060 bool is_fcurve,
3061 bool skip_align,
3062 char fcurve_smoothing)
3063{
3064 /* defines to avoid confusion */
3065#define p2_h1 ((p2)-3)
3066#define p2_h2 ((p2) + 3)
3067
3068 const float *p1, *p3;
3069 float *p2;
3070 float pt[3];
3071 float dvec_a[3], dvec_b[3];
3072 float len, len_a, len_b;
3073 const float eps = 1e-5;
3074
3075 /* assume normal handle until we check */
3077
3078 if (bezt->h1 == 0 && bezt->h2 == 0) {
3079 return;
3080 }
3081
3082 p2 = bezt->vec[1];
3083
3084 if (prev == nullptr) {
3085 p3 = next->vec[1];
3086 pt[0] = 2.0f * p2[0] - p3[0];
3087 pt[1] = 2.0f * p2[1] - p3[1];
3088 pt[2] = 2.0f * p2[2] - p3[2];
3089 p1 = pt;
3090 }
3091 else {
3092 p1 = prev->vec[1];
3093 }
3094
3095 if (next == nullptr) {
3096 pt[0] = 2.0f * p2[0] - p1[0];
3097 pt[1] = 2.0f * p2[1] - p1[1];
3098 pt[2] = 2.0f * p2[2] - p1[2];
3099 p3 = pt;
3100 }
3101 else {
3102 p3 = next->vec[1];
3103 }
3104
3105 sub_v3_v3v3(dvec_a, p2, p1);
3106 sub_v3_v3v3(dvec_b, p3, p2);
3107
3108 if (is_fcurve) {
3109 len_a = dvec_a[0];
3110 len_b = dvec_b[0];
3111 }
3112 else {
3113 len_a = len_v3(dvec_a);
3114 len_b = len_v3(dvec_b);
3115 }
3116
3117 if (len_a == 0.0f) {
3118 len_a = 1.0f;
3119 }
3120 if (len_b == 0.0f) {
3121 len_b = 1.0f;
3122 }
3123
3124 if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
3125 float tvec[3];
3126 tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
3127 tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
3128 tvec[2] = dvec_b[2] / len_b + dvec_a[2] / len_a;
3129
3130 if (is_fcurve) {
3131 if (fcurve_smoothing != FCURVE_SMOOTH_NONE) {
3132 /* force the horizontal handle size to be 1/3 of the key interval so that
3133 * the X component of the parametric bezier curve is a linear spline */
3134 len = 6.0f / 2.5614f;
3135 }
3136 else {
3137 len = tvec[0];
3138 }
3139 }
3140 else {
3141 len = len_v3(tvec);
3142 }
3143 len *= 2.5614f;
3144
3145 if (len != 0.0f) {
3146 /* Only for F-Curves. */
3147 bool leftviolate = false, rightviolate = false;
3148
3149 if (!is_fcurve || fcurve_smoothing == FCURVE_SMOOTH_NONE) {
3150 if (len_a > 5.0f * len_b) {
3151 len_a = 5.0f * len_b;
3152 }
3153 if (len_b > 5.0f * len_a) {
3154 len_b = 5.0f * len_a;
3155 }
3156 }
3157
3158 if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
3159 len_a /= len;
3160 madd_v3_v3v3fl(p2_h1, p2, tvec, -len_a);
3161
3162 if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
3163 float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
3164 float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
3165 if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
3166 bezt->vec[0][1] = bezt->vec[1][1];
3168 }
3169 else { /* handles should not be beyond y coord of two others */
3170 if (ydiff1 <= 0.0f) {
3171 if (prev->vec[1][1] > bezt->vec[0][1]) {
3172 bezt->vec[0][1] = prev->vec[1][1];
3173 leftviolate = true;
3174 }
3175 }
3176 else {
3177 if (prev->vec[1][1] < bezt->vec[0][1]) {
3178 bezt->vec[0][1] = prev->vec[1][1];
3179 leftviolate = true;
3180 }
3181 }
3182 }
3183 }
3184 }
3185 if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
3186 len_b /= len;
3187 madd_v3_v3v3fl(p2_h2, p2, tvec, len_b);
3188
3189 if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
3190 float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
3191 float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
3192 if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
3193 bezt->vec[2][1] = bezt->vec[1][1];
3195 }
3196 else { /* handles should not be beyond y coord of two others */
3197 if (ydiff1 <= 0.0f) {
3198 if (next->vec[1][1] < bezt->vec[2][1]) {
3199 bezt->vec[2][1] = next->vec[1][1];
3200 rightviolate = true;
3201 }
3202 }
3203 else {
3204 if (next->vec[1][1] > bezt->vec[2][1]) {
3205 bezt->vec[2][1] = next->vec[1][1];
3206 rightviolate = true;
3207 }
3208 }
3209 }
3210 }
3211 }
3212 if (leftviolate || rightviolate) { /* align left handle */
3213 BLI_assert(is_fcurve);
3214 /* simple 2d calculation */
3215 float h1_x = p2_h1[0] - p2[0];
3216 float h2_x = p2[0] - p2_h2[0];
3217
3218 if (leftviolate) {
3219 p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
3220 }
3221 else {
3222 p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
3223 }
3224 }
3225 }
3226 }
3227
3228 if (bezt->h1 == HD_VECT) { /* vector */
3229 madd_v3_v3v3fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
3230 }
3231 if (bezt->h2 == HD_VECT) {
3232 madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
3233 }
3234
3235 if (skip_align ||
3236 /* When one handle is free, aligning makes no sense, see: #35952 */
3237 ELEM(HD_FREE, bezt->h1, bezt->h2) ||
3238 /* Also when no handles are aligned, skip this step. */
3239 (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2)))
3240 {
3241 /* Handles need to be updated during animation and applying stuff like hooks,
3242 * but in such situations it's quite difficult to distinguish in which order
3243 * align handles should be aligned so skip them for now. */
3244 return;
3245 }
3246
3247 len_a = len_v3v3(p2, p2_h1);
3248 len_b = len_v3v3(p2, p2_h2);
3249
3250 if (len_a == 0.0f) {
3251 len_a = 1.0f;
3252 }
3253 if (len_b == 0.0f) {
3254 len_b = 1.0f;
3255 }
3256
3257 const float len_ratio = len_a / len_b;
3258
3259 if (bezt->f1 & handle_sel_flag) { /* order of calculation */
3260 if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
3261 if (len_a > eps) {
3262 len = 1.0f / len_ratio;
3263 p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
3264 p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
3265 p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
3266 }
3267 }
3268 if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
3269 if (len_b > eps) {
3270 len = len_ratio;
3271 p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
3272 p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
3273 p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
3274 }
3275 }
3276 }
3277 else {
3278 if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
3279 if (len_b > eps) {
3280 len = len_ratio;
3281 p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
3282 p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
3283 p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
3284 }
3285 }
3286 if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
3287 if (len_a > eps) {
3288 len = 1.0f / len_ratio;
3289 p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
3290 p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
3291 p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
3292 }
3293 }
3294 }
3295
3296#undef p2_h1
3297#undef p2_h2
3298}
3299
3300static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bool skip_align)
3301{
3302 BezTriple *bezt, *prev, *next;
3303 int a;
3304
3305 if (nu->type != CU_BEZIER) {
3306 return;
3307 }
3308 if (nu->pntsu < 2) {
3309 return;
3310 }
3311
3312 a = nu->pntsu;
3313 bezt = nu->bezt;
3314 if (nu->flagu & CU_NURB_CYCLIC) {
3315 prev = bezt + (a - 1);
3316 }
3317 else {
3318 prev = nullptr;
3319 }
3320 next = bezt + 1;
3321
3322 while (a--) {
3323 calchandleNurb_intern(bezt, prev, next, handle_sel_flag, false, skip_align, 0);
3324 prev = bezt;
3325 if (a == 1) {
3326 if (nu->flagu & CU_NURB_CYCLIC) {
3327 next = nu->bezt;
3328 }
3329 else {
3330 next = nullptr;
3331 }
3332 }
3333 else if (next != nullptr) {
3334 next++;
3335 }
3336
3337 bezt++;
3338 }
3339}
3340
3351static void *allocate_arrays(int count, float ***floats, char ***chars, const char *name)
3352{
3353 size_t num_floats = 0, num_chars = 0;
3354
3355 while (floats && floats[num_floats]) {
3356 num_floats++;
3357 }
3358
3359 while (chars && chars[num_chars]) {
3360 num_chars++;
3361 }
3362
3363 void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
3364
3365 if (!buffer) {
3366 return nullptr;
3367 }
3368
3369 float *fptr = (float *)buffer;
3370
3371 for (int i = 0; i < num_floats; i++, fptr += count) {
3372 *floats[i] = fptr;
3373 }
3374
3375 char *cptr = (char *)fptr;
3376
3377 for (int i = 0; i < num_chars; i++, cptr += count) {
3378 *chars[i] = cptr;
3379 }
3380
3381 return buffer;
3382}
3383
3384static void free_arrays(void *buffer)
3385{
3386 MEM_freeN(buffer);
3387}
3388
3389/* computes in which direction to change h[i] to satisfy conditions better */
3390static float bezier_relax_direction(const float *a,
3391 const float *b,
3392 const float *c,
3393 const float *d,
3394 const float *h,
3395 int i,
3396 int count)
3397{
3398 /* current deviation between sides of the equation */
3399 float state = a[i] * h[(i + count - 1) % count] + b[i] * h[i] + c[i] * h[(i + 1) % count] - d[i];
3400
3401 /* only the sign is meaningful */
3402 return -state * b[i];
3403}
3404
3405static void bezier_lock_unknown(float *a, float *b, float *c, float *d, int i, float value)
3406{
3407 a[i] = c[i] = 0.0f;
3408 b[i] = 1.0f;
3409 d[i] = value;
3410}
3411
3412static void bezier_restore_equation(float *a,
3413 float *b,
3414 float *c,
3415 float *d,
3416 const float *a0,
3417 const float *b0,
3418 const float *c0,
3419 const float *d0,
3420 int i)
3421{
3422 a[i] = a0[i];
3423 b[i] = b0[i];
3424 c[i] = c0[i];
3425 d[i] = d0[i];
3426}
3427
3429 float *b,
3430 float *c,
3431 float *d,
3432 float *h,
3433 const float *hmin,
3434 const float *hmax,
3435 int solve_count)
3436{
3437 float *a0, *b0, *c0, *d0;
3438 float **arrays[] = {&a0, &b0, &c0, &d0, nullptr};
3439 char *is_locked, *num_unlocks;
3440 char **flagarrays[] = {&is_locked, &num_unlocks, nullptr};
3441
3442 void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits");
3443 if (!tmps) {
3444 return false;
3445 }
3446
3447 memcpy(a0, a, sizeof(float) * solve_count);
3448 memcpy(b0, b, sizeof(float) * solve_count);
3449 memcpy(c0, c, sizeof(float) * solve_count);
3450 memcpy(d0, d, sizeof(float) * solve_count);
3451
3452 memset(is_locked, 0, solve_count);
3453 memset(num_unlocks, 0, solve_count);
3454
3455 bool overshoot, unlocked;
3456
3457 do {
3458 if (!BLI_tridiagonal_solve_cyclic(a, b, c, d, h, solve_count)) {
3459 free_arrays(tmps);
3460 return false;
3461 }
3462
3463 /* first check if any handles overshoot the limits, and lock them */
3464 bool all = false, locked = false;
3465
3466 overshoot = unlocked = false;
3467
3468 do {
3469 for (int i = 0; i < solve_count; i++) {
3470 if (h[i] >= hmin[i] && h[i] <= hmax[i]) {
3471 continue;
3472 }
3473
3474 overshoot = true;
3475
3476 float target = h[i] > hmax[i] ? hmax[i] : hmin[i];
3477
3478 /* heuristically only lock handles that go in the right direction if there are such ones */
3479 if (target != 0.0f || all) {
3480 /* mark item locked */
3481 is_locked[i] = 1;
3482
3483 bezier_lock_unknown(a, b, c, d, i, target);
3484 locked = true;
3485 }
3486 }
3487
3488 all = true;
3489 } while (overshoot && !locked);
3490
3491 /* If no handles overshot and were locked,
3492 * see if it may be a good idea to unlock some handles. */
3493 if (!locked) {
3494 for (int i = 0; i < solve_count; i++) {
3495 /* to definitely avoid infinite loops limit this to 2 times */
3496 if (!is_locked[i] || num_unlocks[i] >= 2) {
3497 continue;
3498 }
3499
3500 /* if the handle wants to move in allowable direction, release it */
3501 float relax = bezier_relax_direction(a0, b0, c0, d0, h, i, solve_count);
3502
3503 if ((relax > 0 && h[i] < hmax[i]) || (relax < 0 && h[i] > hmin[i])) {
3504 bezier_restore_equation(a, b, c, d, a0, b0, c0, d0, i);
3505
3506 is_locked[i] = 0;
3507 num_unlocks[i]++;
3508 unlocked = true;
3509 }
3510 }
3511 }
3512 } while (overshoot || unlocked);
3513
3514 free_arrays(tmps);
3515 return true;
3516}
3517
3518/* Keep ascii art. */
3519/* clang-format off */
3520/*
3521 * This function computes the handles of a series of auto bezier points
3522 * on the basis of 'no acceleration discontinuities' at the points.
3523 * The first and last bezier points are considered 'fixed' (their handles are not touched)
3524 * The result is the smoothest possible trajectory going through intermediate points.
3525 * The difficulty is that the handles depends on their neighbors.
3526 *
3527 * The exact solution is found by solving a tridiagonal matrix equation formed
3528 * by the continuity and boundary conditions. Although theoretically handle position
3529 * is affected by all other points of the curve segment, in practice the influence
3530 * decreases exponentially with distance.
3531 *
3532 * NOTE: this algorithm assumes that the handle horizontal size is always 1/3 of the
3533 * of the interval to the next point. This rule ensures linear interpolation of time.
3534 *
3535 * ^ height (co 1)
3536 * | yN
3537 * | yN-1 |
3538 * | y2 | |
3539 * | y1 | | |
3540 * | y0 | | | |
3541 * | | | | | |
3542 * | | | | | |
3543 * | | | | | |
3544 * |------dx1--------dx2--------- ~ -------dxN-------------------> time (co 0)
3545 *
3546 * Notation:
3547 *
3548 * x[i], y[i] - keyframe coordinates
3549 * h[i] - right handle y offset from y[i]
3550 *
3551 * dx[i] = x[i] - x[i-1]
3552 * dy[i] = y[i] - y[i-1]
3553 *
3554 * Mathematical basis:
3555 *
3556 * 1. Handle lengths on either side of each point are connected by a factor
3557 * ensuring continuity of the first derivative:
3558 *
3559 * l[i] = dx[i+1]/dx[i]
3560 *
3561 * 2. The tridiagonal system is formed by the following equation, which is derived
3562 * by differentiating the bezier curve and specifies second derivative continuity
3563 * at every point:
3564 *
3565 * l[i]^2 * h[i-1] + (2*l[i]+2) * h[i] + 1/l[i+1] * h[i+1] = dy[i]*l[i]^2 + dy[i+1]
3566 *
3567 * 3. If this point is adjacent to a manually set handle with X size not equal to 1/3
3568 * of the horizontal interval, this equation becomes slightly more complex:
3569 *
3570 * l[i]^2 * h[i-1] + (3*(1-R[i-1])*l[i] + 3*(1-L[i+1])) * h[i] + 1/l[i+1] * h[i+1] = dy[i]*l[i]^2 + dy[i+1]
3571 *
3572 * The difference between equations amounts to this, and it's obvious that when R[i-1]
3573 * and L[i+1] are both 1/3, it becomes zero:
3574 *
3575 * ( (1-3*R[i-1])*l[i] + (1-3*L[i+1]) ) * h[i]
3576 *
3577 * 4. The equations for zero acceleration border conditions are basically the above
3578 * equation with parts omitted, so the handle size correction also applies.
3579 *
3580 * 5. The fully cyclic curve case is handled by eliminating one of the end points,
3581 * and instead of border conditions connecting the curve via a set of equations:
3582 *
3583 * l[0] = l[N] = dx[1] / dx[N]
3584 * dy[0] = dy[N]
3585 * Continuity equation (item 2) for i = 0.
3586 * Substitute h[0] for h[N] and h[N-1] for h[-1]
3587 */
3588/* clang-format on */
3589
3591 float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
3592{
3593 a[i] = l[i] * l[i];
3594 b[i] = 2.0f * (l[i] + 1);
3595 c[i] = 1.0f / l[i + 1];
3596 d[i] = dy[i] * l[i] * l[i] + dy[i + 1];
3597}
3598
3600 float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
3601{
3602 a[i] = 0.0f;
3603 b[i] = 2.0f;
3604 c[i] = 1.0f / l[i + 1];
3605 d[i] = dy[i + 1];
3606}
3607
3609 float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
3610{
3611 a[i] = l[i] * l[i];
3612 b[i] = 2.0f * l[i];
3613 c[i] = 0.0f;
3614 d[i] = dy[i] * l[i] * l[i];
3615}
3616
3617/* auto clamp prevents its own point going the wrong way, and adjacent handles overshooting */
3618static void bezier_clamp(
3619 float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot)
3620{
3621 if (dy > 0) {
3622 if (no_overshoot) {
3623 hmax[i] = min_ff(hmax[i], dy);
3624 }
3625 if (no_reverse) {
3626 hmin[i] = 0.0f;
3627 }
3628 }
3629 else if (dy < 0) {
3630 if (no_reverse) {
3631 hmax[i] = 0.0f;
3632 }
3633 if (no_overshoot) {
3634 hmin[i] = max_ff(hmin[i], dy);
3635 }
3636 }
3637 else if (no_reverse || no_overshoot) {
3638 hmax[i] = hmin[i] = 0.0f;
3639 }
3640}
3641
3642/* write changes to a bezier handle */
3644 bool right,
3645 const float newval[3],
3646 bool endpoint)
3647{
3648 float tmp[3];
3649
3650 int idx = right ? 2 : 0;
3651 char hr = right ? bezt->h2 : bezt->h1;
3652 char hm = right ? bezt->h1 : bezt->h2;
3653
3654 /* only assign Auto/Vector handles */
3655 if (!ELEM(hr, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
3656 return;
3657 }
3658
3659 copy_v3_v3(bezt->vec[idx], newval);
3660
3661 /* fix up the Align handle if any */
3662 if (ELEM(hm, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
3663 float hlen = len_v3v3(bezt->vec[1], bezt->vec[2 - idx]);
3664 float h2len = len_v3v3(bezt->vec[1], bezt->vec[idx]);
3665
3666 sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
3667 madd_v3_v3v3fl(bezt->vec[2 - idx], bezt->vec[1], tmp, hlen / h2len);
3668 }
3669 /* at end points of the curve, mirror handle to the other side */
3670 else if (endpoint && ELEM(hm, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
3671 sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
3672 add_v3_v3v3(bezt->vec[2 - idx], bezt->vec[1], tmp);
3673 }
3674}
3675
3676static void bezier_output_handle(BezTriple *bezt, bool right, float dy, bool endpoint)
3677{
3678 float tmp[3];
3679
3680 copy_v3_v3(tmp, bezt->vec[right ? 2 : 0]);
3681
3682 tmp[1] = bezt->vec[1][1] + dy;
3683
3684 bezier_output_handle_inner(bezt, right, tmp, endpoint);
3685}
3686
3687static bool bezier_check_solve_end_handle(BezTriple *bezt, char htype, bool end)
3688{
3689 return (htype == HD_VECT) || (end && ELEM(htype, HD_AUTO, HD_AUTO_ANIM) &&
3691}
3692
3693static float bezier_calc_handle_adj(float hsize[2], float dx)
3694{
3695 /* if handles intersect in x direction, they are scaled to fit */
3696 float fac = dx / (hsize[0] + dx / 3.0f);
3697 if (fac < 1.0f) {
3698 mul_v2_fl(hsize, fac);
3699 }
3700 return 1.0f - 3.0f * hsize[0] / dx;
3701}
3702
3704 BezTriple *bezt, int total, int start, int count, bool cycle)
3705{
3706 float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin;
3707 float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, nullptr};
3708
3709 int solve_count = count;
3710
3711 /* verify index ranges */
3712
3713 if (count < 2) {
3714 return;
3715 }
3716
3717 BLI_assert(start < total - 1 && count <= total);
3718 BLI_assert(start + count <= total || cycle);
3719
3720 bool full_cycle = (start == 0 && count == total && cycle);
3721
3722 BezTriple *bezt_first = &bezt[start];
3723 BezTriple *bezt_last =
3724 &bezt[(start + count > total) ? start + count - total : start + count - 1];
3725
3726 bool solve_first = bezier_check_solve_end_handle(bezt_first, bezt_first->h2, start == 0);
3727 bool solve_last = bezier_check_solve_end_handle(
3728 bezt_last, bezt_last->h1, start + count == total);
3729
3730 if (count == 2 && !full_cycle && solve_first == solve_last) {
3731 return;
3732 }
3733
3734 /* allocate all */
3735
3736 void *tmp_buffer = allocate_arrays(count, arrays, nullptr, "bezier_calc_smooth_tmp");
3737 if (!tmp_buffer) {
3738 return;
3739 }
3740
3741 /* point locations */
3742
3743 dx[0] = dy[0] = NAN_FLT;
3744
3745 for (int i = 1, j = start + 1; i < count; i++, j++) {
3746 dx[i] = bezt[j].vec[1][0] - bezt[j - 1].vec[1][0];
3747 dy[i] = bezt[j].vec[1][1] - bezt[j - 1].vec[1][1];
3748
3749 /* when cyclic, jump from last point to first */
3750 if (cycle && j == total - 1) {
3751 j = 0;
3752 }
3753 }
3754
3755 /* ratio of x intervals */
3756
3757 if (full_cycle) {
3758 dx[0] = dx[count - 1];
3759 dy[0] = dy[count - 1];
3760
3761 l[0] = l[count - 1] = dx[1] / dx[0];
3762 }
3763 else {
3764 l[0] = l[count - 1] = 1.0f;
3765 }
3766
3767 for (int i = 1; i < count - 1; i++) {
3768 l[i] = dx[i + 1] / dx[i];
3769 }
3770
3771 /* compute handle clamp ranges */
3772
3773 bool clamped_prev = false, clamped_cur = ELEM(HD_AUTO_ANIM, bezt_first->h1, bezt_first->h2);
3774
3775 for (int i = 0; i < count; i++) {
3776 hmax[i] = FLT_MAX;
3777 hmin[i] = -FLT_MAX;
3778 }
3779
3780 for (int i = 1, j = start + 1; i < count; i++, j++) {
3781 clamped_prev = clamped_cur;
3782 clamped_cur = ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
3783
3784 if (cycle && j == total - 1) {
3785 j = 0;
3786 clamped_cur = clamped_cur || ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
3787 }
3788
3789 bezier_clamp(hmax, hmin, i - 1, dy[i], clamped_prev, clamped_prev);
3790 bezier_clamp(hmax, hmin, i, dy[i] * l[i], clamped_cur, clamped_cur);
3791 }
3792
3793 /* full cycle merges first and last points into continuous loop */
3794
3795 float first_handle_adj = 0.0f, last_handle_adj = 0.0f;
3796
3797 if (full_cycle) {
3798 /* reduce the number of unknowns by one */
3799 int i = solve_count = count - 1;
3800
3801 hmin[0] = max_ff(hmin[0], hmin[i]);
3802 hmax[0] = min_ff(hmax[0], hmax[i]);
3803
3804 solve_first = solve_last = true;
3805
3806 bezier_eq_continuous(a, b, c, d, dy, l, 0);
3807 }
3808 else {
3809 float tmp[2];
3810
3811 /* boundary condition: fixed handles or zero curvature */
3812 if (!solve_first) {
3813 sub_v2_v2v2(tmp, bezt_first->vec[2], bezt_first->vec[1]);
3814 first_handle_adj = bezier_calc_handle_adj(tmp, dx[1]);
3815
3816 bezier_lock_unknown(a, b, c, d, 0, tmp[1]);
3817 }
3818 else {
3819 bezier_eq_noaccel_right(a, b, c, d, dy, l, 0);
3820 }
3821
3822 if (!solve_last) {
3823 sub_v2_v2v2(tmp, bezt_last->vec[1], bezt_last->vec[0]);
3824 last_handle_adj = bezier_calc_handle_adj(tmp, dx[count - 1]);
3825
3826 bezier_lock_unknown(a, b, c, d, count - 1, tmp[1]);
3827 }
3828 else {
3829 bezier_eq_noaccel_left(a, b, c, d, dy, l, count - 1);
3830 }
3831 }
3832
3833 /* main tridiagonal system of equations */
3834
3835 for (int i = 1; i < count - 1; i++) {
3836 bezier_eq_continuous(a, b, c, d, dy, l, i);
3837 }
3838
3839 /* apply correction for user-defined handles with nonstandard x positions */
3840
3841 if (!full_cycle) {
3842 if (count > 2 || solve_last) {
3843 b[1] += l[1] * first_handle_adj;
3844 }
3845
3846 if (count > 2 || solve_first) {
3847 b[count - 2] += last_handle_adj;
3848 }
3849 }
3850
3851 /* solve and output results */
3852
3853 if (tridiagonal_solve_with_limits(a, b, c, d, h, hmin, hmax, solve_count)) {
3854 if (full_cycle) {
3855 h[count - 1] = h[0];
3856 }
3857
3858 for (int i = 1, j = start + 1; i < count - 1; i++, j++) {
3859 bool end = (j == total - 1);
3860
3861 bezier_output_handle(&bezt[j], false, -h[i] / l[i], end);
3862
3863 if (end) {
3864 j = 0;
3865 }
3866
3867 bezier_output_handle(&bezt[j], true, h[i], end);
3868 }
3869
3870 if (solve_first) {
3871 bezier_output_handle(bezt_first, true, h[0], start == 0);
3872 }
3873
3874 if (solve_last) {
3875 bezier_output_handle(bezt_last, false, -h[count - 1] / l[count - 1], start + count == total);
3876 }
3877 }
3878
3879 /* free all */
3880
3881 free_arrays(tmp_buffer);
3882}
3883
3885{
3886 return BEZT_IS_AUTOH(bezt) && bezt->auto_handle_type == HD_AUTOTYPE_NORMAL;
3887}
3888
3889void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
3890{
3891 /* ignore cyclic extrapolation if end points are locked */
3892 cyclic = cyclic && is_free_auto_point(&bezt[0]) && is_free_auto_point(&bezt[total - 1]);
3893
3894 /* if cyclic, try to find a sequence break point */
3895 int search_base = 0;
3896
3897 if (cyclic) {
3898 for (int i = 1; i < total - 1; i++) {
3899 if (!is_free_auto_point(&bezt[i])) {
3900 search_base = i;
3901 break;
3902 }
3903 }
3904
3905 /* all points of the curve are freely changeable auto handles - solve as full cycle */
3906 if (search_base == 0) {
3907 bezier_handle_calc_smooth_fcurve(bezt, total, 0, total, cyclic);
3908 return;
3909 }
3910 }
3911
3912 /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base.
3913 * In cyclic mode these sub-sequences can span the cycle boundary. */
3914 int start = search_base, count = 1;
3915
3916 for (int i = 1, j = start + 1; i < total; i++, j++) {
3917 /* in cyclic mode: jump from last to first point when necessary */
3918 if (j == total - 1 && cyclic) {
3919 j = 0;
3920 }
3921
3922 /* non auto handle closes the list (we come here at least for the last handle, see above) */
3923 if (!is_free_auto_point(&bezt[j])) {
3924 bezier_handle_calc_smooth_fcurve(bezt, total, start, count + 1, cyclic);
3925 start = j;
3926 count = 1;
3927 }
3928 else {
3929 count++;
3930 }
3931 }
3932
3933 if (count > 1) {
3934 bezier_handle_calc_smooth_fcurve(bezt, total, start, count, cyclic);
3935 }
3936}
3937
3939 BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
3940{
3941 calchandleNurb_intern(bezt, prev, next, (eBezTriple_Flag)SELECT, is_fcurve, false, smoothing);
3942}
3943
3945 BezTriple *prev,
3946 BezTriple *next,
3947 const eBezTriple_Flag__Alias handle_sel_flag,
3948 const bool is_fcurve,
3949 const char smoothing)
3950{
3952 bezt, prev, next, (eBezTriple_Flag)handle_sel_flag, is_fcurve, false, smoothing);
3953}
3954
3955void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
3956{
3958}
3959
3965{
3966 BezTriple *bezt;
3967 int i;
3968
3969 for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
3970 if ((bezt->f1 & SELECT) != (bezt->f3 & SELECT)) {
3971 bezt->f1 ^= SELECT;
3972 bezt->f3 ^= SELECT;
3973 }
3974 }
3975}
3976
3977/* internal use only (weak) */
3984
3986{
3987 if (nu->pntsu > 1) {
3988 BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt);
3990 BKE_nurb_handle_calc(bezt, prev, next, false, 0);
3991 }
3992}
3993
3995{
3996 if (nu->pntsu > 1) {
3997 const char h1_back = bezt->h1, h2_back = bezt->h2;
3998
3999 bezt->h1 = bezt->h2 = HD_AUTO;
4000
4001 /* Override handle types to HD_AUTO and recalculate */
4003
4004 bezt->h1 = h1_back;
4005 bezt->h2 = h2_back;
4006 }
4007}
4008
4009#define SEL_F1 (1 << 0)
4010#define SEL_F2 (1 << 1)
4011#define SEL_F3 (1 << 2)
4012
4014 const eBezTriple_Flag__Alias sel_flag,
4015 const eNurbHandleTest_Mode handle_mode)
4016{
4017 short flag = 0;
4018
4019 switch (handle_mode) {
4021 flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
4022 break;
4023 }
4025 if (bezt->f2 & sel_flag) {
4026 flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
4027 break;
4028 }
4029 [[fallthrough]];
4030 case NURB_HANDLE_TEST_EACH: {
4031 if (bezt->f1 & sel_flag) {
4032 flag |= SEL_F1;
4033 }
4034 if (bezt->f2 & sel_flag) {
4035 flag |= SEL_F2;
4036 }
4037 if (bezt->f3 & sel_flag) {
4038 flag |= SEL_F3;
4039 }
4040 break;
4041 }
4042 }
4043 return flag;
4044}
4045
4047 const eBezTriple_Flag__Alias sel_flag,
4048 const eNurbHandleTest_Mode handle_mode,
4049 const bool use_around_local)
4050{
4051 short flag = BKE_nurb_bezt_handle_test_calc_flag(bezt, sel_flag, handle_mode);
4052 if (use_around_local) {
4053 flag &= ~SEL_F2;
4054 }
4055
4056 /* check for partial selection */
4057 if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) {
4058 if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
4059 bezt->h1 = HD_ALIGN;
4060 }
4061 if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
4062 bezt->h2 = HD_ALIGN;
4063 }
4064
4065 if (bezt->h1 == HD_VECT) {
4066 if (!(flag & SEL_F1) != !(flag & SEL_F2)) {
4067 bezt->h1 = HD_FREE;
4068 }
4069 }
4070 if (bezt->h2 == HD_VECT) {
4071 if (!(flag & SEL_F3) != !(flag & SEL_F2)) {
4072 bezt->h2 = HD_FREE;
4073 }
4074 }
4075 }
4076}
4077
4078#undef SEL_F1
4079#undef SEL_F2
4080#undef SEL_F3
4081
4083 const eNurbHandleTest_Mode handle_mode,
4084 const bool use_around_local)
4085{
4086 BezTriple *bezt;
4087 int a;
4088
4089 if (nu->type != CU_BEZIER) {
4090 return;
4091 }
4092
4093 bezt = nu->bezt;
4094 a = nu->pntsu;
4095 while (a--) {
4096 BKE_nurb_bezt_handle_test(bezt, SELECT, handle_mode, use_around_local);
4097 bezt++;
4098 }
4099
4101}
4102
4104{
4105 /* checks handle coordinates and calculates type */
4106 const float eps = 0.0001f;
4107 const float eps_sq = eps * eps;
4108
4109 if (nu == nullptr || nu->bezt == nullptr) {
4110 return;
4111 }
4112
4113 BezTriple *bezt2 = nu->bezt;
4114 BezTriple *bezt1 = bezt2 + (nu->pntsu - 1);
4115 BezTriple *bezt0 = bezt1 - 1;
4116 int i = nu->pntsu;
4117
4118 while (i--) {
4119 bool align = false, leftsmall = false, rightsmall = false;
4120
4121 /* left handle: */
4122 if (flag == 0 || (bezt1->f1 & flag)) {
4123 bezt1->h1 = HD_FREE;
4124 /* Distance too short: vector-handle. */
4125 if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
4126 bezt1->h1 = HD_VECT;
4127 leftsmall = true;
4128 }
4129 else {
4130 /* Aligned handle? */
4131 if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
4132 align = true;
4133 bezt1->h1 = HD_ALIGN;
4134 }
4135 /* or vector handle? */
4136 if (dist_squared_to_line_v3(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
4137 bezt1->h1 = HD_VECT;
4138 }
4139 }
4140 }
4141 /* right handle: */
4142 if (flag == 0 || (bezt1->f3 & flag)) {
4143 bezt1->h2 = HD_FREE;
4144 /* Distance too short: vector-handle. */
4145 if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
4146 bezt1->h2 = HD_VECT;
4147 rightsmall = true;
4148 }
4149 else {
4150 /* Aligned handle? */
4151 if (align) {
4152 bezt1->h2 = HD_ALIGN;
4153 }
4154
4155 /* or vector handle? */
4156 if (dist_squared_to_line_v3(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
4157 bezt1->h2 = HD_VECT;
4158 }
4159 }
4160 }
4161 if (leftsmall && bezt1->h2 == HD_ALIGN) {
4162 bezt1->h2 = HD_FREE;
4163 }
4164 if (rightsmall && bezt1->h1 == HD_ALIGN) {
4165 bezt1->h1 = HD_FREE;
4166 }
4167
4168 /* undesired combination: */
4169 if (bezt1->h1 == HD_ALIGN && bezt1->h2 == HD_VECT) {
4170 bezt1->h1 = HD_FREE;
4171 }
4172 if (bezt1->h2 == HD_ALIGN && bezt1->h1 == HD_VECT) {
4173 bezt1->h2 = HD_FREE;
4174 }
4175
4176 bezt0 = bezt1;
4177 bezt1 = bezt2;
4178 bezt2++;
4179 }
4180
4182}
4183
4185{
4186 LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4188 }
4189}
4190
4192 eNurbHandleTest_Mode handle_mode,
4193 const char code)
4194{
4195 BezTriple *bezt;
4196 int a;
4197
4198 if (ELEM(code, HD_AUTO, HD_VECT)) {
4199 LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4200 if (nu->type == CU_BEZIER) {
4201 bezt = nu->bezt;
4202 a = nu->pntsu;
4203 while (a--) {
4204 const short flag = BKE_nurb_bezt_handle_test_calc_flag(bezt, SELECT, handle_mode);
4205 if ((flag & (1 << 0)) || (flag & (1 << 2))) {
4206 if (flag & (1 << 0)) {
4207 bezt->h1 = code;
4208 }
4209 if (flag & (1 << 2)) {
4210 bezt->h2 = code;
4211 }
4212 if (bezt->h1 != bezt->h2) {
4213 if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO)) {
4214 bezt->h1 = HD_FREE;
4215 }
4216 if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO)) {
4217 bezt->h2 = HD_FREE;
4218 }
4219 }
4220 }
4221 bezt++;
4222 }
4223
4224 /* like BKE_nurb_handles_calc but moves selected */
4226 }
4227 }
4228 }
4229 else {
4230 char h_new = HD_FREE;
4231
4232 /* There is 1 handle not FREE: FREE it all, else make ALIGNED. */
4233 if (code == 5) {
4234 h_new = HD_ALIGN;
4235 }
4236 else if (code == 6) {
4237 h_new = HD_FREE;
4238 }
4239 else {
4240 /* Toggle */
4241 LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4242 if (nu->type == CU_BEZIER) {
4243 bezt = nu->bezt;
4244 a = nu->pntsu;
4245 while (a--) {
4246 const short flag = BKE_nurb_bezt_handle_test_calc_flag(bezt, SELECT, handle_mode);
4247 if (((flag & (1 << 0)) && bezt->h1 != HD_FREE) ||
4248 ((flag & (1 << 2)) && bezt->h2 != HD_FREE))
4249 {
4250 h_new = HD_AUTO;
4251 break;
4252 }
4253 bezt++;
4254 }
4255 }
4256 }
4257 h_new = (h_new == HD_FREE) ? HD_ALIGN : HD_FREE;
4258 }
4259 LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4260 if (nu->type == CU_BEZIER) {
4261 bezt = nu->bezt;
4262 a = nu->pntsu;
4263 while (a--) {
4264 const short flag = BKE_nurb_bezt_handle_test_calc_flag(bezt, SELECT, handle_mode);
4265 if (flag & (1 << 0)) {
4266 bezt->h1 = h_new;
4267 }
4268 if (flag & (1 << 2)) {
4269 bezt->h2 = h_new;
4270 }
4271
4272 bezt++;
4273 }
4274
4275 /* like BKE_nurb_handles_calc but moves selected */
4277 }
4278 }
4279 }
4280}
4281
4283 const bool calc_length,
4284 const uint8_t flag)
4285{
4286 BezTriple *bezt;
4287 int a;
4288
4289 LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4290 if (nu->type != CU_BEZIER) {
4291 continue;
4292 }
4293
4294 bool changed = false;
4295
4296 for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
4297
4298 const bool h1_select = (bezt->f1 & flag) == flag;
4299 const bool h2_select = (bezt->f3 & flag) == flag;
4300
4301 if (h1_select || h2_select) {
4302
4303 float co1_back[3], co2_back[3];
4304
4305 copy_v3_v3(co1_back, bezt->vec[0]);
4306 copy_v3_v3(co2_back, bezt->vec[2]);
4307
4309
4310 if (h1_select) {
4311 if (!calc_length) {
4312 dist_ensure_v3_v3fl(bezt->vec[0], bezt->vec[1], len_v3v3(co1_back, bezt->vec[1]));
4313 }
4314 }
4315 else {
4316 copy_v3_v3(bezt->vec[0], co1_back);
4317 }
4318
4319 if (h2_select) {
4320 if (!calc_length) {
4321 dist_ensure_v3_v3fl(bezt->vec[2], bezt->vec[1], len_v3v3(co2_back, bezt->vec[1]));
4322 }
4323 }
4324 else {
4325 copy_v3_v3(bezt->vec[2], co2_back);
4326 }
4327
4328 changed = true;
4329 }
4330 }
4331
4332 if (changed) {
4333 /* Recalculate the whole curve */
4335 }
4336 }
4337}
4338
4339void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
4340{
4341 BezTriple *bezt;
4342 BPoint *bp;
4343 int a;
4344
4345 LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4346 if (nu->type == CU_BEZIER) {
4347 a = nu->pntsu;
4348 bezt = nu->bezt;
4349 while (a--) {
4350 if (set) {
4351 bezt->f1 |= flag;
4352 bezt->f2 |= flag;
4353 bezt->f3 |= flag;
4354 }
4355 else {
4356 bezt->f1 &= ~flag;
4357 bezt->f2 &= ~flag;
4358 bezt->f3 &= ~flag;
4359 }
4360 bezt++;
4361 }
4362 }
4363 else {
4364 a = nu->pntsu * nu->pntsv;
4365 bp = nu->bp;
4366 while (a--) {
4367 SET_FLAG_FROM_TEST(bp->f1, set, flag);
4368 bp++;
4369 }
4370 }
4371 }
4372}
4373
4375{
4376 bool changed = false;
4377
4378 LISTBASE_FOREACH (Nurb *, nu, editnurb) {
4379 if (nu->type == CU_BEZIER) {
4380 for (int i = 0; i < nu->pntsu; i++) {
4381 BezTriple *bezt = &nu->bezt[i];
4382 uint8_t old_f1 = bezt->f1, old_f2 = bezt->f2, old_f3 = bezt->f3;
4383
4384 SET_FLAG_FROM_TEST(bezt->f1, bezt->f1 & from_flag, flag);
4385 SET_FLAG_FROM_TEST(bezt->f2, bezt->f2 & from_flag, flag);
4386 SET_FLAG_FROM_TEST(bezt->f3, bezt->f3 & from_flag, flag);
4387
4388 changed |= (old_f1 != bezt->f1) || (old_f2 != bezt->f2) || (old_f3 != bezt->f3);
4389 }
4390 }
4391 else {
4392 for (int i = 0; i < nu->pntsu * nu->pntsv; i++) {
4393 BPoint *bp = &nu->bp[i];
4394 uint8_t old_f1 = bp->f1;
4395
4396 SET_FLAG_FROM_TEST(bp->f1, bp->f1 & from_flag, flag);
4397 changed |= (old_f1 != bp->f1);
4398 }
4399 }
4400 }
4401
4402 return changed;
4403}
4404
4406{
4407 BezTriple *bezt1, *bezt2;
4408 BPoint *bp1, *bp2;
4409 float *fp1, *fp2, *tempf;
4410 int a, b;
4411
4412 if (nu->pntsu == 1 && nu->pntsv == 1) {
4413 return;
4414 }
4415
4416 if (nu->type == CU_BEZIER) {
4417 a = nu->pntsu;
4418 bezt1 = nu->bezt;
4419 bezt2 = bezt1 + (a - 1);
4420 if (a & 1) {
4421 a += 1; /* if odd, also swap middle content */
4422 }
4423 a /= 2;
4424 while (a > 0) {
4425 if (bezt1 != bezt2) {
4426 std::swap(*bezt1, *bezt2);
4427 }
4428
4429 swap_v3_v3(bezt1->vec[0], bezt1->vec[2]);
4430
4431 if (bezt1 != bezt2) {
4432 swap_v3_v3(bezt2->vec[0], bezt2->vec[2]);
4433 }
4434
4435 std::swap(bezt1->h1, bezt1->h2);
4436 std::swap(bezt1->f1, bezt1->f3);
4437
4438 if (bezt1 != bezt2) {
4439 std::swap(bezt2->h1, bezt2->h2);
4440 std::swap(bezt2->f1, bezt2->f3);
4441 bezt1->tilt = -bezt1->tilt;
4442 bezt2->tilt = -bezt2->tilt;
4443 }
4444 else {
4445 bezt1->tilt = -bezt1->tilt;
4446 }
4447 a--;
4448 bezt1++;
4449 bezt2--;
4450 }
4451 }
4452 else if (nu->pntsv == 1) {
4453 a = nu->pntsu;
4454 bp1 = nu->bp;
4455 bp2 = bp1 + (a - 1);
4456 a /= 2;
4457 while (bp1 != bp2 && a > 0) {
4458 std::swap(*bp1, *bp2);
4459 a--;
4460 bp1->tilt = -bp1->tilt;
4461 bp2->tilt = -bp2->tilt;
4462 bp1++;
4463 bp2--;
4464 }
4465 /* If there are odd number of points no need to touch coord of middle one,
4466 * but still need to change its tilt.
4467 */
4468 if (nu->pntsu & 1) {
4469 bp1->tilt = -bp1->tilt;
4470 }
4471 if (nu->type == CU_NURBS) {
4472 /* no knots for too short paths */
4473 if (nu->knotsu) {
4474 /* inverse knots */
4475 a = KNOTSU(nu);
4476 fp1 = nu->knotsu;
4477 fp2 = fp1 + (a - 1);
4478 a /= 2;
4479 while (fp1 != fp2 && a > 0) {
4480 std::swap(*fp1, *fp2);
4481 a--;
4482 fp1++;
4483 fp2--;
4484 }
4485 /* and make in increasing order again */
4486 a = KNOTSU(nu);
4487 fp1 = nu->knotsu;
4488 fp2 = tempf = (float *)MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
4489 a--;
4490 fp2[a] = fp1[a];
4491 while (a--) {
4492 fp2[0] = fabsf(fp1[1] - fp1[0]);
4493 fp1++;
4494 fp2++;
4495 }
4496
4497 a = KNOTSU(nu) - 1;
4498 fp1 = nu->knotsu;
4499 fp2 = tempf;
4500 fp1[0] = 0.0;
4501 fp1++;
4502 while (a--) {
4503 fp1[0] = fp1[-1] + fp2[0];
4504 fp1++;
4505 fp2++;
4506 }
4507 MEM_freeN(tempf);
4508 }
4509 }
4510 }
4511 else {
4512 for (b = 0; b < nu->pntsv; b++) {
4513 bp1 = nu->bp + b * nu->pntsu;
4514 a = nu->pntsu;
4515 bp2 = bp1 + (a - 1);
4516 a /= 2;
4517
4518 while (bp1 != bp2 && a > 0) {
4519 std::swap(*bp1, *bp2);
4520 a--;
4521 bp1++;
4522 bp2--;
4523 }
4524 }
4525 }
4526}
4527
4528void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float (*vert_coords)[3], int vert_len)
4529{
4530 float *co = vert_coords[0];
4531 LISTBASE_FOREACH (const Nurb *, nu, lb) {
4532 if (nu->type == CU_BEZIER) {
4533 const BezTriple *bezt = nu->bezt;
4534 for (int i = 0; i < nu->pntsu; i++, bezt++) {
4535 copy_v3_v3(co, bezt->vec[0]);
4536 co += 3;
4537 copy_v3_v3(co, bezt->vec[1]);
4538 co += 3;
4539 copy_v3_v3(co, bezt->vec[2]);
4540 co += 3;
4541 }
4542 }
4543 else {
4544 const BPoint *bp = nu->bp;
4545 for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4546 copy_v3_v3(co, bp->vec);
4547 co += 3;
4548 }
4549 }
4550 }
4551 BLI_assert(co == vert_coords[vert_len]);
4552 UNUSED_VARS_NDEBUG(vert_len);
4553}
4554
4555float (*BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
4556{
4557 const int vert_len = BKE_nurbList_verts_count(lb);
4558 float(*vert_coords)[3] = (float(*)[3])MEM_malloc_arrayN(
4559 vert_len, sizeof(*vert_coords), __func__);
4560 BKE_curve_nurbs_vert_coords_get(lb, vert_coords, vert_len);
4561 *r_vert_len = vert_len;
4562 return vert_coords;
4563}
4564
4566 const float (*vert_coords)[3],
4567 const float mat[4][4],
4568 const bool constrain_2d)
4569{
4570 const float *co = vert_coords[0];
4571
4572 LISTBASE_FOREACH (Nurb *, nu, lb) {
4573 if (nu->type == CU_BEZIER) {
4574 BezTriple *bezt = nu->bezt;
4575
4576 for (int i = 0; i < nu->pntsu; i++, bezt++) {
4577 mul_v3_m4v3(bezt->vec[0], mat, co);
4578 co += 3;
4579 mul_v3_m4v3(bezt->vec[1], mat, co);
4580 co += 3;
4581 mul_v3_m4v3(bezt->vec[2], mat, co);
4582 co += 3;
4583 }
4584 }
4585 else {
4586 BPoint *bp = nu->bp;
4587
4588 for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4589 mul_v3_m4v3(bp->vec, mat, co);
4590 co += 3;
4591 }
4592 }
4593
4594 if (constrain_2d) {
4596 }
4597
4599 }
4600}
4601
4603 const float (*vert_coords)[3],
4604 const bool constrain_2d)
4605{
4606 const float *co = vert_coords[0];
4607
4608 LISTBASE_FOREACH (Nurb *, nu, lb) {
4609 if (nu->type == CU_BEZIER) {
4610 BezTriple *bezt = nu->bezt;
4611
4612 for (int i = 0; i < nu->pntsu; i++, bezt++) {
4613 copy_v3_v3(bezt->vec[0], co);
4614 co += 3;
4615 copy_v3_v3(bezt->vec[1], co);
4616 co += 3;
4617 copy_v3_v3(bezt->vec[2], co);
4618 co += 3;
4619 }
4620 }
4621 else {
4622 BPoint *bp = nu->bp;
4623
4624 for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4625 copy_v3_v3(bp->vec, co);
4626 co += 3;
4627 }
4628 }
4629
4630 if (constrain_2d) {
4632 }
4633
4635 }
4636}
4637
4638float (*BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
4639{
4640 int vert_len = BKE_nurbList_verts_count(lb);
4641 float(*cos)[3] = (float(*)[3])MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
4642
4643 float *co = cos[0];
4644 LISTBASE_FOREACH (const Nurb *, nu, lb) {
4645 if (nu->type == CU_BEZIER) {
4646 const BezTriple *bezt = nu->bezt;
4647
4648 for (int i = 0; i < nu->pntsu; i++, bezt++) {
4649 copy_v3_v3(co, &key[0]);
4650 co += 3;
4651 copy_v3_v3(co, &key[3]);
4652 co += 3;
4653 copy_v3_v3(co, &key[6]);
4654 co += 3;
4656 }
4657 }
4658 else {
4659 const BPoint *bp = nu->bp;
4660
4661 for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4662 copy_v3_v3(co, key);
4663 co += 3;
4665 }
4666 }
4667 }
4668 *r_vert_len = vert_len;
4669 return cos;
4670}
4671
4673{
4674 LISTBASE_FOREACH (Nurb *, nu, lb) {
4675 if (nu->type == CU_BEZIER) {
4676 BezTriple *bezt = nu->bezt;
4677
4678 for (int i = 0; i < nu->pntsu; i++, bezt++) {
4679 bezt->tilt = key[9];
4680 bezt->radius = key[10];
4682 }
4683 }
4684 else {
4685 BPoint *bp = nu->bp;
4686
4687 for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
4688 bp->tilt = key[3];
4689 bp->radius = key[4];
4691 }
4692 }
4693 }
4694}
4695
4697 const short order,
4698 const short flag,
4699 const short type,
4700 const bool is_surf,
4701 int *r_points_needed)
4702{
4703 if (pnts <= 1) {
4705 }
4706 if (type == CU_NURBS) {
4707 if (pnts < order) {
4709 }
4710 if (flag & CU_NURB_BEZIER) {
4711 int points_needed = 0;
4712 if (flag & CU_NURB_CYCLIC) {
4713 const int remainder = pnts % (order - 1);
4714 points_needed = remainder > 0 ? order - 1 - remainder : 0;
4715 }
4716 else if (((flag & CU_NURB_ENDPOINT) == 0) && pnts <= order) {
4717 points_needed = order + 1 - pnts;
4718 }
4719 if (points_needed) {
4720 *r_points_needed = points_needed;
4723 }
4724 }
4725 }
4727}
4728
4729bool BKE_nurb_valid_message(const int pnts,
4730 const short order,
4731 const short flag,
4732 const short type,
4733 const bool is_surf,
4734 const int dir,
4735 char *message_dst,
4736 const size_t maxncpy)
4737{
4738 int points_needed;
4740 pnts, order, flag, type, is_surf, &points_needed);
4741
4742 switch (status) {
4744 message_dst[0] = 0;
4745 return false;
4747 if (dir == 1) {
4748 /* Exception made for curves as their pntsv == 1. */
4749 message_dst[0] = 0;
4750 return false;
4751 }
4752 BLI_strncpy(message_dst, RPT_("At least two points required"), maxncpy);
4753 break;
4755 BLI_strncpy(message_dst, RPT_("Must have more control points than Order"), maxncpy);
4756 break;
4758 BLI_snprintf(message_dst,
4759 maxncpy,
4760 RPT_("%d more %s row(s) needed for Bézier"),
4761 points_needed,
4762 dir == 0 ? "U" : "V");
4763 break;
4766 message_dst, maxncpy, RPT_("%d more point(s) needed for Bézier"), points_needed);
4767 break;
4768 }
4769
4770 return true;
4771}
4772
4774{
4775 int points_needed;
4778 nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, &points_needed);
4779}
4780
4782{
4783 int points_needed;
4786 nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, &points_needed);
4787}
4788
4790{
4791 if (!BKE_nurb_check_valid_u(nu)) {
4792 return false;
4793 }
4794 if ((nu->pntsv > 1) && !BKE_nurb_check_valid_v(nu)) {
4795 return false;
4796 }
4797
4798 return true;
4799}
4800
4802{
4803 bool changed = false;
4804 if (nu->pntsu < nu->orderu) {
4805 nu->orderu = max_ii(2, nu->pntsu);
4806 changed = true;
4807 }
4808 return changed;
4809}
4810
4812{
4813 bool changed = false;
4814 if (nu->pntsv < nu->orderv) {
4815 nu->orderv = max_ii(2, nu->pntsv);
4816 changed = true;
4817 }
4818 return changed;
4819}
4820
4822 const short type,
4823 const bool use_handles,
4824 const char **r_err_msg)
4825{
4826 BezTriple *bezt;
4827 BPoint *bp;
4828 int a, c, nr;
4829
4830 if (nu->type == CU_POLY) {
4831 if (type == CU_BEZIER) { /* To Bezier with vector-handles. */
4832 nr = nu->pntsu;
4833 bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
4834 nu->bezt = bezt;
4835 a = nr;
4836 bp = nu->bp;
4837 while (a--) {
4838 copy_v3_v3(bezt->vec[1], bp->vec);
4839 bezt->f1 = bezt->f2 = bezt->f3 = bp->f1;
4840 bezt->h1 = bezt->h2 = HD_VECT;
4841 bezt->weight = bp->weight;
4842 bezt->radius = bp->radius;
4843 bp++;
4844 bezt++;
4845 }
4846 MEM_freeN(nu->bp);
4847 nu->bp = nullptr;
4848 nu->pntsu = nr;
4849 nu->pntsv = 0;
4850 nu->type = CU_BEZIER;
4852 }
4853 else if (type == CU_NURBS) {
4854 nu->type = CU_NURBS;
4855 nu->orderu = 4;
4856 nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
4858 a = nu->pntsu * nu->pntsv;
4859 bp = nu->bp;
4860 while (a--) {
4861 bp->vec[3] = 1.0;
4862 bp++;
4863 }
4864 }
4865 }
4866 else if (nu->type == CU_BEZIER) { /* Bezier */
4867 if (ELEM(type, CU_POLY, CU_NURBS)) {
4868 nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
4869 nu->bp = (BPoint *)MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
4870 a = nu->pntsu;
4871 bezt = nu->bezt;
4872 bp = nu->bp;
4873 while (a--) {
4874 if ((type == CU_POLY && bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) ||
4875 (use_handles == false))
4876 {
4877 /* vector handle becomes one poly vertex */
4878 copy_v3_v3(bp->vec, bezt->vec[1]);
4879 bp->vec[3] = 1.0;
4880 bp->f1 = bezt->f2;
4881 if (use_handles) {
4882 nr -= 2;
4883 }
4884 bp->radius = bezt->radius;
4885 bp->weight = bezt->weight;
4886 bp++;
4887 }
4888 else {
4889 const uint8_t *f = &bezt->f1;
4890 for (c = 0; c < 3; c++, f++) {
4891 copy_v3_v3(bp->vec, bezt->vec[c]);
4892 bp->vec[3] = 1.0;
4893 bp->f1 = *f;
4894 bp->radius = bezt->radius;
4895 bp->weight = bezt->weight;
4896 bp++;
4897 }
4898 }
4899 bezt++;
4900 }
4901 MEM_freeN(nu->bezt);
4902 nu->bezt = nullptr;
4903 nu->pntsu = nr;
4904 nu->pntsv = 1;
4905 nu->orderu = 4;
4906 nu->orderv = 1;
4907 nu->type = type;
4908
4909 if (type == CU_NURBS) {
4910 nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
4911 nu->flagu |= CU_NURB_BEZIER;
4913 }
4914 }
4915 }
4916 else if (nu->type == CU_NURBS) {
4917 if (type == CU_POLY) {
4918 nu->type = CU_POLY;
4919 if (nu->knotsu) {
4920 MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
4921 }
4922 nu->knotsu = nullptr;
4923 MEM_SAFE_FREE(nu->knotsv);
4924 }
4925 else if (type == CU_BEZIER) { /* to Bezier */
4926 nr = nu->pntsu / 3;
4927
4928 if (nr < 2) {
4929 if (r_err_msg != nullptr) {
4930 *r_err_msg = "At least 6 points required for conversion";
4931 }
4932 return false; /* conversion impossible */
4933 }
4934
4935 bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
4936 nu->bezt = bezt;
4937 a = nr;
4938 bp = nu->bp;
4939 while (a--) {
4940 copy_v3_v3(bezt->vec[0], bp->vec);
4941 bezt->f1 = bp->f1;
4942 bp++;
4943 copy_v3_v3(bezt->vec[1], bp->vec);
4944 bezt->f2 = bp->f1;
4945 bp++;
4946 copy_v3_v3(bezt->vec[2], bp->vec);
4947 bezt->f3 = bp->f1;
4948 bezt->radius = bp->radius;
4949 bezt->weight = bp->weight;
4950 bp++;
4951 bezt++;
4952 }
4953 MEM_freeN(nu->bp);
4954 nu->bp = nullptr;
4955 MEM_freeN(nu->knotsu);
4956 nu->knotsu = nullptr;
4957 nu->pntsu = nr;
4958 nu->type = CU_BEZIER;
4959 }
4960 }
4961
4962 return true;
4963}
4964
4966{
4967 if (cu->editnurb) {
4968 return BKE_curve_editNurbs_get(cu);
4969 }
4970
4971 return &cu->nurb;
4972}
4973
4975{
4976 if (cu->editnurb) {
4978 }
4979
4980 return &cu->nurb;
4981}
4982
4984{
4985 if (nu == nullptr) {
4986 cu->actnu = CU_ACT_NONE;
4987 }
4988 else {
4989 BLI_assert(!nu->hide);
4990 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
4991 cu->actnu = BLI_findindex(nurbs, nu);
4992 }
4993}
4994
4996{
4997 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
4998 return (Nurb *)BLI_findlink(nurbs, cu->actnu);
4999}
5000
5002{
5003 Nurb *nu = nullptr;
5004 void *vert = nullptr;
5005
5006 BKE_curve_nurb_vert_active_get(cu, &nu, &vert);
5007 return vert;
5008}
5009
5010int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
5011{
5012 if (nu->type == CU_BEZIER) {
5013 BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
5014 return (BezTriple *)vert - nu->bezt;
5015 }
5016
5017 BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
5018 return (BPoint *)vert - nu->bp;
5019}
5020
5021void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
5022{
5023 if (nu) {
5025
5026 if (vert) {
5027 cu->actvert = BKE_curve_nurb_vert_index_get(nu, vert);
5028 }
5029 else {
5030 cu->actvert = CU_ACT_NONE;
5031 }
5032 }
5033 else {
5034 cu->actnu = cu->actvert = CU_ACT_NONE;
5035 }
5036}
5037
5038bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
5039{
5040 Nurb *nu = nullptr;
5041 void *vert = nullptr;
5042
5043 if (cu->actvert != CU_ACT_NONE) {
5044 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
5045 nu = (Nurb *)BLI_findlink(nurbs, cu->actnu);
5046
5047 if (nu) {
5048 if (nu->type == CU_BEZIER) {
5049 BLI_assert(nu->pntsu > cu->actvert);
5050 vert = &nu->bezt[cu->actvert];
5051 }
5052 else {
5053 BLI_assert((nu->pntsu * nu->pntsv) > cu->actvert);
5054 vert = &nu->bp[cu->actvert];
5055 }
5056 }
5057 }
5058
5059 *r_nu = nu;
5060 *r_vert = vert;
5061
5062 return (*r_vert != nullptr);
5063}
5064
5066{
5067 Nurb *nu;
5068 void *vert;
5069
5070 if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
5071 if (nu->type == CU_BEZIER) {
5072 BezTriple *bezt = (BezTriple *)vert;
5073 if (BEZT_ISSEL_ANY(bezt) == 0) {
5074 cu->actvert = CU_ACT_NONE;
5075 }
5076 }
5077 else {
5078 BPoint *bp = (BPoint *)vert;
5079 if ((bp->f1 & SELECT) == 0) {
5080 cu->actvert = CU_ACT_NONE;
5081 }
5082 }
5083
5084 if (nu->hide) {
5085 cu->actnu = CU_ACT_NONE;
5086 }
5087 }
5088}
5089
5090static std::optional<blender::Bounds<blender::float3>> calc_nurblist_bounds(const ListBase *nurbs,
5091 const bool use_radius)
5092{
5093 if (BLI_listbase_is_empty(nurbs)) {
5094 return std::nullopt;
5095 }
5096 float3 min(std::numeric_limits<float>::max());
5097 float3 max(std::numeric_limits<float>::lowest());
5098 LISTBASE_FOREACH (const Nurb *, nu, nurbs) {
5099 calc_nurb_minmax(nu, use_radius, min, max);
5100 }
5102}
5103
5104std::optional<blender::Bounds<blender::float3>> BKE_curve_minmax(const Curve *cu, bool use_radius)
5105{
5106 const ListBase *nurb_lb = BKE_curve_nurbs_get_for_read(cu);
5107 const bool is_font = BLI_listbase_is_empty(nurb_lb) && (cu->len != 0);
5108 /* For font curves we generate temp list of splines.
5109 *
5110 * This is likely to be fine, this function is not supposed to be called
5111 * often, and it's the only way to get meaningful bounds for fonts.
5112 */
5113 if (is_font) {
5114 ListBase temp_nurb_lb{};
5115 BKE_vfont_to_curve_ex(nullptr,
5116 const_cast<Curve *>(cu),
5117 FO_EDIT,
5118 &temp_nurb_lb,
5119 nullptr,
5120 nullptr,
5121 nullptr,
5122 nullptr);
5123 BLI_SCOPED_DEFER([&]() { BKE_nurbList_free(&temp_nurb_lb); });
5124 return calc_nurblist_bounds(&temp_nurb_lb, false);
5125 }
5126
5127 return calc_nurblist_bounds(nurb_lb, use_radius);
5128}
5129
5130bool BKE_curve_center_median(Curve *cu, float cent[3])
5131{
5132 ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
5133 int total = 0;
5134
5135 zero_v3(cent);
5136
5137 LISTBASE_FOREACH (Nurb *, nu, nurb_lb) {
5138 int i;
5139
5140 if (nu->type == CU_BEZIER) {
5141 BezTriple *bezt;
5142 i = nu->pntsu;
5143 total += i * 3;
5144 for (bezt = nu->bezt; i--; bezt++) {
5145 add_v3_v3(cent, bezt->vec[0]);
5146 add_v3_v3(cent, bezt->vec[1]);
5147 add_v3_v3(cent, bezt->vec[2]);
5148 }
5149 }
5150 else {
5151 BPoint *bp;
5152 i = nu->pntsu * nu->pntsv;
5153 total += i;
5154 for (bp = nu->bp; i--; bp++) {
5155 add_v3_v3(cent, bp->vec);
5156 }
5157 }
5158 }
5159
5160 if (total) {
5161 mul_v3_fl(cent, 1.0f / float(total));
5162 }
5163
5164 return (total != 0);
5165}
5166
5168 const float mat[4][4],
5169 const bool do_keys,
5170 const bool do_props,
5171 const float unit_scale)
5172{
5173 BPoint *bp;
5174 BezTriple *bezt;
5175 int i;
5176
5177 const bool is_uniform_scaled = is_uniform_scaled_m4(mat);
5178
5179 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5180 if (nu->type == CU_BEZIER) {
5181 i = nu->pntsu;
5182 for (bezt = nu->bezt; i--; bezt++) {
5183 mul_m4_v3(mat, bezt->vec[0]);
5184 mul_m4_v3(mat, bezt->vec[1]);
5185 mul_m4_v3(mat, bezt->vec[2]);
5186 if (do_props) {
5187 bezt->radius *= unit_scale;
5188 }
5189 if (!is_uniform_scaled) {
5190 if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
5191 bezt->h1 = bezt->h2 = HD_ALIGN;
5192 }
5193 }
5194 }
5196 }
5197 else {
5198 i = nu->pntsu * nu->pntsv;
5199 for (bp = nu->bp; i--; bp++) {
5200 mul_m4_v3(mat, bp->vec);
5201 if (do_props) {
5202 bp->radius *= unit_scale;
5203 }
5204 }
5205 }
5206 }
5207
5208 if (do_keys && cu->key) {
5209 LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
5210 float *fp = (float *)kb->data;
5211 int n = kb->totelem;
5212
5213 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5214 if (nu->type == CU_BEZIER) {
5215 for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
5216 mul_m4_v3(mat, &fp[0]);
5217 mul_m4_v3(mat, &fp[3]);
5218 mul_m4_v3(mat, &fp[6]);
5219 if (do_props) {
5220 fp[10] *= unit_scale; /* radius */
5221 }
5223 }
5224 }
5225 else {
5226 for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
5227 mul_m4_v3(mat, fp);
5228 if (do_props) {
5229 fp[4] *= unit_scale; /* radius */
5230 }
5232 }
5233 }
5234 }
5235 }
5236 }
5237}
5238
5239void BKE_curve_transform(Curve *cu, const float mat[4][4], const bool do_keys, const bool do_props)
5240{
5241 float unit_scale = mat4_to_scale(mat);
5242 BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale);
5243}
5244
5245void BKE_curve_translate(Curve *cu, const float offset[3], const bool do_keys)
5246{
5247 ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
5248
5249 LISTBASE_FOREACH (Nurb *, nu, nurb_lb) {
5250 if (nu->type == CU_BEZIER) {
5251 int i = nu->pntsu;
5252 for (BezTriple *bezt = nu->bezt; i--; bezt++) {
5253 add_v3_v3(bezt->vec[0], offset);
5254 add_v3_v3(bezt->vec[1], offset);
5255 add_v3_v3(bezt->vec[2], offset);
5256 }
5257 }
5258 else {
5259 int i = nu->pntsu * nu->pntsv;
5260 for (BPoint *bp = nu->bp; i--; bp++) {
5261 add_v3_v3(bp->vec, offset);
5262 }
5263 }
5264 }
5265
5266 if (do_keys && cu->key) {
5267 LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
5268 float *fp = (float *)kb->data;
5269 int n = kb->totelem;
5270
5271 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5272 if (nu->type == CU_BEZIER) {
5273 for (int i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
5274 add_v3_v3(&fp[0], offset);
5275 add_v3_v3(&fp[3], offset);
5276 add_v3_v3(&fp[6], offset);
5278 }
5279 }
5280 else {
5281 for (int i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
5282 add_v3_v3(fp, offset);
5284 }
5285 }
5286 }
5287 }
5288 }
5289}
5290
5292{
5293 const int curvetype = BKE_curve_type_get(cu);
5294
5295 if (curvetype == OB_FONT) {
5296 CharInfo *info = cu->strinfo;
5297 for (int i = cu->len_char32 - 1; i >= 0; i--, info++) {
5298 if (info->mat_nr && info->mat_nr >= index) {
5299 info->mat_nr--;
5300 }
5301 }
5302 }
5303 else {
5304 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5305 if (nu->mat_nr && nu->mat_nr >= index) {
5306 nu->mat_nr--;
5307 }
5308 }
5309 }
5310}
5311
5312bool BKE_curve_material_index_used(const Curve *cu, int index)
5313{
5314 const int curvetype = BKE_curve_type_get(cu);
5315
5316 if (curvetype == OB_FONT) {
5317 const CharInfo *info = cu->strinfo;
5318 for (int i = cu->len_char32 - 1; i >= 0; i--, info++) {
5319 if (info->mat_nr == index) {
5320 return true;
5321 }
5322 }
5323 }
5324 else {
5325 LISTBASE_FOREACH (const Nurb *, nu, &cu->nurb) {
5326 if (nu->mat_nr == index) {
5327 return true;
5328 }
5329 }
5330 }
5331
5332 return false;
5333}
5334
5336{
5337 const int curvetype = BKE_curve_type_get(cu);
5338
5339 if (curvetype == OB_FONT) {
5340 CharInfo *info = cu->strinfo;
5341 for (int i = cu->len_char32 - 1; i >= 0; i--, info++) {
5342 info->mat_nr = 0;
5343 }
5344 }
5345 else {
5346 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5347 nu->mat_nr = 0;
5348 }
5349 }
5350}
5351
5353{
5354 const int curvetype = BKE_curve_type_get(cu);
5355 bool is_valid = true;
5356
5357 if (curvetype == OB_FONT) {
5358 CharInfo *info = cu->strinfo;
5359 const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */
5360 int i;
5361 for (i = cu->len_char32 - 1; i >= 0; i--, info++) {
5362 if (info->mat_nr > max_idx) {
5363 info->mat_nr = 0;
5364 is_valid = false;
5365 }
5366 }
5367 }
5368 else {
5369 const int max_idx = max_ii(0, cu->totcol - 1);
5370 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5371 if (nu->mat_nr > max_idx) {
5372 nu->mat_nr = 0;
5373 is_valid = false;
5374 }
5375 }
5376 }
5377
5378 if (!is_valid) {
5380 return true;
5381 }
5382 return false;
5383}
5384
5385void BKE_curve_material_remap(Curve *cu, const uint *remap, uint remap_len)
5386{
5387 const int curvetype = BKE_curve_type_get(cu);
5388 const short remap_len_short = short(remap_len);
5389
5390#define MAT_NR_REMAP(n) \
5391 if (n < remap_len_short) { \
5392 BLI_assert(n >= 0 && remap[n] < remap_len_short); \
5393 n = remap[n]; \
5394 } \
5395 ((void)0)
5396
5397 if (curvetype == OB_FONT) {
5398 CharInfo *strinfo;
5399 int charinfo_len, i;
5400
5401 if (cu->editfont) {
5402 EditFont *ef = cu->editfont;
5403 strinfo = ef->textbufinfo;
5404 charinfo_len = ef->len;
5405 }
5406 else {
5407 strinfo = cu->strinfo;
5408 charinfo_len = cu->len_char32;
5409 }
5410
5411 for (i = 0; i <= charinfo_len; i++) {
5412 MAT_NR_REMAP(strinfo[i].mat_nr);
5413 }
5414 }
5415 else {
5416 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
5417
5418 if (nurbs) {
5419 LISTBASE_FOREACH (Nurb *, nu, nurbs) {
5420 MAT_NR_REMAP(nu->mat_nr);
5421 }
5422 }
5423 }
5424
5425#undef MAT_NR_REMAP
5426}
5427
5428void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth)
5429{
5430 if (use_smooth) {
5431 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5432 nu->flag |= CU_SMOOTH;
5433 }
5434 }
5435 else {
5436 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
5437 nu->flag &= ~CU_SMOOTH;
5438 }
5439 }
5440}
5441
5442void BKE_curve_rect_from_textbox(const Curve *cu, const TextBox *tb, rctf *r_rect)
5443{
5444 r_rect->xmin = cu->xof + tb->x;
5445 r_rect->ymax = cu->yof + tb->y + cu->fsize;
5446
5447 r_rect->xmax = r_rect->xmin + tb->w;
5448 r_rect->ymin = r_rect->ymax - tb->h;
5449}
5450
5451void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
5452{
5453 float h1[2], h2[2], len1, len2, len, fac;
5454
5455 /* Calculate handle deltas. */
5456 h1[0] = v1[0] - v2[0];
5457 h1[1] = v1[1] - v2[1];
5458
5459 h2[0] = v4[0] - v3[0];
5460 h2[1] = v4[1] - v3[1];
5461
5462 /* Calculate distances:
5463 * - len = span of time between keyframes
5464 * - len1 = length of handle of start key
5465 * - len2 = length of handle of end key
5466 */
5467 len = v4[0] - v1[0];
5468 len1 = fabsf(h1[0]);
5469 len2 = fabsf(h2[0]);
5470
5471 /* If the handles have no length, no need to do any corrections. */
5472 if ((len1 + len2) == 0.0f) {
5473 return;
5474 }
5475
5476 /* the two handles cross over each other, so force them
5477 * apart using the proportion they overlap
5478 */
5479 if ((len1 + len2) > len) {
5480 fac = len / (len1 + len2);
5481
5482 v2[0] = (v1[0] - fac * h1[0]);
5483 v2[1] = (v1[1] - fac * h1[1]);
5484
5485 v3[0] = (v4[0] - fac * h2[0]);
5486 v3[1] = (v4[1] - fac * h2[1]);
5487 }
5488}
5489
5490/* **** Depsgraph evaluation **** */
5491
5493{
5494 DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve);
5496 if (DEG_is_active(depsgraph)) {
5497 Curve *curve_orig = (Curve *)DEG_get_original_id(&curve->id);
5500 copy_v3_v3(curve_orig->texspace_location, curve->texspace_location);
5501 copy_v3_v3(curve_orig->texspace_size, curve->texspace_size);
5502 }
5503 }
5504}
5505
5506/* Draw Engine */
5507
5508void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = nullptr;
5510
5512{
5513 if (cu->batch_cache) {
5515 }
5516}
5518{
5519 if (cu->batch_cache) {
5521 }
5522}
eNurbHandleTest_Mode
Definition BKE_curve.hh:56
@ NURB_HANDLE_TEST_EACH
Definition BKE_curve.hh:58
@ NURB_HANDLE_TEST_KNOT_OR_EACH
Definition BKE_curve.hh:63
@ NURB_HANDLE_TEST_KNOT_ONLY
Definition BKE_curve.hh:68
#define KNOTSU(nu)
Definition BKE_curve.hh:71
#define CU_DO_RADIUS(cu, nu)
Definition BKE_curve.hh:80
int eBezTriple_Flag__Alias
Definition BKE_curve.hh:34
#define CU_IS_2D(cu)
Definition BKE_curve.hh:86
void(* BKE_curve_batch_cache_free_cb)(Curve *cu)
Definition curve.cc:5509
#define KNOTSV(nu)
Definition BKE_curve.hh:73
bool BKE_nurb_check_valid_v(const Nurb *nu)
Definition curve.cc:4781
void(* BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode)
Definition curve.cc:5508
#define SEGMENTSU(nu)
Definition BKE_curve.hh:77
struct CurveProfile * BKE_curveprofile_copy(const struct CurveProfile *profile)
void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile)
void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile)
void BKE_curveprofile_free(struct CurveProfile *profile)
IDTypeInfo IDType_ID_CU_LEGACY
Definition curve.cc:265
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:39
void key_curve_position_weights(float t, float data[4], int type)
Definition key.cc:339
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1415
struct ID * BKE_id_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, const ID *id, const ID *new_owner_id, ID **new_id_p, int flag)
Definition lib_id.cc:656
@ LIB_ID_COPY_SHAPEKEY
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
@ IDWALK_DO_DEPRECATED_POINTERS
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
int BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:120
#define BKE_LIB_FOREACHID_PROCESS_ID_NOCHECK(data_, id_, cb_flag_)
@ FO_EDIT
Definition BKE_vfont.hh:69
VFont * BKE_vfont_builtin_get()
Definition vfont.cc:422
bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, eEditFontMode mode, ListBase *r_nubase, const char32_t **r_text, int *r_text_len, bool *r_text_free, CharTrans **r_chartransdata)
Definition vfont.cc:1984
#define BLI_assert(a)
Definition BLI_assert.h:50
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:787
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
#define M_PI_2
MINLINE int mod_i(int i, int n)
#define NAN_FLT
MINLINE float safe_acosf(float a)
float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:531
float mat4_to_scale(const float mat[4][4])
bool is_uniform_scaled_m4(const float m[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t)
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3])
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void vec_to_quat(float q[4], const float vec[3], short axis, short upflag)
float normalize_qt(float q[4])
#define DEG2RADF(_deg)
void mul_qt_v3(const float q[4], float r[3])
void unit_qt(float q[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void copy_qt_qt(float q[4], const float a[4])
bool BLI_tridiagonal_solve_cyclic(const float *a, const float *b, const float *c, const float *d, float *r_x, int count)
Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
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])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], float dist)
MINLINE float normalize_v3(float n[3])
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
#define BLI_SCOPED_DEFER(function_to_defer)
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define ARRAY_HAS_ITEM(arr_item, arr_start, arr_len)
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNLIKELY(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define POINTER_OFFSET(v, ofs)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition readfile.cc:4967
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
void BLO_read_pointer_array(BlendDataReader *reader, int array_size, void **ptr_p)
Definition readfile.cc:5052
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
#define RPT_(msgid)
#define BLT_I18NCONTEXT_ID_CURVE_LEGACY
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:318
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
ID * DEG_get_original_id(ID *id)
#define FILTER_ID_OB
Definition DNA_ID.h:1181
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define FILTER_ID_MA
Definition DNA_ID.h:1175
#define FILTER_ID_CU_LEGACY
Definition DNA_ID.h:1168
#define FILTER_ID_VF
Definition DNA_ID.h:1189
@ INDEX_ID_CU_LEGACY
Definition DNA_ID.h:1294
#define FILTER_ID_KE
Definition DNA_ID.h:1199
@ ID_CU_LEGACY
@ FCURVE_SMOOTH_NONE
@ CU_TEXSPACE_FLAG_AUTO
@ CU_TEXSPACE_FLAG_AUTO_EVALUATED
@ CU_BEVFAC_MAP_SPLINE
@ CU_BEVFAC_MAP_SEGMENT
#define MAXTEXTBOX
#define BEZT_IS_AUTOH(bezt)
@ CU_BEZIER
@ CU_POLY
@ CU_NURBS
@ CU_3D
@ CU_FRONT
@ CU_BACK
#define BEZT_ISSEL_ANY(bezt)
#define CU_ACT_NONE
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_FREE
@ HD_AUTO
@ HD_ALIGN_DOUBLESIDE
@ HD_ALIGN
#define KEY_CU_EASE
@ HD_AUTOTYPE_NORMAL
@ HD_AUTOTYPE_LOCKED_FINAL
@ CU_SMOOTH
@ CU_TWIST_MINIMUM
@ CU_TWIST_TANGENT
eBezTriple_Flag
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
@ CU_NURB_BEZIER
#define DNA_struct_default_get(struct_name)
#define KEYELEM_ELEM_LEN_BPOINT
#define KEYELEM_FLOAT_LEN_BEZTRIPLE
#define KEYELEM_FLOAT_LEN_BPOINT
#define KEYELEM_ELEM_LEN_BEZTRIPLE
Object is a sort of wrapper for general info.
@ OB_SURF
@ OB_FONT
@ OB_CURVES_LEGACY
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
static void smooth_iter(CorrectiveSmoothModifierData *csmd, Mesh *mesh, blender::MutableSpan< blender::float3 > vertexCos, const float *smooth_weights, uint iterations)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
static T sum(const btAlignedObjectArray< T > &items)
#define p2_h1
#define p2_h2
local_group_size(16, 16) .push_constant(Type b
void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
Definition curve.cc:4103
static void bevel_list_flip_tangents(BevList *bl)
Definition curve.cc:2070
static void makeknots(Nurb *nu, short uv)
Definition curve.cc:1151
void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
Definition curve.cc:3994
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag)
Definition curve.cc:4374
static void basisNurb(float t, short order, int pnts, const float *knots, float *basis, int *start, int *end)
Definition curve.cc:1191
void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
Definition curve.cc:3985
void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
Definition curve.cc:5511
static void curve_copy_data(Main *bmain, std::optional< Library * > owner_library, ID *id_dst, const ID *id_src, const int flag)
Definition curve.cc:83
void BKE_nurb_index_to_uv(Nurb *nu, int index, int *r_u, int *r_v)
Definition curve.cc:911
void BKE_nurb_handles_calc(Nurb *nu)
Definition curve.cc:3955
const ListBase * BKE_curve_editNurbs_get_for_read(const Curve *cu)
Definition curve.cc:407
static void bezier_eq_noaccel_left(float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
Definition curve.cc:3608
void BKE_curve_translate(Curve *cu, const float offset[3], const bool do_keys)
Definition curve.cc:5245
static void nurbList_handles_swap_select(Nurb *nu)
Definition curve.cc:3964
static void make_bevel_list_segment_2D(BevList *bl)
Definition curve.cc:2414
void BKE_curve_editNurb_free(Curve *cu)
Definition curve.cc:337
bool BKE_curve_center_median(Curve *cu, float cent[3])
Definition curve.cc:5130
void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
Definition curve.cc:1269
static void curve_editNurb_keyIndex_cv_free_cb(void *val)
Definition curve.cc:315
void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth)
Definition curve.cc:5428
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
Definition curve.cc:5451
static bool bevelinside(const BevList *bl1, const BevList *bl2)
Definition curve.cc:1785
void BKE_nurb_project_2d(Nurb *nu)
Definition curve.cc:683
static void calc_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
Definition curve.cc:709
static void bevel_list_calc_bisect(BevList *bl)
Definition curve.cc:2008
void BKE_curve_texspace_ensure(Curve *cu)
Definition curve.cc:500
static void curve_init_data(ID *id)
Definition curve.cc:74
static void free_arrays(void *buffer)
Definition curve.cc:3384
void BKE_nurb_bpoint_calc_plane(Nurb *nu, BPoint *bp, float r_plane[3])
Definition curve.cc:1081
void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag)
Definition curve.cc:4184
static void make_bevel_list_3D_minimum_twist(BevList *bl)
Definition curve.cc:2197
static void curve_blend_read_data(BlendDataReader *reader, ID *id)
Definition curve.cc:208
void BKE_nurb_bezt_handle_test(BezTriple *bezt, const eBezTriple_Flag__Alias sel_flag, const eNurbHandleTest_Mode handle_mode, const bool use_around_local)
Definition curve.cc:4046
void BKE_nurb_bezt_calc_normal(Nurb *, BezTriple *bezt, float r_normal[3])
Definition curve.cc:1006
static void minimum_twist_between_two_points(BevPoint *bevp_curr, const BevPoint *bevp_prev)
Definition curve.cc:2181
static void curve_foreach_id(ID *id, LibraryForeachIDData *data)
Definition curve.cc:139
void BKE_nurb_handles_test(Nurb *nu, const eNurbHandleTest_Mode handle_mode, const bool use_around_local)
Definition curve.cc:4082
void BKE_curve_transform_ex(Curve *cu, const float mat[4][4], const bool do_keys, const bool do_props, const float unit_scale)
Definition curve.cc:5167
static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3], float p[3], int it, int stride)
Definition curve.cc:1715
static void bevel_list_smooth(BevList *bl, int smooth_iter)
Definition curve.cc:2114
void BKE_nurb_free(Nurb *nu)
Definition curve.cc:569
void BKE_curve_nurbs_vert_coords_apply_with_mat4(ListBase *lb, const float(*vert_coords)[3], const float mat[4][4], const bool constrain_2d)
Definition curve.cc:4565
void BKE_curve_init(Curve *cu, const short curve_type)
Definition curve.cc:347
static void make_bevel_list_segment_3D(BevList *bl)
Definition curve.cc:2390
void BKE_curve_type_test(Object *ob)
Definition curve.cc:454
static void make_bevel_list_3D_tangent(BevList *bl)
Definition curve.cc:2318
void BKE_curve_bevelList_free(ListBase *bev)
Definition curve.cc:2510
ListBase * BKE_curve_nurbs_get(Curve *cu)
Definition curve.cc:4965
void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
Definition curve.cc:4983
static int vergxcobev(const void *a1, const void *a2)
Definition curve.cc:1846
void BKE_curve_texspace_calc(Curve *cu)
Definition curve.cc:466
static void make_bevel_list_2D(BevList *bl)
Definition curve.cc:2430
Nurb * BKE_curve_nurb_active_get(Curve *cu)
Definition curve.cc:4995
#define MAT_NR_REMAP(n)
const ListBase * BKE_curve_nurbs_get_for_read(const Curve *cu)
Definition curve.cc:4974
static bool is_free_auto_point(BezTriple *bezt)
Definition curve.cc:3884
short BKE_nurb_bezt_handle_test_calc_flag(const BezTriple *bezt, const eBezTriple_Flag__Alias sel_flag, const eNurbHandleTest_Mode handle_mode)
Definition curve.cc:4013
bool BKE_nurb_check_valid_uv(const Nurb *nu)
Definition curve.cc:4789
void(* BKE_curve_batch_cache_free_cb)(Curve *cu)
Definition curve.cc:5509
void BKE_curve_batch_cache_free(Curve *cu)
Definition curve.cc:5517
void BKE_nurb_makeCurve(const Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride)
Definition curve.cc:1461
float BKE_nurb_calc_length(const Nurb *nu, int resolution)
Definition curve.cc:761
void BKE_curve_transform(Curve *cu, const float mat[4][4], const bool do_keys, const bool do_props)
Definition curve.cc:5239
bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles, const char **r_err_msg)
Definition curve.cc:4821
void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
Definition curve.cc:328
static void make_bevel_list_3D_zup(BevList *bl)
Definition curve.cc:2168
void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
Definition curve.cc:5021
static void * allocate_arrays(int count, float ***floats, char ***chars, const char *name)
Definition curve.cc:3351
static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bool skip_align)
Definition curve.cc:3300
void BKE_nurb_knot_calc_u(Nurb *nu)
Definition curve.cc:1181
void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
Definition curve.cc:3889
static float bezier_calc_handle_adj(float hsize[2], float dx)
Definition curve.cc:3693
static void bevel_list_apply_tilt(BevList *bl)
Definition curve.cc:2091
void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float(*vert_coords)[3], int vert_len)
Definition curve.cc:4528
void BKE_curve_dimension_update(Curve *cu)
Definition curve.cc:437
void BKE_curve_nurbs_key_vert_tilts_apply(ListBase *lb, const float *key)
Definition curve.cc:4672
void BKE_nurbList_duplicate(ListBase *lb1, const ListBase *lb2)
Definition curve.cc:673
static bool tridiagonal_solve_with_limits(float *a, float *b, float *c, float *d, float *h, const float *hmin, const float *hmax, int solve_count)
Definition curve.cc:3428
void BKE_nurb_handle_calc(BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
Definition curve.cc:3938
std::optional< blender::Bounds< blender::float3 > > BKE_curve_minmax(const Curve *cu, bool use_radius)
Definition curve.cc:5104
void * BKE_curve_vert_active_get(Curve *cu)
Definition curve.cc:5001
bool BKE_nurb_order_clamp_u(Nurb *nu)
Definition curve.cc:4801
static void calcknots(float *knots, const int pnts, const short order, const short flag)
Definition curve.cc:1111
#define SEL_F1
Definition curve.cc:4009
void BKE_nurbList_handles_set(ListBase *editnurb, eNurbHandleTest_Mode handle_mode, const char code)
Definition curve.cc:4191
static void bezier_lock_unknown(float *a, float *b, float *c, float *d, int i, float value)
Definition curve.cc:3405
#define SEL_F2
Definition curve.cc:4010
static void bezier_handle_calc_smooth_fcurve(BezTriple *bezt, int total, int start, int count, bool cycle)
Definition curve.cc:3703
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition curve.cc:1663
static void bezier_eq_noaccel_right(float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
Definition curve.cc:3599
void BKE_nurbList_free(ListBase *lb)
Definition curve.cc:596
void BKE_curve_material_remap(Curve *cu, const uint *remap, uint remap_len)
Definition curve.cc:5385
static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition curve.cc:161
void BKE_curve_editfont_free(Curve *cu)
Definition curve.cc:295
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition curve.cc:398
bool BKE_nurb_check_valid_v(const Nurb *nu)
Definition curve.cc:4781
static void calchandleNurb_intern(BezTriple *bezt, const BezTriple *prev, const BezTriple *next, eBezTriple_Flag handle_sel_flag, bool is_fcurve, bool skip_align, char fcurve_smoothing)
Definition curve.cc:3056
int BKE_nurbList_verts_count(const ListBase *nurb)
Definition curve.cc:535
void BKE_curve_nurbs_vert_coords_apply(ListBase *lb, const float(*vert_coords)[3], const bool constrain_2d)
Definition curve.cc:4602
static void bevlist_firstlast_direction_calc_from_bpoint(const Nurb *nu, BevList *bl)
Definition curve.cc:2493
void BKE_curve_material_index_remove(Curve *cu, int index)
Definition curve.cc:5291
int BKE_nurb_index_from_uv(Nurb *nu, int u, int v)
Definition curve.cc:889
void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
Definition curve.cc:2528
void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition curve.cc:1691
static void nurb_handles_calc__align_selected(Nurb *nu)
Definition curve.cc:3978
void BKE_nurb_knot_calc_v(Nurb *nu)
Definition curve.cc:1186
static std::optional< blender::Bounds< blender::float3 > > calc_nurblist_bounds(const ListBase *nurbs, const bool use_radius)
Definition curve.cc:5090
static void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode)
Definition curve.cc:2368
static bool bezier_check_solve_end_handle(BezTriple *bezt, char htype, bool end)
Definition curve.cc:3687
short BKE_curve_type_get(const Curve *cu)
Definition curve.cc:416
Curve * BKE_curve_add(Main *bmain, const char *name, int type)
Definition curve.cc:386
void(* BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode)
Definition curve.cc:5508
bool BKE_curve_material_index_used(const Curve *cu, int index)
Definition curve.cc:5312
void BKE_nurb_direction_switch(Nurb *nu)
Definition curve.cc:4405
void BKE_curve_nurb_vert_active_validate(Curve *cu)
Definition curve.cc:5065
#define SEL_F3
Definition curve.cc:4011
void BKE_curve_material_index_clear(Curve *cu)
Definition curve.cc:5335
void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
Definition curve.cc:5492
bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
Definition curve.cc:5038
BPoint * BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
Definition curve.cc:984
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
Definition curve.cc:509
bool BKE_nurb_check_valid_u(const Nurb *nu)
Definition curve.cc:4773
void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
Definition curve.cc:875
static float bezier_relax_direction(const float *a, const float *b, const float *c, const float *d, const float *h, int i, int count)
Definition curve.cc:3390
BPoint * BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
Definition curve.cc:941
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
Definition curve.cc:4339
static void bezier_output_handle_inner(BezTriple *bezt, bool right, const float newval[3], bool endpoint)
Definition curve.cc:3643
BezTriple * BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
Definition curve.cc:920
static NURBSValidationStatus nurb_check_valid(const int pnts, const short order, const short flag, const short type, const bool is_surf, int *r_points_needed)
Definition curve.cc:4696
void BKE_nurb_bpoint_calc_normal(Nurb *nu, BPoint *bp, float r_normal[3])
Definition curve.cc:1058
static void curve_free_data(ID *id)
Definition curve.cc:117
Nurb * BKE_nurb_duplicate(const Nurb *nu)
Definition curve.cc:608
bool BKE_nurb_order_clamp_v(Nurb *nu)
Definition curve.cc:4811
static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3], short cox, short coy, float *lambda, float *mu, float vec[3])
Definition curve.cc:1739
static void bezier_restore_equation(float *a, float *b, float *c, float *d, const float *a0, const float *b0, const float *c0, const float *d0, int i)
Definition curve.cc:3412
bool BKE_nurb_valid_message(const int pnts, const short order, const short flag, const short type, const bool is_surf, const int dir, char *message_dst, const size_t maxncpy)
Definition curve.cc:4729
void BKE_curve_rect_from_textbox(const Curve *cu, const TextBox *tb, rctf *r_rect)
Definition curve.cc:5442
void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
Definition curve.cc:322
int BKE_nurbList_verts_count_without_handles(const ListBase *nurb)
Definition curve.cc:551
static void bezier_output_handle(BezTriple *bezt, bool right, float dy, bool endpoint)
Definition curve.cc:3676
float(* BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
Definition curve.cc:4638
Nurb * BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
Definition curve.cc:648
static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *r_sina, float *r_cosa)
Definition curve.cc:1861
int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
Definition curve.cc:5010
static void bezier_eq_continuous(float *a, float *b, float *c, float *d, const float *dy, const float *l, int i)
Definition curve.cc:3590
static void bezier_clamp(float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot)
Definition curve.cc:3618
uint BKE_curve_calc_coords_axis_len(const uint bezt_array_len, const uint resolu, const bool is_cyclic, const bool use_cyclic_duplicate_endpoint)
Definition curve.cc:1597
static void tilt_bezpart(const BezTriple *prevbezt, const BezTriple *bezt, const Nurb *nu, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride)
Definition curve.cc:1909
void BKE_nurb_bezt_calc_plane(Nurb *nu, BezTriple *bezt, float r_plane[3])
Definition curve.cc:1021
NURBSValidationStatus
Definition curve.cc:66
float(* BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
Definition curve.cc:4555
void BKE_nurb_handle_calc_ex(BezTriple *bezt, BezTriple *prev, BezTriple *next, const eBezTriple_Flag__Alias handle_sel_flag, const bool is_fcurve, const char smoothing)
Definition curve.cc:3944
void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length, const uint8_t flag)
Definition curve.cc:4282
BezTriple * BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
Definition curve.cc:962
void BKE_curve_calc_coords_axis(const BezTriple *bezt_array, const uint bezt_array_len, const uint resolu, const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, const uint axis, const uint stride, float *r_points)
Definition curve.cc:1607
bool BKE_curve_material_index_validate(Curve *cu)
Definition curve.cc:5352
void BKE_nurb_points_add(Nurb *nu, int number)
Definition curve.cc:862
#define SELECT
#define sinf(x)
#define cosf(x)
#define atan2f(x, y)
#define fabsf(x)
#define sqrtf(x)
int len
static bool is_cyclic(const Nurb *nu)
draw_view in_light_buf[] float
#define str(s)
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float cross(const float2 a, const float2 b)
ccl_device_inline float3 cos(float3 v)
static ulong * next
static ulong state[N]
VecBase< float, 3 > float3
const btScalar eps
Definition poly34.cpp:11
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
unsigned char uint8_t
Definition stdint.h:78
uint8_t f1
float vec[4]
float * seglen
BevPoint * bevpoints
int * segbevcount
float dir[3]
float tan[3]
float quat[4]
float vec[3]
int dir
Definition curve.cc:1843
BevList * bl
Definition curve.cc:1841
float left
Definition curve.cc:1842
char auto_handle_type
float vec[3][3]
struct Object * bevobj
char edit_data_from_original
struct CurveProfile * bevel_profile
struct Material ** mat
struct VFont * vfont
short totcol
struct TextBox * tb
short resolv
void * batch_cache
struct EditFont * editfont
char bevfac2_mapping
short resolu
char texspace_flag
short twist_mode
float wordspace
struct Key * key
struct CharInfo * strinfo
struct VFont * vfontb
float linewidth
struct Object * textoncurve
char * str
EditNurb * editnurb
struct VFont * vfonti
float offset
ListBase nurb
float fsize
struct VFont * vfontbi
float texspace_size[3]
float texspace_location[3]
char bevfac1_mapping
struct Object * taperobj
short resolu_ren
float twist_smooth
CharInfo * textbufinfo
Definition BKE_vfont.hh:37
EditFontSelBox * selboxes
Definition BKE_vfont.hh:41
char32_t * textbuf
Definition BKE_vfont.hh:35
struct GHash * keyindex
ListBase nurbs
Definition DNA_ID.h:413
int us
Definition DNA_ID.h:435
char name[66]
Definition DNA_ID.h:425
ListBase block
void * last
void * first
short flagu
short orderu
short orderv
float * knotsu
short tilt_interp
short type
float * knotsv
BezTriple * bezt
BPoint * bp
short resolu
short radius_interp
short hide
short flagv
ObjectRuntimeHandle * runtime
float xmax
float xmin
float ymax
float ymin
float max
#define N_(msgid)
uint8_t flag
Definition wm_window.cc:138