Blender V5.0
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_color.hh"
8#include "BLI_listbase.h"
9#include "BLI_math_vector.hh"
10
11#include "DNA_space_types.h"
12
13#include "BKE_instances.hh"
14
16#include "spreadsheet_layout.hh"
18
20
21template<typename T, typename OperationFn>
23 OperationFn check_fn,
24 const IndexMask &mask,
25 IndexMaskMemory &memory)
26{
28 mask, GrainSize(1024), memory, [&](const int64_t i) { return check_fn(data[i]); });
29}
30
33 const IndexMask &prev_mask,
34 IndexMaskMemory &memory)
35{
36 const ColumnValues &column = *columns.lookup(row_filter.column_name);
37 const GVArray &column_data = column.data();
38 if (column_data.type().is<float>()) {
39 const float value = row_filter.value_float;
40 switch (row_filter.operation) {
42 const float threshold = row_filter.threshold;
44 column_data.typed<float>(),
45 [&](const float cell) { return std::abs(cell - value) < threshold; },
46 prev_mask,
47 memory);
48 }
51 column_data.typed<float>(),
52 [&](const float cell) { return cell > value; },
53 prev_mask,
54 memory);
55 }
58 column_data.typed<float>(),
59 [&](const float cell) { return cell < value; },
60 prev_mask,
61 memory);
62 }
63 }
64 }
65 else if (column_data.type().is<bool>()) {
66 const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
68 column_data.typed<bool>(),
69 [&](const bool cell) { return cell == value; },
70 prev_mask,
71 memory);
72 }
73 else if (column_data.type().is<int8_t>()) {
74 const int value = row_filter.value_int;
75 switch (row_filter.operation) {
78 column_data.typed<int8_t>(),
79 [&](const int cell) { return cell == value; },
80 prev_mask,
81 memory);
82 }
85 column_data.typed<int8_t>(),
86 [value](const int cell) { return cell > value; },
87 prev_mask,
88 memory);
89 }
92 column_data.typed<int8_t>(),
93 [&](const int cell) { return cell < value; },
94 prev_mask,
95 memory);
96 }
97 }
98 }
99 else if (column_data.type().is<int>()) {
100 const int value = row_filter.value_int;
101 switch (row_filter.operation) {
104 column_data.typed<int>(),
105 [&](const int cell) { return cell == value; },
106 prev_mask,
107 memory);
108 }
111 column_data.typed<int>(),
112 [value](const int cell) { return cell > value; },
113 prev_mask,
114 memory);
115 }
118 column_data.typed<int>(),
119 [&](const int cell) { return cell < value; },
120 prev_mask,
121 memory);
122 }
123 }
124 }
125 else if (column_data.type().is<int64_t>()) {
126 const int64_t value = row_filter.value_int;
127 switch (row_filter.operation) {
130 column_data.typed<int64_t>(),
131 [&](const int64_t cell) { return cell == value; },
132 prev_mask,
133 memory);
134 }
137 column_data.typed<int64_t>(),
138 [value](const int64_t cell) { return cell > value; },
139 prev_mask,
140 memory);
141 }
144 column_data.typed<int64_t>(),
145 [&](const int64_t cell) { return cell < value; },
146 prev_mask,
147 memory);
148 }
149 }
150 }
151 else if (column_data.type().is<int2>()) {
152 const int2 value = row_filter.value_int2;
153 switch (row_filter.operation) {
156 column_data.typed<int2>(),
157 [&](const int2 cell) { return cell == value; },
158 prev_mask,
159 memory);
160 }
163 column_data.typed<int2>(),
164 [&](const int2 cell) { return cell.x > value.x && cell.y > value.y; },
165 prev_mask,
166 memory);
167 }
170 column_data.typed<int2>(),
171 [&](const int2 cell) { return cell.x < value.x && cell.y < value.y; },
172 prev_mask,
173 memory);
174 }
175 }
176 }
177 else if (column_data.type().is<int3>()) {
178 const int3 value = row_filter.value_int3;
179 switch (row_filter.operation) {
182 column_data.typed<int3>(),
183 [&](const int3 cell) { return cell == value; },
184 prev_mask,
185 memory);
186 }
189 column_data.typed<int3>(),
190 [&](const int3 cell) {
191 return cell.x > value.x && cell.y > value.y && cell.z > value.z;
192 },
193 prev_mask,
194 memory);
195 }
198 column_data.typed<int3>(),
199 [&](const int3 cell) {
200 return cell.x < value.x && cell.y < value.y && cell.z < value.z;
201 },
202 prev_mask,
203 memory);
204 }
205 }
206 }
207 else if (column_data.type().is<short2>()) {
208 const short2 value = short2(int2(row_filter.value_int2));
209 switch (row_filter.operation) {
212 column_data.typed<short2>(),
213 [&](const short2 cell) { return cell == value; },
214 prev_mask,
215 memory);
216 }
219 column_data.typed<short2>(),
220 [&](const short2 cell) { return cell.x > value.x && cell.y > value.y; },
221 prev_mask,
222 memory);
223 }
226 column_data.typed<short2>(),
227 [&](const short2 cell) { return cell.x < value.x && cell.y < value.y; },
228 prev_mask,
229 memory);
230 }
231 }
232 }
233 else if (column_data.type().is<float2>()) {
234 const float2 value = row_filter.value_float2;
235 switch (row_filter.operation) {
237 const float threshold_sq = pow2f(row_filter.threshold);
239 column_data.typed<float2>(),
240 [&](const float2 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
241 prev_mask,
242 memory);
243 }
246 column_data.typed<float2>(),
247 [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
248 prev_mask,
249 memory);
250 }
253 column_data.typed<float2>(),
254 [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
255 prev_mask,
256 memory);
257 }
258 }
259 }
260 else if (column_data.type().is<float3>()) {
261 const float3 value = row_filter.value_float3;
262 switch (row_filter.operation) {
264 const float threshold_sq = pow2f(row_filter.threshold);
266 column_data.typed<float3>(),
267 [&](const float3 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
268 prev_mask,
269 memory);
270 }
273 column_data.typed<float3>(),
274 [&](const float3 cell) {
275 return cell.x > value.x && cell.y > value.y && cell.z > value.z;
276 },
277 prev_mask,
278 memory);
279 }
282 column_data.typed<float3>(),
283 [&](const float3 cell) {
284 return cell.x < value.x && cell.y < value.y && cell.z < value.z;
285 },
286 prev_mask,
287 memory);
288 }
289 }
290 }
291 else if (column_data.type().is<ColorGeometry4f>()) {
292 const ColorGeometry4f value = row_filter.value_color;
293 switch (row_filter.operation) {
295 const float threshold_sq = pow2f(row_filter.threshold);
297 column_data.typed<ColorGeometry4f>(),
298 [&](const ColorGeometry4f cell) {
299 return math::distance_squared(float4(cell), float4(value)) <= threshold_sq;
300 },
301 prev_mask,
302 memory);
303 }
306 column_data.typed<ColorGeometry4f>(),
307 [&](const ColorGeometry4f cell) {
308 return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
309 },
310 prev_mask,
311 memory);
312 }
315 column_data.typed<ColorGeometry4f>(),
316 [&](const ColorGeometry4f cell) {
317 return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
318 },
319 prev_mask,
320 memory);
321 }
322 }
323 }
324 else if (column_data.type().is<ColorGeometry4b>()) {
325 const ColorGeometry4f value = row_filter.value_color;
326 switch (row_filter.operation) {
328 const float4 value_floats = {
329 float(value.r), float(value.g), float(value.b), float(value.a)};
330 const float threshold_sq = pow2f(row_filter.threshold);
332 column_data.typed<ColorGeometry4b>(),
333 [&](const ColorGeometry4b cell_bytes) {
334 const ColorGeometry4f cell = color::decode(cell_bytes);
335 const float4 cell_floats = {
336 float(cell.r), float(cell.g), float(cell.b), float(cell.a)};
337 return math::distance_squared(value_floats, cell_floats) <= threshold_sq;
338 },
339 prev_mask,
340 memory);
341 }
344 column_data.typed<ColorGeometry4b>(),
345 [&](const ColorGeometry4b cell_bytes) {
346 const ColorGeometry4f cell = color::decode(cell_bytes);
347 return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
348 },
349 prev_mask,
350 memory);
351 }
354 column_data.typed<ColorGeometry4b>(),
355 [&](const ColorGeometry4b cell_bytes) {
356 const ColorGeometry4f cell = color::decode(cell_bytes);
357 return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
358 },
359 prev_mask,
360 memory);
361 }
362 }
363 }
364 else if (column_data.type().is<bke::InstanceReference>()) {
365 const StringRef value = row_filter.value_string;
367 column_data.typed<bke::InstanceReference>(),
368 [&](const bke::InstanceReference cell) {
369 switch (cell.type()) {
370 case bke::InstanceReference::Type::Object: {
371 return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
372 }
373 case bke::InstanceReference::Type::Collection: {
374 return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
375 }
376 case bke::InstanceReference::Type::GeometrySet: {
377 return value == cell.geometry_set().name;
378 }
379 case bke::InstanceReference::Type::None: {
380 return false;
381 }
382 }
384 return false;
385 },
386 prev_mask,
387 memory);
388 }
389 return prev_mask;
390}
391
392static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
393{
394 if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_ENABLE)) {
395 return false;
396 }
397 if (BLI_listbase_is_empty(&sspreadsheet.row_filters)) {
398 return false;
399 }
400 return true;
401}
402
403static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
404 const DataSource &data_source)
405{
406 if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY)) {
407 return false;
408 }
409 if (!data_source.has_selection_filter()) {
410 return false;
411 }
412 return true;
413}
414
416 const SpreadsheetLayout &spreadsheet_layout,
417 const DataSource &data_source,
418 ResourceScope &scope)
419{
420 const int tot_rows = data_source.tot_rows();
421
422 const bool use_selection = use_selection_filter(sspreadsheet, data_source);
423 const bool use_filters = use_row_filters(sspreadsheet);
424
425 /* Avoid allocating an array if no row filtering is necessary. */
426 if (!(use_filters || use_selection)) {
427 return IndexMask(tot_rows);
428 }
429
430 IndexMaskMemory &mask_memory = scope.construct<IndexMaskMemory>();
431 IndexMask mask(tot_rows);
432
433 if (use_selection) {
434 const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
435 &data_source);
436 mask = geometry_data_source->apply_selection_filter(mask_memory);
437 }
438
439 if (use_filters) {
441 for (const ColumnLayout &column : spreadsheet_layout.columns) {
442 columns.add(column.values->name(), column.values);
443 }
444
445 LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
446 if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
447 if (!columns.contains(row_filter->column_name)) {
448 continue;
449 }
450 mask = apply_row_filter(*row_filter, columns, mask, mask_memory);
451 }
452 }
453 }
454
455 return mask;
456}
457
459{
463 row_filter->threshold = 0.01f;
464 row_filter->column_name[0] = '\0';
465
466 return row_filter;
467}
468
470{
472
473 memcpy(new_filter, src_row_filter, sizeof(SpreadsheetRowFilter));
474 new_filter->next = nullptr;
475 new_filter->prev = nullptr;
476
477 return new_filter;
478}
479
481{
482 MEM_SAFE_FREE(row_filter->value_string);
483 MEM_freeN(row_filter);
484}
485
486} // namespace blender::ed::spreadsheet
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
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)
BMesh const char void * data
long long int int64_t
bool is() const
ChannelStorageType r
ChannelStorageType g
ChannelStorageType b
ChannelStorageType a
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
bool contains(const Key &key) const
Definition BLI_map.hh:353
T & construct(Args &&...args)
IndexMask apply_selection_filter(IndexMaskMemory &memory) const
nullptr float
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 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)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
blender::VecBase< int16_t, 2 > short2
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
struct SpreadsheetRowFilter * prev
struct SpreadsheetRowFilter * next
i
Definition text_draw.cc:230