Welcome to mirror list, hosted at ThFree Co, Russian Federation.

select_utils.c « util « editors « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 4e8cf1e92e66f3b5e047f2b8c523e10b4e506b6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/** \file
 * \ingroup edutil
 */

#include "BLI_kdtree.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"

#include "ED_select_utils.h"

#include "float.h"

/** 1: select, 0: deselect, -1: pass. */
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside)
{
  switch (sel_op) {
    case SEL_OP_ADD:
      return (!is_select && (is_inside)) ? 1 : -1;
    case SEL_OP_SUB:
      return (is_select && is_inside) ? 0 : -1;
    case SEL_OP_SET:
      return is_inside ? 1 : 0;
    case SEL_OP_AND:
      return (is_select && is_inside) ? -1 : (is_select ? 0 : -1);
    case SEL_OP_XOR:
      return (is_select && is_inside) ? 0 : ((!is_select && is_inside) ? 1 : -1);
  }
  BLI_assert(!"invalid sel_op");
  return -1;
}
/**
 * Use when we've de-selected all items first (for modes that need it).
 *
 * \note In some cases changing selection needs to perform other checks,
 * so it's more straightforward to deselect all, then select.
 */
int ED_select_op_action_deselected(const eSelectOp sel_op,
                                   const bool is_select,
                                   const bool is_inside)
{
  switch (sel_op) {
    case SEL_OP_ADD:
      return (!is_select && is_inside) ? 1 : -1;
    case SEL_OP_SUB:
      return (is_select && is_inside) ? 0 : -1;
    case SEL_OP_SET:
      /* Only difference w/ function above. */
      return is_inside ? 1 : -1;
    case SEL_OP_AND:
      return (is_select && is_inside) ? -1 : (is_select ? 0 : -1);
    case SEL_OP_XOR:
      return (is_select && is_inside) ? 0 : ((!is_select && is_inside) ? 1 : -1);
  }
  BLI_assert(!"invalid sel_op");
  return -1;
}

/**
 * Utility to use for selection operations that run multiple times (circle select).
 */
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
{
  if (sel_op == SEL_OP_SET) {
    if (is_first == false) {
      return SEL_OP_ADD;
    }
  }
  return sel_op;
}

int ED_select_similar_compare_float(const float delta, const float thresh, const int compare)
{
  switch (compare) {
    case SIM_CMP_EQ:
      return (fabsf(delta) <= thresh);
    case SIM_CMP_GT:
      return ((delta + thresh) >= 0.0);
    case SIM_CMP_LT:
      return ((delta - thresh) <= 0.0);
    default:
      BLI_assert_unreachable();
      return 0;
  }
}

bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
                                          const float length,
                                          const float thresh,
                                          const int compare)
{
  /* Length of the edge we want to compare against. */
  float nearest_edge_length;

  switch (compare) {
    case SIM_CMP_EQ:
      /* Compare to the edge closest to the current edge. */
      nearest_edge_length = length;
      break;
    case SIM_CMP_GT:
      /* Compare against the shortest edge. */
      /* -FLT_MAX leads to some precision issues and the wrong edge being selected.
       * For example, in a tree with 1, 2 and 3, which is stored squared as 1, 4, 9,
       * it returns as the nearest length/node the "4" instead of "1". */
      nearest_edge_length = -1.0f;
      break;
    case SIM_CMP_LT:
      /* Compare against the longest edge. */
      nearest_edge_length = FLT_MAX;
      break;
    default:
      BLI_assert_unreachable();
      return false;
  }

  KDTreeNearest_1d nearest;
  if (BLI_kdtree_1d_find_nearest(tree, &nearest_edge_length, &nearest) != -1) {
    float delta = length - nearest.co[0];
    return ED_select_similar_compare_float(delta, thresh, compare);
  }

  return false;
}