Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/BKE_spline.hh')
-rw-r--r--source/blender/blenkernel/BKE_spline.hh436
1 files changed, 436 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
new file mode 100644
index 00000000000..5834437b7a1
--- /dev/null
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -0,0 +1,436 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <mutex>
+
+#include "FN_generic_virtual_array.hh"
+
+#include "BLI_float3.hh"
+#include "BLI_float4x4.hh"
+#include "BLI_vector.hh"
+
+#include "BKE_attribute_math.hh"
+
+struct Curve;
+
+/**
+ * Contains the information necessary to interpolate values from the original control points to
+ * evaluated points.
+ */
+struct PointMapping {
+ /**
+ * The index of the control point preceding the evaluated point at this index.
+ * For resolutions higher than 1, many evaluated points can share the same value.
+ */
+ int control_point_index;
+ /**
+ * This evaluated point's portion of the total length between the `control_point_index` value
+ * and the next.
+ */
+ float factor;
+};
+
+/**
+ * A spline is an abstraction of a curve section, its evaluation methods, and data.
+ * The spline data itself is just control points and a set of attributes.
+ *
+ * Common evaluated data is stored in caches on the spline itself. This way operations on splines
+ * don't need to worry about taking ownership of evaluated data when they don't need to.
+ */
+class Spline {
+ public:
+ using SplinePtr = std::unique_ptr<Spline>;
+
+ enum Type {
+ Bezier,
+ NURBS,
+ Poly,
+ };
+ Type type;
+ bool is_cyclic = false;
+
+ enum NormalCalculationMode {
+ ZUp,
+ Minimum,
+ Tangent,
+ };
+ NormalCalculationMode normal_mode;
+
+ protected:
+ mutable bool base_cache_dirty_ = true;
+ mutable std::mutex base_cache_mutex_;
+ mutable blender::Vector<blender::float3> evaluated_positions_cache_;
+ mutable blender::Vector<PointMapping> evaluated_mapping_cache_;
+
+ mutable bool tangent_cache_dirty_ = true;
+ mutable std::mutex tangent_cache_mutex_;
+ mutable blender::Vector<blender::float3> evaluated_tangents_cache_;
+
+ mutable bool normal_cache_dirty_ = true;
+ mutable std::mutex normal_cache_mutex_;
+ mutable blender::Vector<blender::float3> evaluated_normals_cache_;
+
+ mutable bool length_cache_dirty_ = true;
+ mutable std::mutex length_cache_mutex_;
+ mutable blender::Vector<float> evaluated_lengths_cache_;
+
+ public:
+ virtual ~Spline() = default;
+ Spline() = default;
+ Spline(Spline &other)
+ : type(other.type), is_cyclic(other.is_cyclic), normal_mode(other.normal_mode)
+ {
+ if (!other.base_cache_dirty_) {
+ evaluated_positions_cache_ = other.evaluated_positions_cache_;
+ evaluated_mapping_cache_ = other.evaluated_mapping_cache_;
+ base_cache_dirty_ = false;
+ }
+ if (!other.tangent_cache_dirty_) {
+ evaluated_tangents_cache_ = other.evaluated_tangents_cache_;
+ tangent_cache_dirty_ = false;
+ }
+ if (!other.normal_cache_dirty_) {
+ evaluated_normals_cache_ = other.evaluated_normals_cache_;
+ normal_cache_dirty_ = false;
+ }
+ if (!other.length_cache_dirty_) {
+ evaluated_lengths_cache_ = other.evaluated_lengths_cache_;
+ length_cache_dirty_ = false;
+ }
+ }
+
+ virtual SplinePtr copy() const = 0;
+
+ virtual int size() const = 0;
+ int segments_size() const;
+ virtual int resolution() const = 0;
+ virtual void set_resolution(const int value) = 0;
+
+ virtual void drop_front(const int count) = 0;
+ virtual void drop_back(const int count) = 0;
+
+ virtual blender::MutableSpan<blender::float3> positions() = 0;
+ virtual blender::Span<blender::float3> positions() const = 0;
+ virtual blender::MutableSpan<float> radii() = 0;
+ virtual blender::Span<float> radii() const = 0;
+ virtual blender::MutableSpan<float> tilts() = 0;
+ virtual blender::Span<float> tilts() const = 0;
+
+ virtual void mark_cache_invalid();
+ virtual int evaluated_points_size() const = 0;
+ int evaluated_edges_size() const;
+
+ float length() const;
+
+ blender::Span<blender::float3> evaluated_positions() const;
+ blender::Span<PointMapping> evaluated_mappings() const;
+ blender::Span<float> evaluated_lengths() const;
+ blender::Span<blender::float3> evaluated_tangents() const;
+ blender::Span<blender::float3> evaluated_normals() const;
+
+ struct LookupResult {
+ /*
+ * The index of the evaluated point before the result location.
+ * In other words, the index of the edge that the result lies on.
+ */
+ int evaluated_index;
+ /**
+ * The portion of the way from the evaluated point at #index to the next point.
+ */
+ float factor;
+ };
+ LookupResult lookup_evaluated_factor(const float factor) const;
+ LookupResult lookup_evaluated_length(const float length) const;
+
+ /**
+ * Interpolate data from the original control points to the corresponding ealuated points.
+ * \param source_data: Should have the same size as the number of control points.
+ * \param result_data: ...
+ */
+ template<typename T>
+ void interpolate_data_to_evaluated_points(blender::Span<T> source_data,
+ blender::MutableSpan<T> result_data,
+ const int offset = 0) const
+ {
+ /* TODO: Onstead of "offset", it may be better to split a function that returns a single value.
+ * TODO: Check for null default mixer, possibly using std::enable_if? */
+ const int control_points_len = this->size();
+ blender::Span<PointMapping> mappings = this->evaluated_mappings();
+
+ blender::attribute_math::DefaultMixer<T> mixer(result_data);
+
+ for (const int i : result_data.index_range()) {
+ const int evaluated_point_index = offset + i;
+ const PointMapping &mapping = mappings[evaluated_point_index];
+ const int index = mapping.control_point_index;
+ const int next_index = (index + 1) % control_points_len;
+ const float factor = mapping.factor;
+
+ const T &value = source_data[index];
+ const T &next_value = source_data[next_index];
+
+ mixer.mix_in(i, value, 1.0f - factor);
+ mixer.mix_in(i, next_value, factor);
+ }
+
+ mixer.finalize();
+ }
+
+ protected:
+ virtual void correct_end_tangents() const = 0;
+ virtual void ensure_base_cache() const = 0;
+};
+
+using SplinePtr = std::unique_ptr<Spline>;
+
+class BezierSpline final : public Spline {
+ public:
+ enum HandleType {
+ Free,
+ Auto,
+ Vector,
+ Align,
+ };
+
+ private:
+ blender::Vector<HandleType> handle_types_start_;
+ blender::Vector<blender::float3> handle_positions_start_;
+ blender::Vector<blender::float3> positions_;
+ blender::Vector<HandleType> handle_types_end_;
+ blender::Vector<blender::float3> handle_positions_end_;
+ blender::Vector<float> radii_;
+ blender::Vector<float> tilts_;
+ int resolution_u_;
+
+ public:
+ virtual SplinePtr copy() const final;
+ BezierSpline() = default;
+ BezierSpline(const BezierSpline &other)
+ : Spline((Spline &)other),
+ handle_types_start_(other.handle_types_start_),
+ handle_positions_start_(other.handle_positions_start_),
+ positions_(other.positions_),
+ handle_types_end_(other.handle_types_end_),
+ handle_positions_end_(other.handle_positions_end_),
+ radii_(other.radii_),
+ tilts_(other.tilts_),
+ resolution_u_(other.resolution_u_)
+ {
+ }
+
+ int size() const final;
+ int resolution() const final;
+ void set_resolution(const int value) final;
+
+ blender::MutableSpan<blender::float3> positions() final;
+ blender::Span<blender::float3> positions() const final;
+ blender::MutableSpan<float> radii() final;
+ blender::Span<float> radii() const final;
+ blender::MutableSpan<float> tilts() final;
+ blender::Span<float> tilts() const final;
+
+ blender::Span<HandleType> handle_types_start() const;
+ blender::MutableSpan<HandleType> handle_types_start();
+ blender::Span<blender::float3> handle_positions_start() const;
+ blender::MutableSpan<blender::float3> handle_positions_start();
+ blender::Span<HandleType> handle_types_end() const;
+ blender::MutableSpan<HandleType> handle_types_end();
+ blender::Span<blender::float3> handle_positions_end() const;
+ blender::MutableSpan<blender::float3> handle_positions_end();
+
+ void add_point(const blender::float3 position,
+ const HandleType handle_type_start,
+ const blender::float3 handle_position_start,
+ const HandleType handle_type_end,
+ const blender::float3 handle_position_end,
+ const float radius,
+ const float tilt);
+
+ void drop_front(const int count) final;
+ void drop_back(const int count) final;
+
+ int evaluated_points_size() const final;
+
+ bool point_is_sharp(const int index) const;
+ bool handle_start_is_automatic(const int index) const;
+ bool handle_end_is_automatic(const int index) const;
+
+ void move_control_point(const int index, const blender::float3 new_position);
+
+ protected:
+ void correct_final_tangents() const;
+
+ private:
+ void correct_end_tangents() const final;
+ void ensure_base_cache() const final;
+ bool segment_is_vector(const int start_index) const;
+ void evaluate_bezier_segment(const int index,
+ const int next_index,
+ int &offset,
+ blender::MutableSpan<blender::float3> positions,
+ blender::MutableSpan<PointMapping> mappings) const;
+ void evaluate_bezier_position_and_mapping(blender::MutableSpan<blender::float3> positions,
+ blender::MutableSpan<PointMapping> mappings) const;
+};
+
+class NURBSpline final : public Spline {
+ public:
+ enum KnotsMode {
+ Normal,
+ EndPoint,
+ Bezier,
+ };
+ KnotsMode knots_mode;
+
+ struct WeightCache {
+ blender::Vector<float> weights;
+ int start_index;
+ };
+
+ private:
+ blender::Vector<blender::float3> positions_;
+ blender::Vector<float> radii_;
+ blender::Vector<float> tilts_;
+ blender::Vector<float> weights_;
+ int resolution_u_;
+ uint8_t order_;
+
+ mutable bool knots_dirty_ = true;
+ mutable std::mutex knots_mutex_;
+ mutable blender::Vector<float> knots_;
+
+ mutable bool weights_dirty_ = true;
+ mutable std::mutex weights_mutex_;
+ mutable blender::Vector<WeightCache> weight_cache_;
+
+ public:
+ SplinePtr copy() const final;
+ NURBSpline() = default;
+ NURBSpline(const NURBSpline &other)
+ : Spline((Spline &)other),
+ positions_(other.positions_),
+ radii_(other.radii_),
+ tilts_(other.tilts_),
+ weights_(other.weights_),
+ resolution_u_(other.resolution_u_),
+ order_(other.order_)
+ {
+ }
+
+ int size() const final;
+ int resolution() const final;
+ void set_resolution(const int value) final;
+ uint8_t order() const;
+ void set_order(const uint8_t value);
+
+ bool check_valid_size_and_order() const;
+ int knots_size() const;
+
+ blender::MutableSpan<blender::float3> positions() final;
+ blender::Span<blender::float3> positions() const final;
+ blender::MutableSpan<float> radii() final;
+ blender::Span<float> radii() const final;
+ blender::MutableSpan<float> tilts() final;
+ blender::Span<float> tilts() const final;
+
+ blender::Span<float> knots() const;
+
+ blender::MutableSpan<float> weights();
+ blender::Span<float> weights() const;
+
+ void add_point(const blender::float3 position,
+ const float radius,
+ const float tilt,
+ const float weight);
+
+ void drop_front(const int count) final;
+ void drop_back(const int count) final;
+
+ int evaluated_points_size() const final;
+
+ blender::fn::GVArrayPtr interpolate_to_evaluated_points(
+ const blender::fn::GVArray &source_data) const;
+
+ protected:
+ void correct_end_tangents() const final;
+ void ensure_base_cache() const final;
+ void calculate_knots() const;
+ void calculate_weights() const;
+};
+
+class PolySpline final : public Spline {
+ public:
+ blender::Vector<blender::float3> positions_;
+ blender::Vector<float> radii_;
+ blender::Vector<float> tilts_;
+
+ private:
+ public:
+ SplinePtr copy() const final;
+ PolySpline() = default;
+ PolySpline(const PolySpline &other)
+ : Spline((Spline &)other),
+ positions_(other.positions_),
+ radii_(other.radii_),
+ tilts_(other.tilts_)
+ {
+ }
+
+ int size() const final;
+ int resolution() const final;
+ void set_resolution(const int value) final;
+
+ blender::MutableSpan<blender::float3> positions() final;
+ blender::Span<blender::float3> positions() const final;
+ blender::MutableSpan<float> radii() final;
+ blender::Span<float> radii() const final;
+ blender::MutableSpan<float> tilts() final;
+ blender::Span<float> tilts() const final;
+
+ void add_point(const blender::float3 position, const float radius, const float tilt);
+
+ void drop_front(const int count) final;
+ void drop_back(const int count) final;
+
+ int evaluated_points_size() const final;
+
+ protected:
+ void correct_end_tangents() const final;
+ void ensure_base_cache() const final;
+};
+
+/* Proposed name to be different from DNA type. */
+class DCurve {
+ public:
+ blender::Vector<SplinePtr> splines;
+
+ // bool is_2d;
+
+ DCurve *copy();
+
+ // DCurve *copy();
+
+ void translate(const blender::float3 translation);
+ void transform(const blender::float4x4 &matrix);
+};
+
+DCurve *dcurve_from_dna_curve(const Curve &curve); \ No newline at end of file