Rotation Gesture Produces Undesired Rotation

Rotation gesture produces undesired rotation

you may want to change self.superview to self.view (mine is subclass)

var xOffSet:CGVector = CGVectorMake(0, 0)
var yOffSet:CGVector = CGVectorMake(0, 0)
var origin:CGPoint = CGPointZero
var tempTransform=CGAffineTransform()
var startingAngle:CGFloat?

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

origin = (touches.first?.locationInView(self.superview))!
xOffSet = CGVector(dx:(origin.x)-self.center.x, dy:(origin.y) - self.center.y)
startingAngle = atan2(xOffSet.dy,xOffSet.dx)

//save the current transform
tempTransform = self.transform
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

let touchPoint = touches.first?.locationInView(self.superview)
yOffSet = CGVector(dx:touchPoint!.x - self.center.x, dy:touchPoint!.y - self.center.y)
let angle = atan2(yOffSet.dy,yOffSet.dx)

let deltaAngle = angle - startingAngle!
self.transform = CGAffineTransformRotate(tempTransform, deltaAngle)
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
startingAngle = nil
}

//reset in case drag is cancelled
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
self.transform = tempTransform
startingAngle = nil
}

How to limit the rotation of a gesture event?

Why don't you try something like this:

dial_mc.addEventListener(TransformGestureEvent.GESTURE_ROTATE, rotateDial);

function rotateDial(e:TransformGestureEvent):void
{
dial_mc.rotation += e:rotation
if(dial_mc.rotation > MAX_ALLOWED_ROTATION) dial_mc.rotation = MAX_ALLOWED_ROTATION;
if(dial_mc.rotation < 0 ) dial_mc.rotation = 0;
}

How to Continue Transform/Rotation? - Dart/Flutter

You basically want to save the state of the widget so I think you will need to wrap it in a StatefulWidget to be able to do that.
(https://www.youtube.com/watch?v=AqCMFXEmf3w)

To smooth out the animation you could maybe try and use the AnimatedContainer?
I haven't used it myself but I think it should be what you need! (https://www.youtube.com/watch?v=yI-8QHpGIP4)

EDIT

Okay, I've got it working for you.

Offset vector;
double startingAngle;
double deltaAngle = 0.0;
double finalAngle = 0.0;
// store the final angle of the object
double finalObjectAngle = 0.0;

void _onPanStart(DragStartDetails details) {
_polarCoordFromGlobalOffset(details.globalPosition);
startingAngle = vector.direction;
print('START = $startingAngle ===================================');
}

void _onPanUpdate(DragUpdateDetails details) {
_polarCoordFromGlobalOffset(details.globalPosition);

setState(() {
// HERE you should use the finalObjectAngle
deltaAngle = vector.direction - startingAngle + finalObjectAngle;
finalAngle = deltaAngle;
});
}

void _onPanEnd(DragEndDetails details) {
finalAngle = deltaAngle;
// Save the finalAngle of the object
finalObjectAngle = finalAngle;
print('End = $finalAngle ===================================');
}

NSUndoManager to undo UIImage rotation using rotation gesture

First of all, read “Using Undo on iPhone”. Make sure you have set the undoManager property somewhere in your responder chain (probably in your view controller).

We only want to push an undo action when the gesture ends. But when we push the undo action, we need to know the view's transform when the gesture started. Create an instance variable to hold that original transform:

@implementation YourViewController {
CGAffineTransform _originalImageViewTransform;
}

Next, we need a method that pushes an undo action and sets the view's transform:

- (void)setTransform:(CGAffineTransform)newTransform ofView:(UIView *)view
undoTransform:(CGAffineTransform)undoTransform
{
// If I'm called because the gesture ended, this pushes an undo action.
// If I'm called because the user requested an undo, this pushes a redo action.
[[self.undoManager prepareWithInvocationTarget:self]
setTransform:undoTransform ofView:view undoTransform:newTransform];

// Now actually set the transform.
view.transform = newTransform;
}

Your handleRotate: method needs to detect the state of the gesture and take the appropriate action.

- (void)handleRotate:(UIRotationGestureRecognizer *)recognizer {
UIView *view = recognizer.view;
UIGestureRecognizerState state = recognizer.state;

if (state == UIGestureRecognizerStateCancelled) {
view.transform = _originalImageViewTransform;
return;
}

if (state == UIGestureRecognizerStateBegan) {
_originalImageViewTransform = view.transform;
}

CGAffineTransform transform = view.transform;
transform = CGAffineTransformRotate(transform, recognizer.rotation);
recognizer.rotation = 0; // This line means we don't need prevRotation

if (state == UIGestureRecognizerStateEnded) {
[[ The gesture ended, so push an undo action before setting the transform.
[self setTransform:transform ofView:view undoTransform:_originalImageViewTransform];
} else {
// The gesture changed but didn't end, so don't push an undo action.
view.transform = transform;
}
}

deciding whether cw or acw rotation from gesture, 3 ordered sample points

It is incredibly difficult to do this.

This may help...

private float bestKnownXYCWAngleFromTo(Vector3 a, Vector3 b)
// the best technology we have so far
{
a.z = 0f;
b.z = 0f;

float __angleCCW = Mathf.Atan2(b.y, b.x) - Mathf.Atan2(a.y, a.x);
if ( __angleCCW < 0f ) __angleCCW += (2.0f * Mathf.PI);

float __angleCWviaatan = (2.0f * Mathf.PI) - __angleCCW;
__angleCWviaatan = __angleCWviaatan * (Mathf.Rad2Deg);

if ( __angleCWviaatan >= 360.0 ) __angleCWviaatan = __angleCWviaatan-360.0f;

return __angleCWviaatan;
}

note that this is a 2D concept, modify as you need.

note that obviously "a" is just your (b-a) and "b" is just your (c-a)


Please note that true gesture recognition is a very advanced research field. I encourage you to get one of the solutions out there,

https://www.assetstore.unity3d.com/en/#!/content/14458

https://www.assetstore.unity3d.com/en/#!/content/21660

which represent literally dozens of engineer-years of effort. PDollar is great (that implementation is even free on the asset store!)

Rotation of UIImageView does not conserve center

I found that setting the transformation to the layer fixes the issue.

self.sourceImageView.layer.transform = CATransform3DRotate(CATransform3DMakeScale(scale, scale, 1.), angle, 0, 0, -1);

UIImageView Rotation Animation using CADisplayLink - Tracking Rotation

You can just have properties to keep track of the state of the rotation so that when you stop it, it can pick up where it left off. For example:

@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()

startDisplayLink()
}

@IBAction func handleTapGesture(sender: UITapGestureRecognizer) {
if displayLink != nil {
stopDisplayLink()
} else {
startDisplayLink()
}
}

private let duration = 2.5
private var percent = 0.0
private var displayLink: CADisplayLink?
private var start: CFAbsoluteTime?

func startDisplayLink() {
displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
start = CFAbsoluteTimeGetCurrent() + (1.0 - percent) * duration
displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}

func stopDisplayLink() {
displayLink?.invalidate()
displayLink = nil
}

func handleDisplayLink(displayLink: CADisplayLink) {
let elapsed = CFAbsoluteTimeGetCurrent() - start!
percent = (elapsed % duration) / duration
imageView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI * 2.0 * percent))
}

or in Objective-C:

static CGFloat const kDuration = 2.5;

@interface ViewController2 ()

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic) CFAbsoluteTime startTime;
@property (nonatomic) CGFloat percent;

@end

@implementation ViewController2

- (IBAction)handleTapGesture:(UITapGestureRecognizer *)sender {
if (self.displayLink) {
[self stopDisplayLink];
} else {
[self startDisplayLink];
}
}

- (void)viewDidLoad {
[super viewDidLoad];

[self startDisplayLink];
// Do any additional setup after loading the view.
}

- (void)startDisplayLink {
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
self.startTime = CFAbsoluteTimeGetCurrent() + (1.0 - self.percent) * kDuration;
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)stopDisplayLink {
[self.displayLink invalidate];
self.displayLink = nil;
}

- (void)handleDisplayLink:(CADisplayLink *)displayLink {
CFAbsoluteTime elapsed = CFAbsoluteTimeGetCurrent() - self.startTime;
self.percent = elapsed / kDuration - floor(elapsed / kDuration);
self.imageView.transform = CGAffineTransformMakeRotation(M_PI * 2.0 * self.percent);
}

@end


Related Topics



Leave a reply



Submit