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