I implemented a UIPanGestureRecognizer since I wish to use one finger to rotate a UIView along its axis. A button within the uiview begins the gesture at which point the UIView rotates. Problem is that it only rotates correctly if the button is in the 1st quadrant, top left. Any other quadrant and it rotates erratically. Can someone tell me what is wrong with my math. By the way ang calculates the angle using the superview's coordinates since the users finger might be outside the rotating views bounds, but that might not be necessary.
thank you
- (void)rotateItem:(UIPanGestureRecognizer *)recognizer
{
NSLog(#"Rotate Item");
float ang = atan2([recognizer locationInView:self.superview].y - self.center.y, [recognizer locationInView:self.superview].x - self.center.x);
float angleDiff = deltaAngle - ang;
self.transform = CGAffineTransformRotate(startTransform, -angleDiff);
CGFloat radians = atan2f(self.transform.b, self.transform.a);
NSLog(#"rad is %f", radians);
}
#pragma mark - Touch Methods
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)recognizer
{
if (recognizer == rotateGesture) {
NSLog(#"rotate gesture started");
deltaAngle = atan2([recognizer locationInView:self].y-self.center.y, [recognizer locationInView:self].x-self.center.x);
startTransform = self.transform;
}
return YES;
}
I did some logging and it seems that the center of my uiview was changing during the touch drag event. Hence I stored the center of the uiview with the touches began method and used it instead.
- (void)rotateItem:(UIPanGestureRecognizer *)recognizer
{
NSLog(#"Rotate Item");
CGPoint superPoint = [self convertPoint:itemCenter toView:self.superview];
float ang = atan2([recognizer locationInView:self.superview].y - superPoint.y, [recognizer locationInView:self.superview].x - superPoint.x);
float angleDiff = deltaAngle - ang;
self.transform = CGAffineTransformRotate(startTransform, -angleDiff);
}
#pragma mark - Touch Methods
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)recognizer
{
if (recognizer == rotateGesture) {
NSLog(#"rotate gesture started");
deltaAngle = atan2([recognizer locationInView:self.superview].y-self.center.y, [recognizer locationInView:self.superview].x-self.center.x);
startTransform = self.transform;
}
return YES;
}
Related
I have a overlay image (.png) on my map that consists of a transparent bit in the middle, and colored sides so the user can only focus on the middle part. However do to the shape of that middle bit, quite a bit is visible at some sides.
I'm trying to detect a tap on the OverlayView so I can ignore it and only accept touches in the designated area.
I followed the following tut at Ray Wenderlich's site for adding the overlay:
The image overlay is drawn like this:
#implementation PVParkOverlayView
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage {
self = [super initWithOverlay:overlay];
if (self) {
_overlayImage = overlayImage;
}
return self;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGImageRef imageReference = self.overlayImage.CGImage;
//UIImage *imageTest = _overlayImage;
MKMapRect theMapRect = self.overlay.boundingMapRect;
CGRect theRect = [self rectForMapRect:theMapRect];
//orientation testing
//CGContextRotateCTM(context, 0);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
CGContextDrawImage(context, theRect, imageReference);
}
I have a gesture recognizer on my mapview and am trying to detect the tap there:
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
CGPoint tapPoint = [gestureRecognizer locationInView:self.mapView];
CLLocationCoordinate2D tapCoord = [self.mapView convertPoint:tapPoint toCoordinateFromView:self.mapView];
MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoord);
CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
for (id<MKOverlay> overlay in self.mapView.overlays) {
if([overlay isKindOfClass:[PVParkOverlay class]]){
NSLog(#"overlay is present");
/*
MKPolygon *polygon = (MKPolygon*) overlay;
CGMutablePathRef mpr = CGPathCreateMutable();
MKMapPoint *polygonPoints = polygon.points;
for (int p=0; p < polygon.pointCount; p++){
MKMapPoint mp = polygonPoints[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
else
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
if(CGPathContainsPoint(mpr , NULL, mapPointAsCGP, FALSE)){
// ... found it!
NSLog(#"I've found it!");
}
//CGPathRelease(mpr);
*/
}
}
I know that the overlay is there, but since it is a drawn image I can't find a way to convert this to polygon points to use this code (if even possible).
Any other methods I can use for this?
I also found following sample code but the viewForOverlay method is deprecated:
- (void)mapTapped:(UITapGestureRecognizer *)recognizer
{
MKMapView *mapView = (MKMapView *)recognizer.view;
id<MKOverlay> tappedOverlay = nil;
for (id<MKOverlay> overlay in mapView.overlays)
{
MKOverlayView *view = [mapView viewForOverlay:overlay];
if (view)
{
// Get view frame rect in the mapView's coordinate system
CGRect viewFrameInMapView = [view.superview convertRect:view.frame toView:mapView];
// Get touch point in the mapView's coordinate system
CGPoint point = [recognizer locationInView:mapView];
// Check if the touch is within the view bounds
if (CGRectContainsPoint(viewFrameInMapView, point))
{
tappedOverlay = overlay;
break;
}
}
}
NSLog(#"Tapped view: %#", [mapView viewForOverlay:tappedOverlay]);
}
I am using Apple's source code. I am sure there is just a snippet that I have messed up. I have a form that I have made programmatically. When I double tap the recognizer fires and goes through the motions but I it won't actually zoom. Any suggestions? Thanks for the help
imageScrollView.delegate=self;
CGRect fullScreenRect=[[UIScreen mainScreen] applicationFrame];
imageScrollView=[[UIScrollView alloc]initWithFrame:fullScreenRect];
imageScrollView.contentSize=CGSizeMake(750,1250);
imageScrollView.minimumZoomScale=1.0;
imageScrollView.maximumZoomScale=5.0;
[imageScrollView setZoomScale:imageScrollView.minimumZoomScale];
self.view=imageScrollView;
[imageScrollView release];
Added a bunch of UItextfields/labels to the scrollview.
aircraftType = [[UITextField alloc]initWithFrame:CGRectMake(170, 32, 150, 15)];
aircraftType.font=[UIFont systemFontOfSize:10];
aircraftType.borderStyle = UITextBorderStyleRoundedRect;
aircraftType.placeholder = #"Aicraft Type";
aircraftType.delegate = self;
[self.view addSubview:aircraftType];
#pragma mark UIScrollViewDelegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [imageScrollView viewWithTag:ZOOM_VIEW_TAG];
}
#pragma mark TapDetectingImageViewDelegate methods
- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
// double tap zooms in
float newScale = [imageScrollView zoomScale] * ZOOM_STEP;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
[imageScrollView zoomToRect:zoomRect animated:YES];
}
#pragma mark Utility methods
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {
CGRect zoomRect;
// the zoom rect is in the content view's coordinates.
// At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
// As the zoom scale decreases, so more content is visible, the size of the rect grows.
zoomRect.size.height = [imageScrollView frame].size.height / scale;
zoomRect.size.width = [imageScrollView frame].size.width / scale;
// choose an origin so as to get the right center.
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
return zoomRect;
}
Anyone know of any good up to date tutorials out there that show how can one animate a sprite based on accelerometer movement. I want to animate a bird to sway to the position the device was pointed to. For example if the player decides to move the bird to the left via the accelerometer I would like for my bird to play an animation that is swaying to the left.
// Accelerometer
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
birdSpeedY = 9.0 + acceleration.x*15;
birdSpeedX = -acceleration.y*20;
}
// Updating bird based on accelerometer
-(void)updateBird {
float maxY = winSize.height - bird.contentSize.height/2;
float minY = bird.contentSize.height/2;
float newY = bird.position.y + birdSpeedY;
newY = MIN(MAX(newY, minY), maxY);
float maxX = winSize.width - bird.contentSize.width/2;
float minX = bird.contentSize.width/2;
float newX = bird.position.x + birdSpeedX;
newX = MIN(MAX(newX, minX), maxX);
bird.position = ccp(newX, newY);
}
// Making background scroll automatically
-(void)update:(ccTime)dt {
[self updateBird];
CGPoint backgroundScrollVel = ccp(-100, 0);
parallaxNode.position = ccpAdd(parallaxNode.position, ccpMult(backgroundScrollVel, dt));
}
-(id)init {
self = [super init];
if (self != nil) {
winSize = [CCDirector sharedDirector].winSize;
CCSpriteFrameCache *cache=[CCSpriteFrameCache sharedSpriteFrameCache];
[cache addSpriteFramesWithFile:#"birdAtlas.plist"];
NSMutableArray *framesArray=[NSMutableArray array];
for (int i=1; i<10; i++) {
NSString *frameName=[NSString stringWithFormat:#"bird%d.png", i];
id frameObject=[cache spriteFrameByName:frameName];
[framesArray addObject:frameObject];
}
// animation object
id animObject=[CCAnimation animationWithFrames:framesArray delay:0.1];
// animation action
id animAction=[CCAnimate actionWithAnimation:animObject restoreOriginalFrame:NO];
animAction=[CCRepeatForever actionWithAction:animAction];
bird=[CCSprite spriteWithSpriteFrameName:#"bird1.png"];
bird.position=ccp(60,160);
CCSpriteBatchNode *batchNode=[CCSpriteBatchNode batchNodeWithFile:#"birdAtlas.png"];
[self addChild:batchNode z:100];
[batchNode addChild:bird];
[bird runAction:animAction];
self.isAccelerometerEnabled = YES;
[self scheduleUpdate];
[self addScrollingBackgroundWithTileMapInsideParallax];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
#end
You can try the Accelerometer methods with it and change the position of the Sprite using ccp(). You also need to know is that project for the Landscape or Portrait in the Mode.
You Can Try the Stuff below
- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
[lbl setString:[NSString stringWithFormat:#"X=>%.2lf Y=>%.2lf",(double)acceleration.x,(double)acceleration.y]];
double x1= -acceleration.y *10;
double y1= acceleration.x *15;
if(acceleration.x >0.05)
{
y1*=spped_incr; // Make Movement Here
}
[Sprite_Name runAction:[CCMoveTo actionWithDuration:0.1f position:ccpAdd(ccp(x1,y1), Sprite_Name.position)]];
}
The Above Stuff is for the Landscape Mode.... if You need in Portrait Mode you need to change the Axis and use the TRY & Error Method.
I would like to make it so when the user rotates the device (to any angle, not just landscape/portrait) the UIImageView would always be facing upwards. How would I do this?
Thanks in advance
#interface FirstViewController : UIViewController <UIAccelerometerDelegate> {
IBOutlet UIImageView *imageView;
CGPoint delta;
CGPoint translation;
float ballRadius;
}
//implementation
- (void)viewDidLoad
{
[super viewDidLoad];
// for the line in the middle of the camera
UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = self;
accel.updateInterval = 1.0f/60.0f;
}
- (void)accelerometer:(UIAccelerometer *)acel
didAccelerate:(UIAcceleration *)acceleration {
// Get the current device angle
float xx = -[acceleration x];
float yy = [acceleration y];
float angle = atan2(yy, xx);
// Add 1.5 to the angle to keep the image constantly horizontal to the viewer.
[imageView setTransform:CGAffineTransformMakeRotation(angle+1.5)];
}
I am trying to draw a rectangle and let the user create it based on where he clicks and where he drags the mouse.
The code I am using to draw the NSRect is:
CGFloat width = endPoint.x-startPoint.x; //Width of rectangle.
CGFloat height = endPoint.y-startPoint.y; //Height of rectangle.
CGFloat rectXPoint = startPoint.x; //x component of corner of rect
CGFloat rectYPoint = startPoint.x; //y component of corner of rect
if (width < 0) { //Handle negavive rect size here.
width = startPoint.x-endPoint.x;
rectXPoint = endPoint.x;
}
if (height < 0) { //and here.
height = startPoint.y-endPoint.y;
rectYPoint = endPoint.y;
}
NSRect theRect = NSMakeRect(rectXPoint, rectYPoint, width, height);
[[NSColor blackColor] set];
NSRectFill(theRect);
So I can sort of get the code to work but not exactly. Sometimes it offsets the y of the rectangle from the cursor by some seemingly arbitrary amount (even though I know it isn't arbitrary). It is hard to get a screen shot considering that would involve me moving the mouse from the point it would need to be to demonstrate the point. Just in case you need to see the code for how I am getting the location of the mouse here it is:
- (void)mouseDown:(NSEvent *)event {
NSPoint location = [self convertPointFromBase:[event locationInWindow]];
startPoint = location;
}
- (void)mouseDragged:(NSEvent *)event {
NSPoint location = [self convertPointFromBase:[event locationInWindow]];
endPoint = location;
[self setNeedsDisplay:YES];
}
And isFlipped returns YES.
If you need any more clarification ask what you need clarification.
Probably this line:
CGFloat rectYPoint = startPoint.x; //y component of corner of rect