Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenlib/BLI_length_parameterize.hh
- This file was added.
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | |||||
| #pragma once | |||||
| /** \file | |||||
| * \ingroup bli | |||||
| */ | |||||
| #include "BLI_math_base.hh" | |||||
| #include "BLI_math_color.hh" | |||||
| #include "BLI_math_vector.hh" | |||||
| #include "BLI_vector.hh" | |||||
| namespace blender::length_parameterize { | |||||
| /** | |||||
| * Return the size of the necessary lengths array for a group of points, taking into account the | |||||
| * possible last cyclic segment. | |||||
| * | |||||
| * \note This is the same as #bke::curves::curve_segment_size. | |||||
| */ | |||||
| inline int lengths_num(const int points_num, const bool cyclic) | |||||
| { | |||||
| return (cyclic && points_num > 2) ? points_num : points_num - 1; | |||||
| } | |||||
JacquesLucke: I think it is not obvious that a curve cannot be cyclic when it only has two points. I don't… | |||||
Done Inline ActionsI think I was copying the logic from existing curve code, but I also can't think of a fundamental reason, at this level. HooglyBoogly: I think I was copying the logic from existing curve code, but I also can't think of a… | |||||
Done Inline ActionsWell, there are always ways to visualize it. We could just use the arrows that you see when adjusting the tilt. Then better mention that reason in a comment. JacquesLucke: Well, there are always ways to visualize it. We could just use the arrows that you see when… | |||||
Done Inline ActionsHonestly I don't remember the reasoning well enough to document it. I'll just remove that 2 point check for now I think. If it becomes a problem we can add it back. HooglyBoogly: Honestly I don't remember the reasoning well enough to document it. I'll just remove that 2… | |||||
| /** | |||||
| * Accumulate the length of the next segment into each point. | |||||
| */ | |||||
| template<typename T> | |||||
| void accumulate_lengths(const Span<T> values, const bool cyclic, MutableSpan<float> lengths) | |||||
| { | |||||
| BLI_assert(lengths.size() == lengths_num(values.size(), cyclic)); | |||||
| float length = 0.0f; | |||||
| for (const int i : IndexRange(values.size() - 1)) { | |||||
| length += math::distance(values[i], values[i + 1]); | |||||
| lengths[i] = length; | |||||
| } | |||||
| if (cyclic) { | |||||
| lengths.last() = length + math::distance(values.last(), values.first()); | |||||
| } | |||||
| } | |||||
| struct ResultSamples { | |||||
| /** | |||||
| * The index of the sample's previous point. Note that this and #factors don't include | |||||
| * the first result point, which always copies the value of the first source point. | |||||
| */ | |||||
| Vector<int> indices; | |||||
| /** The sample's factor from the previous point to the next point. */ | |||||
| Vector<float> factors; | |||||
| /** Sample factors for the last cyclic segment connecting the first and last point. */ | |||||
| Vector<float> cyclic_samples; | |||||
| bool cyclic; | |||||
| #ifdef DEBUG | |||||
| int src_points_size; | |||||
| #endif | |||||
| /* Do linear interpolation of the values from the samples' neighboring points. */ | |||||
| template<typename T> void interpolate_linear(const Span<T> src, MutableSpan<T> dst) const | |||||
| { | |||||
| #ifdef DEBUG | |||||
| BLI_assert(src.size() == this->src_points_size); | |||||
| #endif | |||||
| dst.first() = src.first(); | |||||
| dst = dst.drop_front(1); | |||||
| if (cyclic) { | |||||
| for (const int i : this->indices.index_range()) { | |||||
| const int index = this->indices[i]; | |||||
| const float factor = this->factors[i]; | |||||
| dst[i] = math::interpolate(src[index], src[index + 1], factor); | |||||
| } | |||||
| MutableSpan<T> cyclic_results = dst.take_back(cyclic_samples.size()); | |||||
| for (const int i : cyclic_samples.index_range()) { | |||||
| cyclic_results[i] = math::interpolate(src.last(), src.first(), cyclic_samples[i]); | |||||
| } | |||||
| } | |||||
| else { | |||||
| for (const int i : this->indices.index_range()) { | |||||
| const int index = this->indices[i]; | |||||
| const float factor = this->factors[i]; | |||||
| dst[i] = math::interpolate(src[index], src[index + 1], factor); | |||||
| } | |||||
| dst.last() = src.last(); | |||||
| } | |||||
| } | |||||
| }; | |||||
| /** | |||||
| * Find the given number of points, evenly spaced along the provided length. For non-cyclic | |||||
| * sequences, the first and last point will always be included, for cyclic sequences, the first | |||||
| * point will always be included. | |||||
Done Inline ActionsEven when count is zero or one? JacquesLucke: Even when `count` is zero or one? | |||||
Done Inline ActionsGood point, I adjusted the comment. And the function expects the count to be greater than zero so I added that too. HooglyBoogly: Good point, I adjusted the comment. And the function expects the count to be greater than zero… | |||||
| */ | |||||
| void create_uniform_samples(Span<float> lengths, | |||||
| const bool cyclic, | |||||
| const int count, | |||||
| ResultSamples &result); | |||||
| } // namespace blender::length_parameterize | |||||
I think it is not obvious that a curve cannot be cyclic when it only has two points. I don't see a fundamental reason for why this should be the case. If there is a reason for this behavior, it should be mentioned here.