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
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
131 BKE_curveprofile_free(curve->bevel_profile);
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
140{
141 Curve *curve = reinterpret_cast<Curve *>(id);
143
145 BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->taperobj, IDWALK_CB_NOP);
146 BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, curve->textoncurve, IDWALK_CB_NOP);
148 for (int i = 0; i < curve->totcol; i++) {
150 }
155
158 }
159}
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 }
257 cu->texspace_flag &= ~CU_TEXSPACE_FLAG_AUTO_EVALUATED;
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);
725 minmax_v3v3_v3(min, max, point);
726
727 sub_v3_v3v3(point, bezt->vec[1], radius_vector);
728 minmax_v3v3_v3(min, max, point);
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);
747 minmax_v3v3_v3(min, max, point);
748
749 sub_v3_v3v3(point, bp->vec, radius_vector);
750 minmax_v3v3_v3(min, max, point);
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}
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 }
5101 return blender::Bounds<float3>{min, max};
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);
5498 if (curve->texspace_flag & CU_TEXSPACE_FLAG_AUTO_EVALUATED) {
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
#define KNOTSV(nu)
Definition BKE_curve.hh:73
#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)
@ 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
@ LIB_ID_COPY_SHAPEKEY
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
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
int BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:120
@ IDWALK_DO_DEPRECATED_POINTERS
#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:1983
#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
#define MAXTEXTBOX
@ CU_SMOOTH
#define BEZT_IS_AUTOH(bezt)
struct Curve Curve
struct BevPoint BevPoint
@ CU_BEZIER
@ CU_POLY
@ CU_NURBS
struct BPoint BPoint
#define BEZT_ISSEL_ANY(bezt)
#define CU_ACT_NONE
@ CU_3D
@ CU_FRONT
@ CU_BACK
@ 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_TEXSPACE_FLAG_AUTO
@ CU_TEXSPACE_FLAG_AUTO_EVALUATED
struct BezTriple BezTriple
@ CU_BEVFAC_MAP_SPLINE
@ CU_BEVFAC_MAP_SEGMENT
@ CU_TWIST_MINIMUM
@ CU_TWIST_TANGENT
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
@ CU_NURB_BEZIER
eBezTriple_Flag
#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)
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
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
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
IDTypeInfo IDType_ID_CU_LEGACY
Definition curve.cc:265
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
#define p2_h1
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
#define p2_h2
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
const Depsgraph * depsgraph
#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]
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
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
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
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