Blender V4.5
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_vector.hh"
9
10#include "DNA_space_types.h"
11
12#include "BKE_instances.hh"
13
15#include "spreadsheet_layout.hh"
17
19
20template<typename T, typename OperationFn>
22 OperationFn check_fn,
23 const IndexMask &mask,
24 IndexMaskMemory &memory)
25{
27 mask, GrainSize(1024), memory, [&](const int64_t i) { return check_fn(data[i]); });
28}
29
32 const IndexMask &prev_mask,
33 IndexMaskMemory &memory)
34{
35 const ColumnValues &column = *columns.lookup(row_filter.column_name);
36 const GVArray &column_data = column.data();
37 if (column_data.type().is<float>()) {
38 const float value = row_filter.value_float;
39 switch (row_filter.operation) {
41 const float threshold = row_filter.threshold;
43 column_data.typed<float>(),
44 [&](const float cell) { return std::abs(cell - value) < threshold; },
45 prev_mask,
46 memory);
47 }
50 column_data.typed<float>(),
51 [&](const float cell) { return cell > value; },
52 prev_mask,
53 memory);
54 }
57 column_data.typed<float>(),
58 [&](const float cell) { return cell < value; },
59 prev_mask,
60 memory);
61 }
62 }
63 }
64 else if (column_data.type().is<bool>()) {
65 const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
67 column_data.typed<bool>(),
68 [&](const bool cell) { return cell == value; },
69 prev_mask,
70 memory);
71 }
72 else if (column_data.type().is<int8_t>()) {
73 const int value = row_filter.value_int;
74 switch (row_filter.operation) {
77 column_data.typed<int8_t>(),
78 [&](const int cell) { return cell == value; },
79 prev_mask,
80 memory);
81 }
84 column_data.typed<int8_t>(),
85 [value](const int cell) { return cell > value; },
86 prev_mask,
87 memory);
88 }
91 column_data.typed<int8_t>(),
92 [&](const int cell) { return cell < value; },
93 prev_mask,
94 memory);
95 }
96 }
97 }
98 else if (column_data.type().is<int>()) {
99 const int value = row_filter.value_int;
100 switch (row_filter.operation) {
103 column_data.typed<int>(),
104 [&](const int cell) { return cell == value; },
105 prev_mask,
106 memory);
107 }
110 column_data.typed<int>(),
111 [value](const int cell) { return cell > value; },
112 prev_mask,
113 memory);
114 }
117 column_data.typed<int>(),
118 [&](const int cell) { return cell < value; },
119 prev_mask,
120 memory);
121 }
122 }
123 }
124 else if (column_data.type().is<int2>()) {
125 const int2 value = row_filter.value_int2;
126 switch (row_filter.operation) {
129 column_data.typed<int2>(),
130 [&](const int2 cell) { return cell == value; },
131 prev_mask,
132 memory);
133 }
136 column_data.typed<int2>(),
137 [&](const int2 cell) { return cell.x > value.x && cell.y > value.y; },
138 prev_mask,
139 memory);
140 }
143 column_data.typed<int2>(),
144 [&](const int2 cell) { return cell.x < value.x && cell.y < value.y; },
145 prev_mask,
146 memory);
147 }
148 }
149 }
150 else if (column_data.type().is<short2>()) {
151 const short2 value = short2(int2(row_filter.value_int2));
152 switch (row_filter.operation) {
155 column_data.typed<short2>(),
156 [&](const short2 cell) { return cell == value; },
157 prev_mask,
158 memory);
159 }
162 column_data.typed<short2>(),
163 [&](const short2 cell) { return cell.x > value.x && cell.y > value.y; },
164 prev_mask,
165 memory);
166 }
169 column_data.typed<short2>(),
170 [&](const short2 cell) { return cell.x < value.x && cell.y < value.y; },
171 prev_mask,
172 memory);
173 }
174 }
175 }
176 else if (column_data.type().is<float2>()) {
177 const float2 value = row_filter.value_float2;
178 switch (row_filter.operation) {
180 const float threshold_sq = pow2f(row_filter.threshold);
182 column_data.typed<float2>(),
183 [&](const float2 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
184 prev_mask,
185 memory);
186 }
189 column_data.typed<float2>(),
190 [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
191 prev_mask,
192 memory);
193 }
196 column_data.typed<float2>(),
197 [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
198 prev_mask,
199 memory);
200 }
201 }
202 }
203 else if (column_data.type().is<float3>()) {
204 const float3 value = row_filter.value_float3;
205 switch (row_filter.operation) {
207 const float threshold_sq = pow2f(row_filter.threshold);
209 column_data.typed<float3>(),
210 [&](const float3 cell) { return math::distance_squared(cell, value) <= threshold_sq; },
211 prev_mask,
212 memory);
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 }
225 column_data.typed<float3>(),
226 [&](const float3 cell) {
227 return cell.x < value.x && cell.y < value.y && cell.z < value.z;
228 },
229 prev_mask,
230 memory);
231 }
232 }
233 }
234 else if (column_data.type().is<ColorGeometry4f>()) {
235 const ColorGeometry4f value = row_filter.value_color;
236 switch (row_filter.operation) {
238 const float threshold_sq = pow2f(row_filter.threshold);
240 column_data.typed<ColorGeometry4f>(),
241 [&](const ColorGeometry4f cell) {
242 return math::distance_squared(float4(cell), float4(value)) <= threshold_sq;
243 },
244 prev_mask,
245 memory);
246 }
249 column_data.typed<ColorGeometry4f>(),
250 [&](const ColorGeometry4f cell) {
251 return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
252 },
253 prev_mask,
254 memory);
255 }
258 column_data.typed<ColorGeometry4f>(),
259 [&](const ColorGeometry4f cell) {
260 return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
261 },
262 prev_mask,
263 memory);
264 }
265 }
266 }
267 else if (column_data.type().is<ColorGeometry4b>()) {
268 const ColorGeometry4f value = row_filter.value_color;
269 switch (row_filter.operation) {
271 const float4 value_floats = {
272 float(value.r), float(value.g), float(value.b), float(value.a)};
273 const float threshold_sq = pow2f(row_filter.threshold);
275 column_data.typed<ColorGeometry4b>(),
276 [&](const ColorGeometry4b cell_bytes) {
277 const ColorGeometry4f cell = cell_bytes.decode();
278 const float4 cell_floats = {
279 float(cell.r), float(cell.g), float(cell.b), float(cell.a)};
280 return math::distance_squared(value_floats, cell_floats) <= threshold_sq;
281 },
282 prev_mask,
283 memory);
284 }
287 column_data.typed<ColorGeometry4b>(),
288 [&](const ColorGeometry4b cell_bytes) {
289 const ColorGeometry4f cell = cell_bytes.decode();
290 return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
291 },
292 prev_mask,
293 memory);
294 }
297 column_data.typed<ColorGeometry4b>(),
298 [&](const ColorGeometry4b cell_bytes) {
299 const ColorGeometry4f cell = cell_bytes.decode();
300 return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
301 },
302 prev_mask,
303 memory);
304 }
305 }
306 }
307 else if (column_data.type().is<bke::InstanceReference>()) {
308 const StringRef value = row_filter.value_string;
310 column_data.typed<bke::InstanceReference>(),
311 [&](const bke::InstanceReference cell) {
312 switch (cell.type()) {
313 case bke::InstanceReference::Type::Object: {
314 return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
315 }
316 case bke::InstanceReference::Type::Collection: {
317 return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
318 }
319 case bke::InstanceReference::Type::GeometrySet: {
320 return value == cell.geometry_set().name;
321 }
322 case bke::InstanceReference::Type::None: {
323 return false;
324 }
325 }
327 return false;
328 },
329 prev_mask,
330 memory);
331 }
332 return prev_mask;
333}
334
335static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
336{
337 if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_ENABLE)) {
338 return false;
339 }
340 if (BLI_listbase_is_empty(&sspreadsheet.row_filters)) {
341 return false;
342 }
343 return true;
344}
345
346static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
347 const DataSource &data_source)
348{
349 if (!(sspreadsheet.filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY)) {
350 return false;
351 }
352 if (!data_source.has_selection_filter()) {
353 return false;
354 }
355 return true;
356}
357
359 const SpreadsheetLayout &spreadsheet_layout,
360 const DataSource &data_source,
361 ResourceScope &scope)
362{
363 const int tot_rows = data_source.tot_rows();
364
365 const bool use_selection = use_selection_filter(sspreadsheet, data_source);
366 const bool use_filters = use_row_filters(sspreadsheet);
367
368 /* Avoid allocating an array if no row filtering is necessary. */
369 if (!(use_filters || use_selection)) {
370 return IndexMask(tot_rows);
371 }
372
373 IndexMaskMemory &mask_memory = scope.construct<IndexMaskMemory>();
374 IndexMask mask(tot_rows);
375
376 if (use_selection) {
377 const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
378 &data_source);
379 mask = geometry_data_source->apply_selection_filter(mask_memory);
380 }
381
382 if (use_filters) {
384 for (const ColumnLayout &column : spreadsheet_layout.columns) {
385 columns.add(column.values->name(), column.values);
386 }
387
388 LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
389 if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
390 if (!columns.contains(row_filter->column_name)) {
391 continue;
392 }
393 mask = apply_row_filter(*row_filter, columns, mask, mask_memory);
394 }
395 }
396 }
397
398 return mask;
399}
400
402{
406 row_filter->threshold = 0.01f;
407 row_filter->column_name[0] = '\0';
408
409 return row_filter;
410}
411
413{
415
416 memcpy(new_filter, src_row_filter, sizeof(SpreadsheetRowFilter));
417 new_filter->next = nullptr;
418 new_filter->prev = nullptr;
419
420 return new_filter;
421}
422
424{
425 MEM_SAFE_FREE(row_filter->value_string);
426 MEM_freeN(row_filter);
427}
428
429} // 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
BMesh const char void * data
long long int int64_t
bool is() const
ChannelStorageType r
Definition BLI_color.hh:93
ChannelStorageType g
Definition BLI_color.hh:93
ChannelStorageType b
Definition BLI_color.hh:93
ChannelStorageType a
Definition BLI_color.hh:93
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
#define MEM_SAFE_FREE(v)
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
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
blender::VecBase< int16_t, 2 > short2
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
Definition BLI_color.hh:343
struct SpreadsheetRowFilter * prev
struct SpreadsheetRowFilter * next
i
Definition text_draw.cc:230