Blender  V3.3
spreadsheet_row_filter.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <cstring>
4 
5 #include "BLI_listbase.h"
6 
7 #include "DNA_screen_types.h"
8 #include "DNA_space_types.h"
9 
10 #include "DEG_depsgraph_query.h"
11 
12 #include "UI_interface.h"
13 #include "UI_resources.h"
14 
15 #include "RNA_access.h"
16 
18 #include "spreadsheet_intern.hh"
19 #include "spreadsheet_layout.hh"
21 
22 namespace blender::ed::spreadsheet {
23 
24 template<typename T, typename OperationFn>
26  OperationFn check_fn,
27  const IndexMask mask,
28  Vector<int64_t> &new_indices)
29 {
30  for (const int64_t i : mask) {
31  if (check_fn(data[i])) {
32  new_indices.append(i);
33  }
34  }
35 }
36 
37 static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
39  const IndexMask prev_mask,
40  Vector<int64_t> &new_indices)
41 {
42  const ColumnValues &column = *columns.lookup(row_filter.column_name);
43  const GVArray &column_data = column.data();
44  if (column_data.type().is<float>()) {
45  const float value = row_filter.value_float;
46  switch (row_filter.operation) {
48  const float threshold = row_filter.threshold;
50  column_data.typed<float>(),
51  [&](const float cell) { return std::abs(cell - value) < threshold; },
52  prev_mask,
53  new_indices);
54  break;
55  }
58  column_data.typed<float>(),
59  [&](const float cell) { return cell > value; },
60  prev_mask,
61  new_indices);
62  break;
63  }
66  column_data.typed<float>(),
67  [&](const float cell) { return cell < value; },
68  prev_mask,
69  new_indices);
70  break;
71  }
72  }
73  }
74  else if (column_data.type().is<bool>()) {
75  const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
77  column_data.typed<bool>(),
78  [&](const bool cell) { return cell == value; },
79  prev_mask,
80  new_indices);
81  }
82  else if (column_data.type().is<int8_t>()) {
83  const int value = row_filter.value_int;
84  switch (row_filter.operation) {
87  column_data.typed<int8_t>(),
88  [&](const int cell) { return cell == value; },
89  prev_mask,
90  new_indices);
91  break;
92  }
95  column_data.typed<int8_t>(),
96  [value](const int cell) { return cell > value; },
97  prev_mask,
98  new_indices);
99  break;
100  }
103  column_data.typed<int8_t>(),
104  [&](const int cell) { return cell < value; },
105  prev_mask,
106  new_indices);
107  break;
108  }
109  }
110  }
111  else if (column_data.type().is<int>()) {
112  const int value = row_filter.value_int;
113  switch (row_filter.operation) {
116  column_data.typed<int>(),
117  [&](const int cell) { return cell == value; },
118  prev_mask,
119  new_indices);
120  break;
121  }
124  column_data.typed<int>(),
125  [value](const int cell) { return cell > value; },
126  prev_mask,
127  new_indices);
128  break;
129  }
132  column_data.typed<int>(),
133  [&](const int cell) { return cell < value; },
134  prev_mask,
135  new_indices);
136  break;
137  }
138  }
139  }
140  else if (column_data.type().is<float2>()) {
141  const float2 value = row_filter.value_float2;
142  switch (row_filter.operation) {
144  const float threshold_sq = pow2f(row_filter.threshold);
146  column_data.typed<float2>(),
147  [&](const float2 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
148  prev_mask,
149  new_indices);
150  break;
151  }
154  column_data.typed<float2>(),
155  [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
156  prev_mask,
157  new_indices);
158  break;
159  }
162  column_data.typed<float2>(),
163  [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
164  prev_mask,
165  new_indices);
166  break;
167  }
168  }
169  }
170  else if (column_data.type().is<float3>()) {
171  const float3 value = row_filter.value_float3;
172  switch (row_filter.operation) {
174  const float threshold_sq = pow2f(row_filter.threshold);
176  column_data.typed<float3>(),
177  [&](const float3 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
178  prev_mask,
179  new_indices);
180  break;
181  }
184  column_data.typed<float3>(),
185  [&](const float3 cell) {
186  return cell.x > value.x && cell.y > value.y && cell.z > value.z;
187  },
188  prev_mask,
189  new_indices);
190  break;
191  }
194  column_data.typed<float3>(),
195  [&](const float3 cell) {
196  return cell.x < value.x && cell.y < value.y && cell.z < value.z;
197  },
198  prev_mask,
199  new_indices);
200  break;
201  }
202  }
203  }
204  else if (column_data.type().is<ColorGeometry4f>()) {
205  const ColorGeometry4f value = row_filter.value_color;
206  switch (row_filter.operation) {
208  const float threshold_sq = pow2f(row_filter.threshold);
210  column_data.typed<ColorGeometry4f>(),
211  [&](const ColorGeometry4f cell) {
212  return len_squared_v4v4(cell, value) <= threshold_sq;
213  },
214  prev_mask,
215  new_indices);
216  break;
217  }
220  column_data.typed<ColorGeometry4f>(),
221  [&](const ColorGeometry4f cell) {
222  return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
223  },
224  prev_mask,
225  new_indices);
226  break;
227  }
230  column_data.typed<ColorGeometry4f>(),
231  [&](const ColorGeometry4f cell) {
232  return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
233  },
234  prev_mask,
235  new_indices);
236  break;
237  }
238  }
239  }
240  else if (column_data.type().is<ColorGeometry4b>()) {
241  const ColorGeometry4f value = row_filter.value_color;
242  switch (row_filter.operation) {
244  const float4 value_floats = {
245  (float)value.r, (float)value.g, (float)value.b, (float)value.a};
246  const float threshold_sq = pow2f(row_filter.threshold);
248  column_data.typed<ColorGeometry4b>(),
249  [&](const ColorGeometry4b cell_bytes) {
250  const ColorGeometry4f cell = cell_bytes.decode();
251  const float4 cell_floats = {
252  (float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a};
253  return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq;
254  },
255  prev_mask,
256  new_indices);
257  break;
258  }
261  column_data.typed<ColorGeometry4b>(),
262  [&](const ColorGeometry4b cell_bytes) {
263  const ColorGeometry4f cell = cell_bytes.decode();
264  return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
265  },
266  prev_mask,
267  new_indices);
268  break;
269  }
272  column_data.typed<ColorGeometry4b>(),
273  [&](const ColorGeometry4b cell_bytes) {
274  const ColorGeometry4f cell = cell_bytes.decode();
275  return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
276  },
277  prev_mask,
278  new_indices);
279  break;
280  }
281  }
282  }
283  else if (column_data.type().is<InstanceReference>()) {
284  const StringRef value = row_filter.value_string;
286  column_data.typed<InstanceReference>(),
287  [&](const InstanceReference cell) {
288  switch (cell.type()) {
289  case InstanceReference::Type::Object: {
290  return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
291  }
292  case InstanceReference::Type::Collection: {
293  return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
294  }
295  case InstanceReference::Type::GeometrySet: {
296  return false;
297  }
298  case InstanceReference::Type::None: {
299  return false;
300  }
301  }
303  return false;
304  },
305  prev_mask,
306  new_indices);
307  }
308 }
309 
310 static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
311 {
312  if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_ENABLE)) {
313  return false;
314  }
315  if (BLI_listbase_is_empty(&sspreadsheet.row_filters)) {
316  return false;
317  }
318  return true;
319 }
320 
321 static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
322  const DataSource &data_source)
323 {
324  if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY)) {
325  return false;
326  }
327  if (!data_source.has_selection_filter()) {
328  return false;
329  }
330  return true;
331 }
332 
334  const SpreadsheetLayout &spreadsheet_layout,
335  const DataSource &data_source,
336  ResourceScope &scope)
337 {
338  const int tot_rows = data_source.tot_rows();
339 
340  const bool use_selection = use_selection_filter(sspreadsheet, data_source);
341  const bool use_filters = use_row_filters(sspreadsheet);
342 
343  /* Avoid allocating an array if no row filtering is necessary. */
344  if (!(use_filters || use_selection)) {
345  return IndexMask(tot_rows);
346  }
347 
348  IndexMask mask(tot_rows);
349 
350  Vector<int64_t> mask_indices;
351  mask_indices.reserve(tot_rows);
352 
353  if (use_selection) {
354  const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
355  &data_source);
356  mask = geometry_data_source->apply_selection_filter(mask_indices);
357  }
358 
359  if (use_filters) {
361  for (const ColumnLayout &column : spreadsheet_layout.columns) {
362  columns.add(column.values->name(), column.values);
363  }
364 
365  LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
366  if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
367  if (!columns.contains(row_filter->column_name)) {
368  continue;
369  }
370  Vector<int64_t> new_indices;
371  new_indices.reserve(mask_indices.size());
372  apply_row_filter(*row_filter, columns, mask, new_indices);
373  std::swap(new_indices, mask_indices);
374  mask = IndexMask(mask_indices);
375  }
376  }
377  }
378 
379  if (mask_indices.is_empty()) {
380  BLI_assert(mask.is_empty() || mask.is_range());
381  return mask;
382  }
383 
384  return IndexMask(scope.add_value(std::move(mask_indices)));
385 }
386 
388 {
389  SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__);
392  row_filter->threshold = 0.01f;
393  row_filter->column_name[0] = '\0';
394 
395  return row_filter;
396 }
397 
399 {
401 
402  memcpy(new_filter, src_row_filter, sizeof(SpreadsheetRowFilter));
403  new_filter->next = nullptr;
404  new_filter->prev = nullptr;
405 
406  return new_filter;
407 }
408 
410 {
411  MEM_SAFE_FREE(row_filter->value_string);
412  MEM_freeN(row_filter);
413 }
414 
415 } // namespace blender::ed::spreadsheet
typedef float(TangentPoint)[2]
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
MINLINE float pow2f(float x)
MINLINE float len_squared_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT
void swap(T &a, T &b)
Definition: Common.h:19
@ SPREADSHEET_ROW_FILTER_BOOL_VALUE
@ SPREADSHEET_ROW_FILTER_UI_EXPAND
@ SPREADSHEET_ROW_FILTER_ENABLED
@ SPREADSHEET_FILTER_SELECTED_ONLY
@ SPREADSHEET_FILTER_ENABLE
@ SPREADSHEET_ROW_FILTER_GREATER
@ SPREADSHEET_ROW_FILTER_EQUAL
@ SPREADSHEET_ROW_FILTER_LESS
#define MEM_SAFE_FREE(v)
bool is() const
ChannelStorageType r
Definition: BLI_color.hh:85
ChannelStorageType g
Definition: BLI_color.hh:85
ChannelStorageType b
Definition: BLI_color.hh:85
ChannelStorageType a
Definition: BLI_color.hh:85
const CPPType & type() const
VArray< T > typed() const
bool add(const Key &key, const Value &value)
Definition: BLI_map.hh:250
const Value & lookup(const Key &key) const
Definition: BLI_map.hh:485
bool contains(const Key &key) const
Definition: BLI_map.hh:308
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
bool is_empty() const
Definition: BLI_vector.hh:706
void reserve(const int64_t min_capacity)
Definition: BLI_vector.hh:340
IndexMask apply_selection_filter(Vector< int64_t > &indices) const
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
SpreadsheetRowFilter * spreadsheet_row_filter_new()
IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, const SpreadsheetLayout &spreadsheet_layout, const DataSource &data_source, ResourceScope &scope)
SpreadsheetRowFilter * spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter)
static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet, const DataSource &data_source)
static void apply_row_filter(const SpreadsheetRowFilter &row_filter, const Map< StringRef, const ColumnValues * > &columns, const IndexMask prev_mask, Vector< int64_t > &new_indices)
void spreadsheet_row_filter_free(SpreadsheetRowFilter *row_filter)
static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
static void apply_filter_operation(const VArray< T > &data, OperationFn check_fn, const IndexMask mask, Vector< int64_t > &new_indices)
__int64 int64_t
Definition: stdint.h:89
signed char int8_t
Definition: stdint.h:75
struct SpreadsheetRowFilter * prev
struct SpreadsheetRowFilter * next