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