Blender V4.3
BKE_curves.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
12#include "BLI_bounds_types.hh"
15#include "BLI_index_mask_fwd.hh"
19#include "BLI_offset_indices.hh"
20#include "BLI_shared_cache.hh"
21#include "BLI_span.hh"
22#include "BLI_vector.hh"
24
25#include "BKE_attribute_math.hh"
26#include "BKE_curves.h"
27
28struct BlendDataReader;
29struct BlendWriter;
30struct MDeformVert;
31namespace blender::bke {
32class AttributeAccessor;
33class MutableAttributeAccessor;
34enum class AttrDomain : int8_t;
35} // namespace blender::bke
36namespace blender::bke::bake {
37struct BakeMaterialsList;
38}
39
40namespace blender::bke {
41
42namespace curves::nurbs {
43
63
64} // namespace curves::nurbs
65
129
136 public:
143 CurvesGeometry(const CurvesGeometry &other);
148
149 /* --------------------------------------------------------------------
150 * Accessors.
151 */
152
156 int points_num() const;
160 int curves_num() const;
161 IndexRange points_range() const;
162 IndexRange curves_range() const;
163
170 Span<int> offsets() const;
172
177
186 void fill_curve_types(CurveType type);
188 void fill_curve_types(const IndexMask &selection, CurveType type);
190 void update_curve_types();
191
192 bool has_curve_with_type(CurveType type) const;
193 bool has_curve_with_type(Span<CurveType> types) const;
195 bool is_single_type(CurveType type) const;
197 const std::array<int, CURVE_TYPES_NUM> &curve_type_counts() const;
203 const IndexMask &selection,
204 IndexMaskMemory &memory) const;
205
207
208 Span<float3> positions() const;
210
212 VArray<bool> cyclic() const;
215
220 VArray<int> resolution() const;
223
228 VArray<float> tilt() const;
230
237
245
256
263
270
276
282
289
293 std::optional<Bounds<float3>> bounds_min_max() const;
294
295 void count_memory(MemoryCounter &memory) const;
296
297 private:
298 /* --------------------------------------------------------------------
299 * Evaluation.
300 */
301
302 public:
307 int evaluated_points_num() const;
308
313
319 Span<int> bezier_evaluated_offsets_for_curve(int curve_index) const;
320
324
334 Span<float> evaluated_lengths_for_curve(int curve_index, bool cyclic) const;
335 float evaluated_length_total_for_curve(int curve_index, bool cyclic) const;
336
338 void ensure_evaluated_lengths() const;
339
341
349 void interpolate_to_evaluated(int curve_index, GSpan src, GMutableSpan dst) const;
353 void interpolate_to_evaluated(GSpan src, GMutableSpan dst) const;
354
355 private:
359 void ensure_nurbs_basis_cache() const;
360
362 IndexRange lengths_range_for_curve(int curve_index, bool cyclic) const;
363
364 /* --------------------------------------------------------------------
365 * Operations.
366 */
367
368 public:
375 void resize(int points_num, int curves_num);
376
385 void tag_normals_changed();
390 void tag_radii_changed();
391
392 void translate(const float3 &translation);
393 void transform(const float4x4 &matrix);
394
396
397 void remove_points(const IndexMask &points_to_delete, const AttributeFilter &attribute_filter);
398 void remove_curves(const IndexMask &curves_to_delete, const AttributeFilter &attribute_filter);
399
404 void reverse_curves(const IndexMask &curves_to_reverse);
405
410
413
414 /* --------------------------------------------------------------------
415 * Attributes.
416 */
417
418 GVArray adapt_domain(const GVArray &varray, AttrDomain from, AttrDomain to) const;
419 template<typename T>
420 VArray<T> adapt_domain(const VArray<T> &varray, AttrDomain from, AttrDomain to) const
421 {
422 return this->adapt_domain(GVArray(varray), from, to).typed<T>();
423 }
424
425 /* --------------------------------------------------------------------
426 * File Read/Write.
427 */
428 void blend_read(BlendDataReader &reader);
433 /* The point custom data layers to be written. */
435 /* The curve custom data layers to be written. */
437 };
443 void blend_write(BlendWriter &writer, ID &id, const BlendWriteData &write_data);
444};
445
446static_assert(sizeof(blender::bke::CurvesGeometry) == sizeof(::CurvesGeometry));
447
453 public:
467 std::optional<Array<float3x3>> deform_mats;
468
470
471 std::optional<Span<float3>> positions() const;
472 std::optional<MutableSpan<float3>> positions_for_write();
473
478 bool is_valid() const;
479};
480
482
483namespace curves {
484
485/* -------------------------------------------------------------------- */
493inline int segments_num(const int points_num, const bool cyclic)
494{
495 BLI_assert(points_num > 0);
496 return (cyclic && points_num > 1) ? points_num : points_num - 1;
497}
498
500{
501 BLI_assert(std::abs(v.x + v.y + v.z - 1.0f) < 0.00001f);
502 return {v.x, v.y};
503}
504
506{
507 return {v.x, v.y, 1.0f - v.x - v.y};
508}
509
516inline IndexRange per_curve_point_offsets_range(const IndexRange points, const int curve_index)
517{
518 return {curve_index + points.start(), points.size() + 1};
519}
520
523/* -------------------------------------------------------------------- */
527namespace poly {
528
535void calculate_tangents(Span<float3> positions, bool is_cyclic, MutableSpan<float3> tangents);
536
542void calculate_normals_minimum(Span<float3> tangents, bool cyclic, MutableSpan<float3> normals);
543
549
550} // namespace poly
551
554/* -------------------------------------------------------------------- */
558namespace bezier {
559
564bool segment_is_vector(const HandleType left, const HandleType right);
565bool segment_is_vector(const int8_t left, const int8_t right);
566bool segment_is_vector(Span<int8_t> handle_types_left,
567 Span<int8_t> handle_types_right,
568 int segment_index);
569
578bool has_vector_handles(int num_curve_points, int64_t evaluated_size, bool cyclic, int resolution);
579
584bool last_cyclic_segment_is_vector(Span<int8_t> handle_types_left,
585 Span<int8_t> handle_types_right);
586
592bool point_is_sharp(Span<int8_t> handle_types_left, Span<int8_t> handle_types_right, int index);
593
603void calculate_evaluated_offsets(Span<int8_t> handle_types_left,
604 Span<int8_t> handle_types_right,
605 bool cyclic,
606 int resolution,
607 MutableSpan<int> evaluated_offsets);
608
617
636Insertion insert(const float3 &point_prev,
637 const float3 &handle_prev,
638 const float3 &handle_next,
639 const float3 &point_next,
640 float parameter);
641
648float3 calculate_vector_handle(const float3 &point, const float3 &next_point);
649
656void calculate_auto_handles(bool cyclic,
657 Span<int8_t> types_left,
658 Span<int8_t> types_right,
659 Span<float3> positions,
660 MutableSpan<float3> positions_left,
661 MutableSpan<float3> positions_right);
662
670void set_handle_position(const float3 &position,
671 HandleType type,
672 HandleType type_other,
673 const float3 &new_handle,
674 float3 &handle,
675 float3 &handle_other);
676
683template<typename T>
685 const T &point_0, const T &point_1, const T &point_2, const T &point_3, MutableSpan<T> result);
686
697 Span<float3> handles_left,
698 Span<float3> handles_right,
699 OffsetIndices<int> evaluated_offsets,
700 MutableSpan<float3> evaluated_positions);
701
707void interpolate_to_evaluated(GSpan src, OffsetIndices<int> evaluated_offsets, GMutableSpan dst);
708
709} // namespace bezier
710
713/* -------------------------------------------------------------------- */
717namespace catmull_rom {
718
724int calculate_evaluated_num(int points_num, bool cyclic, int resolution);
725
730void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst);
731
736void interpolate_to_evaluated(const GSpan src,
737 const bool cyclic,
738 const OffsetIndices<int> evaluated_offsets,
739 GMutableSpan dst);
740
741float4 calculate_basis(const float parameter);
742
749template<typename T>
750T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter)
751{
752 BLI_assert(0.0f <= parameter && parameter <= 1.0f);
753 const float4 weights = calculate_basis(parameter);
755 /* Save multiplications by adjusting weights after mix. */
756 return 0.5f * attribute_math::mix4<T>(weights, a, b, c, d);
757 }
758 else {
759 return attribute_math::mix4<T>(weights * 0.5f, a, b, c, d);
760 }
761}
762
763} // namespace catmull_rom
764
767/* -------------------------------------------------------------------- */
771namespace nurbs {
772
776bool check_valid_num_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode);
777
787 int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode);
788
794int knots_num(int points_num, int8_t order, bool cyclic);
795
804void calculate_knots(
805 int points_num, KnotsMode mode, int8_t order, bool cyclic, MutableSpan<float> knots);
806
813void calculate_basis_cache(int points_num,
814 int evaluated_num,
815 int8_t order,
816 bool cyclic,
817 Span<float> knots,
818 BasisCache &basis_cache);
819
828void interpolate_to_evaluated(const BasisCache &basis_cache,
829 int8_t order,
830 Span<float> control_weights,
831 GSpan src,
832 GMutableSpan dst);
833
834} // namespace nurbs
835
838} // namespace curves
839
840Curves *curves_new_nomain(int points_num, int curves_num);
842
846Curves *curves_new_nomain_single(int points_num, CurveType type);
847
852void curves_copy_parameters(const Curves &src, Curves &dst);
853
855 const IndexMask &points_to_copy,
856 const AttributeFilter &attribute_filter);
857
859 const IndexMask &curves_to_copy,
860 const AttributeFilter &attribute_filter);
861
862CurvesGeometry curves_new_no_attributes(int point_num, int curve_num);
863
864std::array<int, CURVE_TYPES_NUM> calculate_type_counts(const VArray<int8_t> &types);
865
866/* -------------------------------------------------------------------- */
870inline int CurvesGeometry::points_num() const
871{
872 return this->point_num;
873}
874inline int CurvesGeometry::curves_num() const
875{
876 return this->curve_num;
877}
878inline IndexRange CurvesGeometry::points_range() const
879{
880 return IndexRange(this->points_num());
881}
882inline IndexRange CurvesGeometry::curves_range() const
883{
884 return IndexRange(this->curves_num());
885}
886
887inline bool CurvesGeometry::is_single_type(const CurveType type) const
888{
889 return this->curve_type_counts()[type] == this->curves_num();
890}
891
892inline bool CurvesGeometry::has_curve_with_type(const CurveType type) const
893{
894 return this->curve_type_counts()[type] > 0;
895}
896
897inline bool CurvesGeometry::has_curve_with_type(const Span<CurveType> types) const
898{
899 return std::any_of(
900 types.begin(), types.end(), [&](CurveType type) { return this->has_curve_with_type(type); });
901}
902
903inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts() const
904{
905#ifndef NDEBUG
906
907 if (this->runtime->check_type_counts) {
908 const std::array<int, CURVE_TYPES_NUM> actual_type_counts = calculate_type_counts(
909 this->curve_types());
910 BLI_assert(this->runtime->type_counts == actual_type_counts);
911 this->runtime->check_type_counts = false;
912 }
913#endif
914 return this->runtime->type_counts;
915}
916
917inline OffsetIndices<int> CurvesGeometry::points_by_curve() const
918{
919 return OffsetIndices<int>({this->curve_offsets, this->curve_num + 1},
921}
922
923inline int CurvesGeometry::evaluated_points_num() const
924{
925 /* This could avoid calculating offsets in the future in simple circumstances. */
926 return this->evaluated_points_by_curve().total_size();
927}
928
929inline Span<int> CurvesGeometry::bezier_evaluated_offsets_for_curve(const int curve_index) const
930{
932 const IndexRange points = points_by_curve[curve_index];
933 const IndexRange range = curves::per_curve_point_offsets_range(points, curve_index);
934 const Span<int> offsets = this->runtime->evaluated_offsets_cache.data().all_bezier_offsets;
935 return offsets.slice(range);
936}
937
938inline IndexRange CurvesGeometry::lengths_range_for_curve(const int curve_index,
939 const bool cyclic) const
940{
941 BLI_assert(cyclic == this->cyclic()[curve_index]);
942 const IndexRange points = this->evaluated_points_by_curve()[curve_index];
943 const int start = points.start() + curve_index;
944 return {start, curves::segments_num(points.size(), cyclic)};
945}
946
947inline Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,
948 const bool cyclic) const
949{
950 const IndexRange range = this->lengths_range_for_curve(curve_index, cyclic);
951 return this->runtime->evaluated_length_cache.data().as_span().slice(range);
952}
953
954inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_index,
955 const bool cyclic) const
956{
957 const Span<float> lengths = this->evaluated_lengths_for_curve(curve_index, cyclic);
958 if (lengths.is_empty()) {
959 return 0.0f;
960 }
961 return lengths.last();
962}
963
966namespace curves {
967
968/* -------------------------------------------------------------------- */
972namespace bezier {
973
974inline bool point_is_sharp(const Span<int8_t> handle_types_left,
975 const Span<int8_t> handle_types_right,
976 const int index)
977{
978 return ELEM(handle_types_left[index], BEZIER_HANDLE_VECTOR, BEZIER_HANDLE_FREE) ||
979 ELEM(handle_types_right[index], BEZIER_HANDLE_VECTOR, BEZIER_HANDLE_FREE);
980}
981
982inline bool segment_is_vector(const HandleType left, const HandleType right)
983{
984 return left == BEZIER_HANDLE_VECTOR && right == BEZIER_HANDLE_VECTOR;
985}
986
987inline bool segment_is_vector(const int8_t left, const int8_t right)
988{
989 return segment_is_vector(HandleType(left), HandleType(right));
990}
991
992inline bool has_vector_handles(const int num_curve_points,
993 const int64_t evaluated_size,
994 const bool cyclic,
995 const int resolution)
996{
997 return evaluated_size - !cyclic != int64_t(segments_num(num_curve_points, cyclic)) * resolution;
998}
999
1000inline float3 calculate_vector_handle(const float3 &point, const float3 &next_point)
1001{
1002 return math::interpolate(point, next_point, 1.0f / 3.0f);
1003}
1004
1005} // namespace bezier
1006
1009} // namespace curves
1010
1023
1024} // namespace blender::bke
1025
1026inline blender::bke::CurvesGeometry &CurvesGeometry::wrap()
1027{
1028 return *reinterpret_cast<blender::bke::CurvesGeometry *>(this);
1029}
1030inline const blender::bke::CurvesGeometry &CurvesGeometry::wrap() const
1031{
1032 return *reinterpret_cast<const blender::bke::CurvesGeometry *>(this);
1033}
Low-level operations for curves that cannot be defined in the C++ header yet.
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ELEM(...)
CurveType
HandleType
@ BEZIER_HANDLE_FREE
@ BEZIER_HANDLE_VECTOR
KnotsMode
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr int64_t start() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr const T * data() const
Definition BLI_span.hh:216
std::optional< MutableSpan< float3 > > positions_for_write()
ImplicitSharingPtrAndData positions_data
std::optional< Span< float3 > > positions() const
CurvesEditHints(const Curves &curves_id_orig)
std::optional< Array< float3x3 > > deform_mats
SharedCache< Vector< curves::nurbs::BasisCache > > nurbs_basis_cache
Definition BKE_curves.hh:90
SharedCache< Vector< float > > evaluated_length_cache
SharedCache< Vector< float3 > > evaluated_tangent_cache
SharedCache< EvaluatedOffsets > evaluated_offsets_cache
Definition BKE_curves.hh:88
SharedCache< Vector< float3 > > evaluated_normal_cache
std::unique_ptr< bake::BakeMaterialsList > bake_materials
SharedCache< Bounds< float3 > > bounds_cache
SharedCache< Vector< float3 > > evaluated_position_cache
Definition BKE_curves.hh:96
const ImplicitSharingInfo * curve_offsets_sharing_info
Definition BKE_curves.hh:72
std::array< int, CURVE_TYPES_NUM > type_counts
Definition BKE_curves.hh:78
VArray< int8_t > handle_types_left() const
void reverse_curves(const IndexMask &curves_to_reverse)
void blend_read(BlendDataReader &reader)
MutableSpan< float3 > positions_for_write()
void translate(const float3 &translation)
Array< int > point_to_curve_map() const
MutableSpan< MDeformVert > deform_verts_for_write()
OffsetIndices< int > points_by_curve() const
VArray< int8_t > normal_mode() const
MutableSpan< int8_t > handle_types_right_for_write()
VArray< int8_t > handle_types_right() const
void ensure_can_interpolate_to_evaluated() const
IndexRange curves_range() const
MutableSpan< int8_t > curve_types_for_write()
MutableSpan< int > resolution_for_write()
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
MutableSpan< float3 > handle_positions_left_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< float3 > handle_positions_right_for_write()
MutableSpan< int8_t > nurbs_knots_modes_for_write()
Span< float > evaluated_lengths_for_curve(int curve_index, bool cyclic) const
MutableSpan< float > tilt_for_write()
VArray< float > tilt() const
void blend_write(BlendWriter &writer, ID &id, const BlendWriteData &write_data)
Span< float3 > evaluated_tangents() const
Span< MDeformVert > deform_verts() const
MutableSpan< int8_t > nurbs_orders_for_write()
Span< float > nurbs_weights() const
MutableSpan< float2 > surface_uv_coords_for_write()
Span< float3 > handle_positions_left() const
VArray< int > resolution() const
Span< int > bezier_evaluated_offsets_for_curve(int curve_index) const
void interpolate_to_evaluated(int curve_index, GSpan src, GMutableSpan dst) const
IndexRange points_range() const
VArray< int8_t > nurbs_knots_modes() const
Span< float3 > evaluated_normals() const
std::optional< Bounds< float3 > > bounds_min_max() const
Span< float3 > positions() const
OffsetIndices< int > evaluated_points_by_curve() const
bool has_curve_with_type(CurveType type) const
MutableSpan< float > nurbs_weights_for_write()
GVArray adapt_domain(const GVArray &varray, AttrDomain from, AttrDomain to) const
void resize(int points_num, int curves_num)
Span< float3 > handle_positions_right() const
void remove_curves(const IndexMask &curves_to_delete, const AttributeFilter &attribute_filter)
MutableSpan< int8_t > normal_mode_for_write()
VArray< T > adapt_domain(const VArray< T > &varray, AttrDomain from, AttrDomain to) const
void fill_curve_types(CurveType type)
float evaluated_length_total_for_curve(int curve_index, bool cyclic) const
IndexMask indices_for_curve_type(CurveType type, IndexMaskMemory &memory) const
void count_memory(MemoryCounter &memory) const
bool is_single_type(CurveType type) const
MutableSpan< int > offsets_for_write()
Span< float2 > surface_uv_coords() const
void remove_points(const IndexMask &points_to_delete, const AttributeFilter &attribute_filter)
void transform(const float4x4 &matrix)
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
CurvesGeometry & operator=(const CurvesGeometry &other)
MutableSpan< bool > cyclic_for_write()
VArray< int8_t > nurbs_orders() const
MutableSpan< int8_t > handle_types_left_for_write()
local_group_size(16, 16) .push_constant(Type b
static bool is_cyclic(const Nurb *nu)
T mix4(const float4 &weights, const T &v0, const T &v1, const T &v2, const T &v3)
Insertion insert(const float3 &point_prev, const float3 &handle_prev, const float3 &handle_next, const float3 &point_next, float parameter)
bool segment_is_vector(const HandleType left, const HandleType right)
bool point_is_sharp(Span< int8_t > handle_types_left, Span< int8_t > handle_types_right, int index)
void calculate_auto_handles(bool cyclic, Span< int8_t > types_left, Span< int8_t > types_right, Span< float3 > positions, MutableSpan< float3 > positions_left, MutableSpan< float3 > positions_right)
void calculate_evaluated_offsets(Span< int8_t > handle_types_left, Span< int8_t > handle_types_right, bool cyclic, int resolution, MutableSpan< int > evaluated_offsets)
float3 calculate_vector_handle(const float3 &point, const float3 &next_point)
bool has_vector_handles(int num_curve_points, int64_t evaluated_size, bool cyclic, int resolution)
bool last_cyclic_segment_is_vector(Span< int8_t > handle_types_left, Span< int8_t > handle_types_right)
void evaluate_segment(const T &point_0, const T &point_1, const T &point_2, const T &point_3, MutableSpan< T > result)
void calculate_evaluated_positions(Span< float3 > positions, Span< float3 > handles_left, Span< float3 > handles_right, OffsetIndices< int > evaluated_offsets, MutableSpan< float3 > evaluated_positions)
void interpolate_to_evaluated(GSpan src, OffsetIndices< int > evaluated_offsets, GMutableSpan dst)
void set_handle_position(const float3 &position, HandleType type, HandleType type_other, const float3 &new_handle, float3 &handle, float3 &handle_other)
T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter)
int calculate_evaluated_num(int points_num, bool cyclic, int resolution)
float4 calculate_basis(const float parameter)
void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst)
int calculate_evaluated_num(int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode)
bool check_valid_num_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode)
void calculate_knots(int points_num, KnotsMode mode, int8_t order, bool cyclic, MutableSpan< float > knots)
void calculate_basis_cache(int points_num, int evaluated_num, int8_t order, bool cyclic, Span< float > knots, BasisCache &basis_cache)
int knots_num(int points_num, int8_t order, bool cyclic)
void interpolate_to_evaluated(const BasisCache &basis_cache, int8_t order, Span< float > control_weights, GSpan src, GMutableSpan dst)
void calculate_normals_z_up(Span< float3 > tangents, MutableSpan< float3 > normals)
void calculate_normals_minimum(Span< float3 > tangents, bool cyclic, MutableSpan< float3 > normals)
void calculate_tangents(Span< float3 > positions, bool is_cyclic, MutableSpan< float3 > tangents)
Definition curve_poly.cc:43
IndexRange per_curve_point_offsets_range(const IndexRange points, const int curve_index)
float3 decode_surface_bary_coord(const float2 &v)
int segments_num(const int points_num, const bool cyclic)
float2 encode_surface_bary_coord(const float3 &v)
CurvesGeometry curves_copy_curve_selection(const CurvesGeometry &curves, const IndexMask &curves_to_copy, const AttributeFilter &attribute_filter)
CurvesGeometry curves_copy_point_selection(const CurvesGeometry &curves, const IndexMask &points_to_copy, const AttributeFilter &attribute_filter)
void curves_copy_parameters(const Curves &src, Curves &dst)
CurvesGeometry curves_new_no_attributes(int point_num, int curve_num)
std::array< int, CURVE_TYPES_NUM > calculate_type_counts(const VArray< int8_t > &types)
Curves * curves_new_nomain_single(int points_num, CurveType type)
Curves * curves_new_nomain(int points_num, int curves_num)
void curves_normals_point_domain_calc(const CurvesGeometry &curves, MutableSpan< float3 > normals)
T interpolate(const T &a, const T &b, const FactorT &t)
constexpr bool is_same_any_v
__int64 int64_t
Definition stdint.h:89
signed char int8_t
Definition stdint.h:75
CurvesGeometryRuntimeHandle * runtime
Definition DNA_ID.h:413
Vector< CustomDataLayer, 16 > curve_layers
Vector< CustomDataLayer, 16 > point_layers