Files
test2/source/blender/blenlib/intern/BLI_dial_2d.cc
Bastien Montagne dd168a35c5 Refactor: Replace MEM_cnew with a type-aware template version of MEM_callocN.
The general idea is to keep the 'old', C-style MEM_callocN signature, and slowly
replace most of its usages with the new, C++-style type-safer template version.

* `MEM_cnew<T>` allocation version is renamed to `MEM_callocN<T>`.
* `MEM_cnew_array<T>` allocation version is renamed to `MEM_calloc_arrayN<T>`.
* `MEM_cnew<T>` duplicate version is renamed to `MEM_dupallocN<T>`.

Similar templates type-safe version of `MEM_mallocN` will be added soon
as well.

Following discussions in !134452.

NOTE: For now static type checking in `MEM_callocN` and related are slightly
different for Windows MSVC. This compiler seems to consider structs using the
`DNA_DEFINE_CXX_METHODS` macro as non-trivial (likely because their default
copy constructors are deleted). So using checks on trivially
constructible/destructible instead on this compiler/system.

Pull Request: https://projects.blender.org/blender/blender/pulls/134771
2025-03-05 16:35:09 +01:00

96 lines
2.4 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bli
*/
#include "BLI_dial_2d.h"
#include "MEM_guardedalloc.h"
#include "BLI_math_vector.h"
struct Dial {
/* center of the dial */
float center[2];
/* threshold of the dial. Distance of current position has to be greater
* than the threshold to be used in any calculations */
float threshold_squared;
/* the direction of the first dial position exceeding the threshold. This
* is later used as the basis against which rotation angle is calculated */
float initial_direction[2];
/* cache the last angle to detect rotations bigger than -/+ PI */
float last_angle;
/* number of full rotations */
int rotations;
/* has initial_direction been initialized */
bool initialized;
};
Dial *BLI_dial_init(const float start_position[2], float threshold)
{
Dial *dial = MEM_callocN<Dial>("dial");
copy_v2_v2(dial->center, start_position);
dial->threshold_squared = threshold * threshold;
return dial;
}
void BLI_dial_free(Dial *dial)
{
MEM_freeN(dial);
}
float BLI_dial_angle(Dial *dial, const float current_position[2])
{
float current_direction[2];
sub_v2_v2v2(current_direction, current_position, dial->center);
/* only update when we have enough precision,
* by having the mouse adequately away from center */
if (len_squared_v2(current_direction) > dial->threshold_squared) {
float angle;
float cosval, sinval;
normalize_v2(current_direction);
if (!dial->initialized) {
copy_v2_v2(dial->initial_direction, current_direction);
dial->initialized = true;
}
/* calculate mouse angle between initial and final mouse position */
cosval = dot_v2v2(current_direction, dial->initial_direction);
sinval = cross_v2v2(current_direction, dial->initial_direction);
/* Clamp to avoid NAN's in #acos */
angle = atan2f(sinval, cosval);
/* change of sign, we passed the 180 degree threshold. This means we need to add a turn.
* to distinguish between transition from 0 to -1 and -PI to +PI,
* use comparison with PI/2 */
if ((angle * dial->last_angle < 0.0f) && (fabsf(dial->last_angle) > float(M_PI_2))) {
if (dial->last_angle < 0.0f) {
dial->rotations--;
}
else {
dial->rotations++;
}
}
dial->last_angle = angle;
return angle + 2.0f * float(M_PI) * dial->rotations;
}
return dial->last_angle;
}