📜 ⬆️ ⬇️

Pinch gesture orientation determination

Brief introduction


In one of the projects, I needed a definition of the Pinch gesture orientation. It was necessary for selective scaling of the object along the axis. Those. if the fingers move / move apart vertically, then we scale the object only vertically. Unfortunately, the UIPinchGestureRecognizer standard gesture recognizer does not provide such information. After reviewing the first page of search results in Google, I did not stumble upon a ready-made solution. “Well, let's write it ourselves. So even more interesting :) ”- I thought, and started to implement my pinch.


Editing


07/10/2010 - updated source code. Added the oScale property (CGPoint). Contains the scaling factor for individual axes. Analogue scale with UIPinchGestureRecognizer.

Basic development


To determine the orientation of fingers when doing Pinch, two subtasks need to be solved.
  1. Define the pinch gesture
  2. Determine the angle of the fingers

There were no problems with the first subtask. After reading the documentation again, I made sure that everything was already done long before us, you can write your own “recognizers” of gestures based on the UIGestureRecognizer, and therefore on UIPinchGestureRecognizer.
The solution of the second subtask also did not take much time. A little thought
image
I found a solution: simply determine the angle between the Oy axis of the screen and the line passing through the user's fingers.
')
Everything, it was possible to be accepted for writing the code. Below are the results of work:

Description:


// // UIOrientedPinchGestureRecognizer.h //  .. // #import <Foundation/Foundation.h> #import "UIKit/UIGestureRecognizerSubclass.h" typedef enum{ OrientationNone = 0, OrientationVertical = 1, OrientationHorizontal = 2, OrientationDiagonal = 3, OrientationInvertedDiagonal = 4 }Orientation; @interface UIOrientedPinchGestureRecognizer : UIPinchGestureRecognizer { Orientation _orientation; CGFloat _angle; CGPoint _lastScale; CGFloat _oldScale; } //  @property (nonatomic) Orientation orientation; // ,  OY.  .  0  PI.  angle==PI_2 orientation==OrientationHorizontal @property (nonatomic) CGFloat angle; @property (nonatomic) CGPoint oScale; @end #pragma mark c_func static inline CGFloat degToRad(CGFloat deg) {return deg*M_PI/180;} static inline CGFloat radToDeg(CGFloat rad) {return rad*180/M_PI;} //     .     A, .   PointB-PointA-PointC static inline double getCosAngle(CGPoint pointA,CGPoint pointB, CGPoint pointC){ CGPoint vectorAB = CGPointMake(pointB.x-pointA.x, pointB.y-pointA.y); CGPoint vectorAC = CGPointMake(pointC.x-pointA.x, pointC.y-pointA.y); double dAB=sqrt(vectorAB.x*vectorAB.x+vectorAB.y*vectorAB.y); double dAC=sqrt(vectorAC.x*vectorAC.x+vectorAC.y*vectorAC.y); double scal = vectorAB.x * vectorAC.x +vectorAB.y * vectorAC.y; double angle = scal/(dAB*dAC); return angle; } //    .     A, .   PointB-PointA-PointC static inline double getAngle(CGPoint pointA,CGPoint pointB, CGPoint pointC){ if ((CGPointEqualToPoint(pointA, pointB))||(CGPointEqualToPoint(pointA, pointC))||(CGPointEqualToPoint(pointB, pointC))) return 0; //     3,  2     return acos(getCosAngle(pointA, pointB, pointC)); } #pragma - 


Implementation:


 // // UIOrientedPinchGestureRecognizer.m // #import "UIOrientedPinchGestureRecognizer.h" @implementation UIOrientedPinchGestureRecognizer @synthesize angle=_angle, orientation=_orientation,oScale=_lastScale; #pragma mark init/dealloc -(void) dealloc{ [super dealloc]; } -(id) init{ self = [super init]; if (self) { _orientation = OrientationNone; _angle = 0; } return self; } #pragma mark - Methods -(void) detectAngle:(NSArray *) touches{ if ([touches count]!=2) { _orientation= OrientationNone; _angle = 0; //     //  .   _lastScale.x *= self.scale/_oldScale; _lastScale.y *= self.scale/_oldScale; _oldScale = self.scale; return; } //   CGPoint firstPoint =[[touches objectAtIndex:0] locationInView:self.view]; CGPoint secondPoint = [[touches objectAtIndex:1] locationInView:self.view]; //   OY if (secondPoint.x<firstPoint.x) { CGPoint tmp = secondPoint; secondPoint = firstPoint; firstPoint = tmp; } //  _angle = getAngle(firstPoint,secondPoint,CGPointMake(firstPoint.x,firstPoint.y-100.0f)); //    if ((_angle> M_PI_4/2.0f)&&(_angle< M_PI_4+M_PI_4/2.0f)) { _orientation= OrientationDiagonal; _lastScale.x *= self.scale/_oldScale; _lastScale.y *= self.scale/_oldScale; }else if ((_angle> M_PI_4+M_PI_4/2.0f)&&(_angle<M_PI_2+M_PI_4/2.0f)) { _orientation = OrientationHorizontal; _lastScale.x *= self.scale/_oldScale; }else if ((_angle>M_PI_2+M_PI_4/2.0f)&&(_angle<M_PI_2+M_PI_4+M_PI_4/2.0f)){ _orientation = OrientationInvertedDiagonal; _lastScale.x *= self.scale/_oldScale; _lastScale.y *= self.scale/_oldScale; }else{ _orientation=OrientationVertical; _lastScale.y *= self.scale/_oldScale; } _oldScale=self.scale; return; } -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ _lastScale = CGPointMake(1.0f, 1.0f); _oldScale = 1.0f; [self detectAngle:[touches allObjects]]; [super touchesBegan:touches withEvent:event]; } -(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ [self detectAngle:[touches allObjects]]; [super touchesMoved:touches withEvent:event]; } @end 


Use the same way as UIPinchGestureRecognizer


 UIOrientedPinchGestureRecognizer *pinchGesture = [[UIOrientedPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; [pinchGesture setDelegate:self]; pinchGesture.cancelsTouchesInView=NO; [self.view addGestureRecognizer:pinchGesture]; 


Treatment:


 - (IBAction)handlePinchGesture:(UIOrientedPinchGestureRecognizer *)sender { NSLog(@"angle: %f orientation: %i scale.x:%f scale.y:%f",radToDeg(sender.angle),sender.orientation,sender.oScale.x,sender.oScale.y); } 


Disadvantages:


At the moment there is no definition of the angle for three / four, etc. fingers.

Sources



Thank you all for your attention.

Source: https://habr.com/ru/post/123644/


All Articles