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