GPv3: Select Alternate #109240

Merged
Falk David merged 6 commits from Lorenzo-Carpaneto/blender:gpv3-select-alternate into main 2023-06-23 11:34:06 +02:00
1 changed files with 2 additions and 8 deletions
Showing only changes of commit ecaee61f57 - Show all commits

View File

@ -288,14 +288,8 @@ void select_alternate(bke::CurvesGeometry &curves, const bool deselect_ends)
continue;
Lorenzo-Carpaneto marked this conversation as resolved Outdated

I think it make sense to avoid the indentation and continue early.

if (!has_anything_selected(selection.span.slice(points))) {
   continue;
I think it make sense to avoid the indentation and continue early. ``` if (!has_anything_selected(selection.span.slice(points))) { continue; ```
}
bool prev_selected = deselect_ends;
for (int point_i = points.first(); point_i <= points.last(); point_i++) {
if (prev_selected) {
selection_typed[point_i] = prev_selected = false;
}
else {
selection_typed[point_i] = prev_selected = true;
}
for (const int offset : IndexRange(points.size())) {
Lorenzo-Carpaneto marked this conversation as resolved Outdated

I think this loop can now be simplified:

for (const int point_i : points.index_range()) {
   selection[point_i] = (point_i % 2 == 0);
}
I think this loop can now be simplified: ``` for (const int point_i : points.index_range()) { selection[point_i] = (point_i % 2 == 0); } ```

mmm, this is not entirely right I think: the select ends param makes us start or from first or from second point... So the selection is kind of "inverted" based on this params (I am basing this fact on the older version of gp, that works like this)

mmm, this is not entirely right I think: the select ends param makes us start or from first or from second point... So the selection is kind of "inverted" based on this params (I am basing this fact on the older version of gp, that works like this)

Ah then you use (point_i % 2 == unselect_ends) instead.

Ah then you use `(point_i % 2 == unselect_ends)` instead.

It's weird, but I noticed we can't use points.index_range(), because it always starts at 0. While points.first() gives the correct offset.
So keeping
for (int point_i = points.first(); point_i <= points.last(); point_i++) {
is the right thing to do.

It's weird, but I noticed we can't use `points.index_range()`, because it always starts at `0`. While `points.first()` gives the correct offset. So keeping ` for (int point_i = points.first(); point_i <= points.last(); point_i++) {` is the right thing to do.
const int half_of_size = points.size() / 2;
const IndexRange selected = points.shift(select_ends ? 0 : 1);
const IndexRange deselected = points.shift(select_ends ? 1 : 0);
for (const int index : IndexRange(half_of_size)) {
  const int selected_index = selected[index * 2];
  const int deselected_index = deselected[index * 2];
  selection_typed[selected_index] = true;
  selection_typed[deselected_index] = false;
}
selection_typed.last() = select_ends;

Maybe something like this?

```Cpp const int half_of_size = points.size() / 2; const IndexRange selected = points.shift(select_ends ? 0 : 1); const IndexRange deselected = points.shift(select_ends ? 1 : 0); for (const int index : IndexRange(half_of_size)) { const int selected_index = selected[index * 2]; const int deselected_index = deselected[index * 2]; selection_typed[selected_index] = true; selection_typed[deselected_index] = false; } selection_typed.last() = select_ends; ``` Maybe something like this?

@mod_moder to me this seems more difficult to read than what I had originally written though...

@mod_moder to me this seems more difficult to read than what I had originally written though...

Ah then you use (point_i % 2 == unselect_ends) instead.

Are we entirely sure that the first point is always 0? Because I see that index_range has a start_ init param

> Ah then you use `(point_i % 2 == unselect_ends)` instead. Are we entirely sure that the first point is always 0? Because I see that index_range has a start_ init param

@SietseB is right, the for loop can stay as is.

@SietseB is right, the for loop can stay as is.

@Lorenzo-Carpaneto The main reason for my approach is that it is:

  • It doesn't require you to calculate each step of the loop in your head that you know the result.
  • It can be multi-threaded. Remember, these arrays can be millions of points long.
@Lorenzo-Carpaneto The main reason for my approach is that it is: - It doesn't require you to calculate each step of the loop in your head that you know the result. - It can be multi-threaded. Remember, these arrays can be millions of points long.

@mod_moder These are good motivations, but I think there might be problems with your solution.
@SietseB and @filedescriptor said that points.index_range() is not working (and that function returns: IndexRange(size_);. So I fear that your approach suffers from the same bug. So for now maybe better keep the loop as is, and as soon as we fix the problem with iteration on indexRange, we change the code

@mod_moder These are good motivations, but I think there might be problems with your solution. @SietseB and @filedescriptor said that `points.index_range()` is not working (and that function returns: `IndexRange(size_);`. So I fear that your approach suffers from the same bug. So for now maybe better keep the loop as is, and as soon as we fix the problem with iteration on indexRange, we change the code

IndexRange is iterator factory itself. If you use index_range() method, you will create new IndexRange for iterating on something. In my case, points sampled directly, look at const IndexRange selected = points.shift(select_ends ? 0 : 1);... lines.

IndexRange is iterator factory itself. If you use `index_range()` method, you will create new IndexRange for iterating on something. In my case, `points` sampled directly, look at `const IndexRange selected = points.shift(select_ends ? 0 : 1);...` lines.

I was referring to for (const int index : IndexRange(half_of_size))

I was referring to `for (const int index : IndexRange(half_of_size))`

const int selected_index = selected[index * 2];
You can sampling IndexRage to maping indices.

`const int selected_index = selected[index * 2];` You can sampling IndexRage to maping indices.

@mod_moder @HooglyBoogly I looked better at the problem that @SietseB was saying about IndexRange and I am now convinced that the solution proposed should work :) I have made the change (a bit different from suggestion but basically the same) check it out :)

@mod_moder @HooglyBoogly I looked better at the problem that @SietseB was saying about IndexRange and I am now convinced that the solution proposed should work :) I have made the change (a bit different from suggestion but basically the same) check it out :)
selection_typed[points.first() + offset] = deselect_ends ? offset % 2 : !(offset % 2);
Lorenzo-Carpaneto marked this conversation as resolved Outdated

for (const int point : points) {

`for (const int point : points) {`

We are just discussing about this in the other thread, please join in the dicussion :D

We are just discussing about this in the other thread, please join in the dicussion :D

Ah sorry, haha
Think I agree with Iliya in principle (whenever possible, better to write loops in a parallel way, so they have no dependence on the previous iteration)

Ah sorry, haha Think I agree with Iliya in principle (whenever possible, better to write loops in a parallel way, so they have no dependence on the previous iteration)
for (const int index : points.index_range()) {
  selection_typed[points[index]] = deselect_ends ? index % 2 : !(index % 2);

This one is exactly the same

```Cpp for (const int index : points.index_range()) { selection_typed[points[index]] = deselect_ends ? index % 2 : !(index % 2); ``` This one is exactly the same

According to @SietseB (previous comment in the other thread)

It's weird, but I noticed we can't use points.index_range(), because it always starts at 0. While points.first() gives the correct offset.

This way should avoid this problem (cause we need to start from 0)

According to @SietseB (previous comment in the other thread) ``` It's weird, but I noticed we can't use points.index_range(), because it always starts at 0. While points.first() gives the correct offset. ``` This way should avoid this problem (cause we need to start from 0)

IndexRange(points.size()) == points.index_range()
points.first() + 0..1..2... == points[0...1...2...]

`IndexRange(points.size())` == `points.index_range()` `points.first() + 0..1..2...` == `points[0...1...2...]`

Ah, you are totally right, pushing the proposed version, it's a bit more readable and efficient :)

Ah, you are totally right, pushing the proposed version, it's a bit more readable and efficient :)
}
if (cyclic[curve_i]) {