Blender V4.3
spreadsheet_row_filter.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <cstring>
6
7#include "BLI_listbase.h"
8#include "BLI_math_color.hh"
9#include "BLI_math_matrix.hh"
10
11#include "DNA_screen_types.h"
12#include "DNA_space_types.h"
13
15
16#include "UI_interface.hh"
17#include "UI_resources.hh"
18
19#include "RNA_access.hh"
20
21#include "BKE_instances.hh"
22
24#include "spreadsheet_intern.hh"
25#include "spreadsheet_layout.hh"
27
29
30template<typename T, typename OperationFn>
32 OperationFn check_fn,
33 const IndexMask &mask,
34 IndexMaskMemory &memory)
35{
37 mask, GrainSize(1024), memory, [&](const int64_t i) { return check_fn(data[i]); });
38}
39
42 const IndexMask prev_mask,
43 IndexMaskMemory &memory)
44{
45 const ColumnValues &column = *columns.lookup(row_filter.column_name);
46 const GVArray &column_data = column.data();
47 if (column_data.type().is<float>()) {
48 const float value = row_filter.value_float;
49 switch (row_filter.operation) {
51 const float threshold = row_filter.threshold;
53 column_data.typed<float>(),
54 [&](const float cell) { return std::abs(cell - value) < threshold; },
55 prev_mask,
56 memory);
57 }
60 column_data.typed<float>(),
61 [&](const float cell) { return cell > value; },
62 prev_mask,
63 memory);
64 break;
65 }
68 column_data.typed<float>(),
69 [&](const float cell) { return cell < value; },
70 prev_mask,
71 memory);
72 break;
73 }
74 }
75 }
76 else if (column_data.type().is<bool>()) {
77 const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
79 column_data.typed<bool>(),
80 [&](const bool cell) { return cell == value; },
81 prev_mask,
82 memory);
83 }
84 else if (column_data.type().is<int8_t>()) {
85 const int value = row_filter.value_int;
86 switch (row_filter.operation) {
89 column_data.typed<int8_t>(),
90 [&](const int cell) { return cell == value; },
91 prev_mask,
92 memory);
93 break;
94 }
97 column_data.typed<int8_t>(),
98 [value](const int cell) { return cell > value; },
99 prev_mask,
100 memory);
101 break;
102 }
105 column_data.typed<int8_t>(),
106 [&](const int cell) { return cell < value; },
107 prev_mask,
108 memory);
109 break;
110 }
111 }
112 }
113 else if (column_data.type().is<int>()) {
114 const int value = row_filter.value_int;
115 switch (row_filter.operation) {
118 column_data.typed<int>(),
119 [&](const int cell) { return cell == value; },
120 prev_mask,
121 memory);
122 break;
123 }
126 column_data.typed<int>(),
127 [value](const int cell) { return cell > value; },
128 prev_mask,
129 memory);
130 break;
131 }
134 column_data.typed<int>(),
135 [&](const int cell) { return cell < value; },
136 prev_mask,
137 memory);
138 break;
139 }
140 }
141 }
142 else if (column_data.type().is<int2>()) {
143 const int2 value = row_filter.value_int2;
144 switch (row_filter.operation) {
146 const float threshold_sq = pow2f(row_filter.threshold);
148 column_data.typed<int2>(),
149 [&](const int2 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
150 prev_mask,
151 memory);
152 break;
153 }
156 column_data.typed<int2>(),
157 [&](const int2 cell) { return cell.x > value.x && cell.y > value.y; },
158 prev_mask,
159 memory);
160 break;
161 }
164 column_data.typed<int2>(),
165 [&](const int2 cell) { return cell.x < value.x && cell.y < value.y; },
166 prev_mask,
167 memory);
168 break;
169 }
170 }
171 }
172 else if (column_data.type().is<float2>()) {
173 const float2 value = row_filter.value_float2;
174 switch (row_filter.operation) {
176 const float threshold_sq = pow2f(row_filter.threshold);
178 column_data.typed<float2>(),
179 [&](const float2 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
180 prev_mask,
181 memory);
182 break;
183 }
186 column_data.typed<float2>(),
187 [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
188 prev_mask,
189 memory);
190 break;
191 }
194 column_data.typed<float2>(),
195 [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
196 prev_mask,
197 memory);
198 break;
199 }
200 }
201 }
202 else if (column_data.type().is<float3>()) {
203 const float3 value = row_filter.value_float3;
204 switch (row_filter.operation) {
206 const float threshold_sq = pow2f(row_filter.threshold);
208 column_data.typed<float3>(),
209 [&](const float3 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
210 prev_mask,
211 memory);
212 break;
213 }
216 column_data.typed<float3>(),
217 [&](const float3 cell) {
218 return cell.x > value.x && cell.y > value.y && cell.z > value.z;
219 },
220 prev_mask,
221 memory);
222 break;
223 }
226 column_data.typed<float3>(),
227 [&](const float3 cell) {
228 return cell.x < value.x && cell.y < value.y && cell.z < value.z;
229 },
230 prev_mask,
231 memory);
232 break;
233 }
234 }
235 }
236 else if (column_data.type().is<ColorGeometry4f>()) {
237 const ColorGeometry4f value = row_filter.value_color;
238 switch (row_filter.operation) {
240 const float threshold_sq = pow2f(row_filter.threshold);
242 column_data.typed<ColorGeometry4f>(),
243 [&](const ColorGeometry4f cell) {
244 return math::distance_squared(float4(cell), float4(value)) <= threshold_sq;
245 },
246 prev_mask,
247 memory);
248 break;
249 }
252 column_data.typed<ColorGeometry4f>(),
253 [&](const ColorGeometry4f cell) {
254 return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
255 },
256 prev_mask,
257 memory);
258 break;
259 }
262 column_data.typed<ColorGeometry4f>(),
263 [&](const ColorGeometry4f cell) {
264 return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
265 },
266 prev_mask,
267 memory);
268 break;
269 }
270 }
271 }
272 else if (column_data.type().is<ColorGeometry4b>()) {
273 const ColorGeometry4f value = row_filter.value_color;
274 switch (row_filter.operation) {
276 const float4 value_floats = {
277 float(value.r), float(value.g), float(value.b), float(value.a)};
278 const float threshold_sq = pow2f(row_filter.threshold);
280 column_data.typed<ColorGeometry4b>(),
281 [&](const ColorGeometry4b cell_bytes) {
282 const ColorGeometry4f cell = cell_bytes.decode();
283 const float4 cell_floats = {
284 float(cell.r), float(cell.g), float(cell.b), float(cell.a)};
285 return math::distance_squared(value_floats, cell_floats) <= threshold_sq;
286 },
287 prev_mask,
288 memory);
289 break;
290 }
293 column_data.typed<ColorGeometry4b>(),
294 [&](const ColorGeometry4b cell_bytes) {
295 const ColorGeometry4f cell = cell_bytes.decode();
296 return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
297 },
298 prev_mask,
299 memory);
300 break;
301 }
304 column_data.typed<ColorGeometry4b>(),
305 [&](const ColorGeometry4b cell_bytes) {
306 const ColorGeometry4f cell = cell_bytes.decode();
307 return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
308 },
309 prev_mask,
310 memory);
311 break;
312 }
313 }
314 }
315 else if (column_data.type().is<bke::InstanceReference>()) {
316 const StringRef value = row_filter.value_string;
318 column_data.typed<bke::InstanceReference>(),
319 [&](const bke::InstanceReference cell) {
320 switch (cell.type()) {
321 case bke::InstanceReference::Type::Object: {
322 return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
323 }
324 case bke::InstanceReference::Type::Collection: {
325 return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
326 }
327 case bke::InstanceReference::Type::GeometrySet: {
328 return false;
329 }
330 case bke::InstanceReference::Type::None: {
331 return false;
332 }
333 }
335 return false;
336 },
337 prev_mask,
338 memory);
339 }
340 return prev_mask;
341}
342
343static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
344{
345 if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_ENABLE)) {
346 return false;
347 }
348 if (BLI_listbase_is_empty(&sspreadsheet.row_filters)) {
349 return false;
350 }
351 return true;
352}
353
354static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
355 const DataSource &data_source)
356{
357 if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY)) {
358 return false;
359 }
360 if (!data_source.has_selection_filter()) {
361 return false;
362 }
363 return true;
364}
365
367 const SpreadsheetLayout &spreadsheet_layout,
368 const DataSource &data_source,
369 ResourceScope &scope)
370{
371 const int tot_rows = data_source.tot_rows();
372
373 const bool use_selection = use_selection_filter(sspreadsheet, data_source);
374 const bool use_filters = use_row_filters(sspreadsheet);
375
376 /* Avoid allocating an array if no row filtering is necessary. */
377 if (!(use_filters || use_selection)) {
378 return IndexMask(tot_rows);
379 }
380
381 IndexMaskMemory &mask_memory = scope.construct<IndexMaskMemory>();
382 IndexMask mask(tot_rows);
383
384 if (use_selection) {
385 const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
386 &data_source);
387 mask = geometry_data_source->apply_selection_filter(mask_memory);
388 }
389
390 if (use_filters) {
392 for (const ColumnLayout &column : spreadsheet_layout.columns) {
393 columns.add(column.values->name(), column.values);
394 }
395
396 LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
397 if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
398 if (!columns.contains(row_filter->column_name)) {
399 continue;
400 }
401 mask = apply_row_filter(*row_filter, columns, mask, mask_memory);
402 }
403 }
404 }
405
406 return mask;
407}
408
410{
411 SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__);
414 row_filter->threshold = 0.01f;
415 row_filter->column_name[0] = '\0';
416
417 return row_filter;
418}
419
421{
423
424 memcpy(new_filter, src_row_filter, sizeof(SpreadsheetRowFilter));
425 new_filter->next = nullptr;
426 new_filter->prev = nullptr;
427
428 return new_filter;
429}
430
432{
433 MEM_SAFE_FREE(row_filter->value_string);
434 MEM_freeN(row_filter);
435}
436
437} // namespace blender::ed::spreadsheet
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
MINLINE float pow2f(float x)
@ 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
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
bool contains(const Key &key) const
Definition BLI_map.hh:329
T & construct(Args &&...args)
IndexMask apply_selection_filter(IndexMaskMemory &memory) const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float4 mask(const int4 mask, const float4 a)
SpreadsheetRowFilter * spreadsheet_row_filter_new()
IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, const SpreadsheetLayout &spreadsheet_layout, const DataSource &data_source, ResourceScope &scope)
static IndexMask apply_filter_operation(const VArray< T > &data, OperationFn check_fn, const IndexMask &mask, IndexMaskMemory &memory)
SpreadsheetRowFilter * spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter)
static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet, const DataSource &data_source)
void spreadsheet_row_filter_free(SpreadsheetRowFilter *row_filter)
static IndexMask apply_row_filter(const SpreadsheetRowFilter &row_filter, const Map< StringRef, const ColumnValues * > &columns, const IndexMask prev_mask, IndexMaskMemory &memory)
static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
__int64 int64_t
Definition stdint.h:89
signed char int8_t
Definition stdint.h:75
struct SpreadsheetRowFilter * prev
struct SpreadsheetRowFilter * next