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')
-rw-r--r--source/blender/blenkernel/BKE_curves.hh26
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc60
2 files changed, 86 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 82f77d83bec..05a20917552 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -77,6 +77,15 @@ class CurvesGeometryRuntime {
mutable std::mutex position_cache_mutex;
mutable bool position_cache_dirty = true;
+ /**
+ * Cache of lengths along each evaluated curve for for each evaluated point. If a curve is
+ * cyclic, it needs one more length value to correspond to the last segment, so in order to
+ * make slicing this array for a curve fast, an extra float is stored for every curve.
+ */
+ mutable Vector<float> evaluated_length_cache;
+ mutable std::mutex length_cache_mutex;
+ mutable bool length_cache_dirty = true;
+
/** Direction of the spline at each evaluated point. */
mutable Vector<float3> evaluated_tangents_cache;
mutable std::mutex tangent_cache_mutex;
@@ -267,6 +276,20 @@ class CurvesGeometry : public ::CurvesGeometry {
Span<float3> evaluated_positions() const;
/**
+ * Return a cache of accumulated lengths along the curve. Each item is the length of the
+ * subsequent segment (the first value is the length of the first segment rather than 0).
+ * This calculation is rather trivial, and only depends on the evaluated positions, but
+ * the results are used often, and it is necessarily single threaded per curve, so it is cached.
+ *
+ * \param cyclic: This argument is redundant with the data stored for the curve,
+ * but is passed for performance reasons to avoid looking up the attribute.
+ */
+ Span<float> evaluated_lengths_for_curve(int curve_index, bool cyclic) const;
+
+ /** Calculates the data described by #evaluated_lengths_for_curve if necessary. */
+ void ensure_evaluated_lengths() const;
+
+ /**
* Evaluate a generic data to the standard evaluated points of a specific curve,
* defined by the resolution attribute or other factors, depending on the curve type.
*
@@ -281,6 +304,9 @@ class CurvesGeometry : public ::CurvesGeometry {
*/
void ensure_nurbs_basis_cache() const;
+ /** Return the slice of #evaluated_length_cache that corresponds to this curve index. */
+ IndexRange lengths_range_for_curve(int curve_index, bool cyclic) const;
+
/* --------------------------------------------------------------------
* Operations.
*/
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 7ceaa8f0f37..c4e9a06aad0 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -11,6 +11,7 @@
#include "BLI_bounds.hh"
#include "BLI_index_mask_ops.hh"
+#include "BLI_length_parameterize.hh"
#include "DNA_curves_types.h"
@@ -721,6 +722,63 @@ void CurvesGeometry::interpolate_to_evaluated(const int curve_index,
BLI_assert_unreachable();
}
+IndexRange CurvesGeometry::lengths_range_for_curve(const int curve_index, const bool cyclic) const
+{
+ BLI_assert(cyclic == this->cyclic()[curve_index]);
+ const IndexRange points = this->evaluated_points_for_curve(curve_index);
+ const int start = points.start() + curve_index;
+ const int size = curves::curve_segment_size(points.size(), cyclic);
+ return {start, size};
+}
+
+void CurvesGeometry::ensure_evaluated_lengths() const
+{
+ if (!this->runtime->length_cache_dirty) {
+ return;
+ }
+
+ /* A double checked lock. */
+ std::scoped_lock lock{this->runtime->length_cache_mutex};
+ if (!this->runtime->length_cache_dirty) {
+ return;
+ }
+
+ threading::isolate_task([&]() {
+ /* Use an extra length value for the final cyclic segment for a consistent size
+ * (see comment on #evaluated_length_cache). */
+ const int total_size = this->evaluated_points_num() + this->curves_num();
+ this->runtime->evaluated_length_cache.resize(total_size);
+ MutableSpan<float> evaluated_lengths = this->runtime->evaluated_length_cache;
+
+ Span<float3> evaluated_positions = this->evaluated_positions();
+ VArray<bool> curves_cyclic = this->cyclic();
+
+ threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
+ for (const int curve_index : curves_range) {
+ const bool cyclic = curves_cyclic[curve_index];
+ const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
+ if (UNLIKELY(evaluated_points.is_empty())) {
+ continue;
+ }
+ const IndexRange lengths_range = this->lengths_range_for_curve(curve_index, cyclic);
+ length_parameterize::accumulate_lengths(evaluated_positions.slice(evaluated_points),
+ cyclic,
+ evaluated_lengths.slice(lengths_range));
+ }
+ });
+ });
+
+ this->runtime->length_cache_dirty = false;
+}
+
+Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,
+ const bool cyclic) const
+{
+ BLI_assert(!this->runtime->length_cache_dirty);
+ const IndexRange range = this->lengths_range_for_curve(curve_index, cyclic);
+ return this->runtime->evaluated_length_cache.as_span().slice(range);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -747,6 +805,7 @@ void CurvesGeometry::tag_positions_changed()
this->runtime->position_cache_dirty = true;
this->runtime->tangent_cache_dirty = true;
this->runtime->normal_cache_dirty = true;
+ this->runtime->length_cache_dirty = true;
}
void CurvesGeometry::tag_topology_changed()
{
@@ -755,6 +814,7 @@ void CurvesGeometry::tag_topology_changed()
this->runtime->normal_cache_dirty = true;
this->runtime->offsets_cache_dirty = true;
this->runtime->nurbs_basis_cache_dirty = true;
+ this->runtime->length_cache_dirty = true;
}
void CurvesGeometry::tag_normals_changed()
{