Blender  V3.3
BLI_dial_2d.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "BLI_dial_2d.h"
8 #include "BLI_math.h"
9 
10 #include "MEM_guardedalloc.h"
11 
12 struct Dial {
13  /* center of the dial */
14  float center[2];
15 
16  /* threshold of the dial. Distance of current position has to be greater
17  * than the threshold to be used in any calculations */
19 
20  /* the direction of the first dial position exceeding the threshold. This
21  * is later used as the basis against which rotation angle is calculated */
23 
24  /* cache the last angle to detect rotations bigger than -/+ PI */
25  float last_angle;
26 
27  /* number of full rotations */
28  int rotations;
29 
30  /* has initial_direction been initialized */
32 };
33 
34 Dial *BLI_dial_init(const float start_position[2], float threshold)
35 {
36  Dial *dial = MEM_callocN(sizeof(Dial), "dial");
37 
38  copy_v2_v2(dial->center, start_position);
40 
41  return dial;
42 }
43 
44 float BLI_dial_angle(Dial *dial, const float current_position[2])
45 {
46  float current_direction[2];
47 
48  sub_v2_v2v2(current_direction, current_position, dial->center);
49 
50  /* only update when we have enough precision,
51  * by having the mouse adequately away from center */
52  if (len_squared_v2(current_direction) > dial->threshold_squared) {
53  float angle;
54  float cosval, sinval;
55 
56  normalize_v2(current_direction);
57 
58  if (!dial->initialized) {
59  copy_v2_v2(dial->initial_direction, current_direction);
60  dial->initialized = true;
61  }
62 
63  /* calculate mouse angle between initial and final mouse position */
64  cosval = dot_v2v2(current_direction, dial->initial_direction);
65  sinval = cross_v2v2(current_direction, dial->initial_direction);
66 
67  /* Clamp to avoid NAN's in #acos */
68  angle = atan2f(sinval, cosval);
69 
70  /* change of sign, we passed the 180 degree threshold. This means we need to add a turn.
71  * to distinguish between transition from 0 to -1 and -PI to +PI,
72  * use comparison with PI/2 */
73  if ((angle * dial->last_angle < 0.0f) && (fabsf(dial->last_angle) > (float)M_PI_2)) {
74  if (dial->last_angle < 0.0f) {
75  dial->rotations--;
76  }
77  else {
78  dial->rotations++;
79  }
80  }
81  dial->last_angle = angle;
82 
83  return angle + 2.0f * (float)M_PI * dial->rotations;
84  }
85 
86  return dial->last_angle;
87 }
typedef float(TangentPoint)[2]
Dial * BLI_dial_init(const float start_position[2], float threshold)
Definition: BLI_dial_2d.c:34
float BLI_dial_angle(Dial *dial, const float current_position[2])
Definition: BLI_dial_2d.c:44
#define M_PI_2
Definition: BLI_math_base.h:23
#define M_PI
Definition: BLI_math_base.h:20
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float r[2])
Read Guarded memory(de)allocation.
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define atan2f(x, y)
Definition: metal/compat.h:227
#define fabsf(x)
Definition: metal/compat.h:219
float center[2]
Definition: BLI_dial_2d.c:14
float initial_direction[2]
Definition: BLI_dial_2d.c:22
float last_angle
Definition: BLI_dial_2d.c:25
float threshold_squared
Definition: BLI_dial_2d.c:18
bool initialized
Definition: BLI_dial_2d.c:31
int rotations
Definition: BLI_dial_2d.c:28