| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup bli | 
					
						
							| 
									
										
										
										
											2018-02-18 21:27:33 +11:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_dial_2d.h"
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  | #include "BLI_math.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Dial { | 
					
						
							|  |  |  |   /* center of the dial */ | 
					
						
							|  |  |  |   float center[2]; | 
					
						
							| 
									
										
										
										
											2018-06-17 16:32:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* threshold of the dial. Distance of current position has to be greater
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |    * than the threshold to be used in any calculations */ | 
					
						
							|  |  |  |   float threshold_squared; | 
					
						
							| 
									
										
										
										
											2018-06-17 16:32:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   /* 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; | 
					
						
							| 
									
										
										
										
											2018-06-17 16:32:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   /* number of full rotations */ | 
					
						
							|  |  |  |   int rotations; | 
					
						
							| 
									
										
										
										
											2018-06-17 16:32:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   /* has initial_direction been initialized */ | 
					
						
							|  |  |  |   bool initialized; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-01 13:02:21 +10:00
										 |  |  | Dial *BLI_dial_init(const float start_position[2], float threshold) | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   Dial *dial = MEM_callocN(sizeof(Dial), "dial"); | 
					
						
							| 
									
										
										
										
											2018-06-17 16:32:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   copy_v2_v2(dial->center, start_position); | 
					
						
							|  |  |  |   dial->threshold_squared = threshold * threshold; | 
					
						
							| 
									
										
										
										
											2018-06-17 16:32:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   return dial; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 22:39:00 +10:00
										 |  |  | float BLI_dial_angle(Dial *dial, const float current_position[2]) | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   float current_direction[2]; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   sub_v2_v2v2(current_direction, current_position, dial->center); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-15 23:15:58 +11:00
										 |  |  |   /* only update when we have enough precision,
 | 
					
						
							|  |  |  |    * by having the mouse adequately away from center */ | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   if (len_squared_v2(current_direction) > dial->threshold_squared) { | 
					
						
							|  |  |  |     float angle; | 
					
						
							|  |  |  |     float cosval, sinval; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |     normalize_v2(current_direction); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |     if (!dial->initialized) { | 
					
						
							|  |  |  |       copy_v2_v2(dial->initial_direction, current_direction); | 
					
						
							|  |  |  |       dial->initialized = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |     /* 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); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 08:09:05 +10:00
										 |  |  |     /* Clamp to avoid NAN's in #acos */ | 
					
						
							| 
									
										
										
										
											2014-08-29 15:35:19 +10:00
										 |  |  |     angle = atan2f(sinval, cosval); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |     /* change of sign, we passed the 180 degree threshold. This means we need to add a turn.
 | 
					
						
							| 
									
										
										
										
											2019-01-15 23:15:58 +11:00
										 |  |  |      * to distinguish between transition from 0 to -1 and -PI to +PI, | 
					
						
							|  |  |  |      * use comparison with PI/2 */ | 
					
						
							| 
									
										
										
										
											2014-08-29 15:35:19 +10:00
										 |  |  |     if ((angle * dial->last_angle < 0.0f) && (fabsf(dial->last_angle) > (float)M_PI_2)) { | 
					
						
							| 
									
										
										
										
											2019-03-27 13:16:10 +11:00
										 |  |  |       if (dial->last_angle < 0.0f) { | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |         dial->rotations--; | 
					
						
							| 
									
										
										
										
											2019-03-27 13:16:10 +11:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |         dial->rotations++; | 
					
						
							| 
									
										
										
										
											2019-03-27 13:16:10 +11:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     dial->last_angle = angle; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |     return angle + 2.0f * (float)M_PI * dial->rotations; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-27 17:29:15 +02:00
										 |  |  |   return dial->last_angle; | 
					
						
							|  |  |  | } |