iPhone wheel not running smoothly - iphone

I am implementing a wheel for iPhone which should turn clockwise or anti-clockwise upon being dragged into that direction. Although it does this, there was some errors with smoothness. Sometimes it seems like it get confused regards which way it should turn. Any help please?
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
int len = [allTouches count]-1;
UITouch *touch =[[allTouches allObjects] objectAtIndex:len];
CGPoint location = [touch locationInView:[self superview]];
xfirst = location.x;
xnext = xfirst;
x = [NSNumber numberWithFloat:xfirst];
yfirst = location.y;
ynext = yfirst;
y = [NSNumber numberWithFloat:yfirst];
//NSLog(#"Touch began for wheel at %f and %f",xfirst, yfirst);
//NSLog(#"Centre %f and %f",self.center.x, self.center.y);
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch =[[allTouches allObjects] objectAtIndex:len];
CGPoint location = [touch locationInView:[self superview]];
xlast = location.x;
ylast = location.y;
//dy / dx (gradient)
if (((ylast-yfirst)/(xlast-xfirst) >= 0.3) || ((ylast-yfirst)/(xlast-xfirst) <= -0.3))
{
int seg1 = [self detectSegment:xnext :ynext];
int seg2 = [self detectSegment:xlast :ylast];
bool direction = [self isClockWise:seg1 :seg2];
lastDirection = direction;
float theAngle = [self getAngle:self.center.x:self.center.y:xfirst:yfirst:xlast:ylast];
theAngle = theAngle / 6;
if (direction == YES)
{
}
else {
theAngle = -1*theAngle;
}
theAngle += totalRadians;
float rads = 6.28318531;
int divAm = 0;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:0];
[formatter setRoundingMode: NSNumberFormatterRoundDown];
float nm = theAngle/rads;
NSString *numberString = [formatter stringFromNumber:[NSNumber numberWithFloat:nm]];
[formatter release];
divAm = [numberString floatValue];
theAngle = theAngle - (float)(6.28318531*divAm);
totalRadians = theAngle;
xnext = xlast;
ynext = ylast;
[self rotateImage:theAngle];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}
-(float) getAngle: (CGFloat)P1x: (CGFloat)P1y: (CGFloat)P2x: (CGFloat)P2y: (CGFloat)P3x: (CGFloat)P3y {
float P23 = [self getLength:P2x:P2y:P3x:P3y];
float P12 = [self getLength:P1x:P1y:P2x:P2y];
float P13 = [self getLength:P1x:P1y:P3x:P3y];
return acos((P23*P23 - P12*P12 - P13*P13)/(-2*P12*P13));
}
-(float) getLength: (CGFloat)P1x: (CGFloat)P1y: (CGFloat)P2x: (CGFloat)P2y
{
return sqrt((P1x-P2x)*(P1x-P2x) + (P1y-P2y)*(P1y-P2y));
}
Any suggestions please?

I'm a bit confused why you're using such a complex algorithm to find the angle. I don't understand why you need the gradient, and using number formatting in a calculation is a little strange. That said, you may have good reason for doing these things, so I suggest you simplify the algorithm in order to test the rotation code; you can add the complexity later if you still need it. Fundamentally, you just need:-
theAngle = atan2( location.y-self.center.y, location.x-self.center.x )
to ensure the wheel tracks your finger.

Related

objective-c iPhone game programming : detect touch on tile map object layer

hi made an object layer on my tile map with tile map editor like this :
http://i.stack.imgur.com/f5fZK.png
The big square represent my object layer named : ObjectIt.
My problem is when i touch the square in the simulator it doesn't correspond to the right place. Some people told me problem with float value or open gl but I'm noob i need clear answers .
This is my code :
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touch detect");
CCNode* node = [self getChildByTag:TileMapNode];
NSAssert([node isKindOfClass:[CCTMXTiledMap class]], #"not a CCTMXTiledMap");
CCTMXTiledMap* tileMap = (CCTMXTiledMap*)node;
// Get the position in tile coordinates from the touch location
CGPoint touchLocation = [self locationFromTouches:touches];
CGPoint tilePos = [self tilePosFromLocation:touchLocation tileMap:self.tileMap];
// Check if the touch was on water (e.g., tiles with isWater property)
bool isTouchOnWater = NO;
CCTMXObjectGroup* objectLayer = [tileMap objectGroupNamed:#"ObjectIt"];
bool isTouchInRectangle = NO;
int numObjects = [objectLayer.objects count];
for (int i = 0; i < numObjects; i++)
{
NSDictionary* properties = [objectLayer.objects objectAtIndex:i];
CGRect rect = [self getRectFromObjectProperties:properties tileMap:tileMap];
if (CGRectContainsPoint(rect, touchLocation))
{
isTouchInRectangle = YES;
break; }
}
if (isTouchInRectangle)
{
NSLog(#"TOUCH IN RECTANGLE");
// get the ALGORITH FOR TOWERS
}
}
-
(CGPoint) locationFromTouch:(UITouch*)touch
{
CGPoint touchLocation = [touch locationInView: [touch view]];
return [[CCDirector sharedDirector] convertToGL:touchLocation];
}
-(CGPoint) locationFromTouches:(NSSet*)touches
{
return [self locationFromTouch:[touches anyObject]];
}
-(CGRect) getRectFromObjectProperties:(NSDictionary*)dict
tileMap:(CCTMXTiledMap*)tileMap
{
float x, y, width, height;
x = [[dict valueForKey:#"x"] floatValue] + tileMap.position.x;
y = [[dict valueForKey:#"y"] floatValue] + tileMap.position.y;
width = [[dict valueForKey:#"width"] floatValue];
height = [[dict valueForKey:#"height"] floatValue];
return CGRectMake(x, y, width, height);
}
Thats the code , ill give you more if you need.
Also : when i run on the iPhone i got vertical black lines...
In order to get the correct touch location in Cocos2D points use this CCNode convenience method:
- (CGPoint)convertTouchToNodeSpace:(UITouch *)touch
{
CGPoint point = [touch locationInView: [touch view]];
point = [[CCDirector sharedDirector] convertToGL: point];
return [self convertToNodeSpace:point];
}
I'm not sure if it's been added to the API since phix23 posted their answer but the convertTouchToNodeSpace: method basically does the same thing:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CCTMXTiledMap* tileMap = (CCTMXTiledMap*)[self getChildByTag:TileMapNode];
CGPoint p = [tileMap convertTouchToNodeSpace:touch];
// If you wanted to figure out which tile in a layer they touched (assuming
// it's Ortho) you could do something like this:
CCTMXLayer *layer = [tileMap layerNamed:#"Tile Layer 1"];
CGPoint q = {
(int) (p.x / tileMap.tileSize.width),
// World origin is bottom left but map coordinates are top left so flip
// the y.
layer.layerSize.height - (int) (p.y / tileMap.tileSize.height) - 1
};
CCSprite *s = [layer tileAt:q];
NSLog(#"Touched %#", s);
return YES;
}

Rotate image on center using one finger touch

I want to rotate the below image on a center point using one finger touch...
And i want to display the value of the image with the label when I rotate the image using touch.
I have done the image rotation but the problem is that how to set the value of the image according to rotation.
The angle of the rotation is increase so i can not set the value.
Can any one help me?
The code is below
float fromAngle = atan2(firstLoc.y-imageView.center.y,
firstLoc.x-imageView.center.x);
NSLog(#"From angle:%f",fromAngle);
float toAngle = atan2( currentLoc.y-imageView.center.y,
currentLoc.x-imageView.center.x);
NSLog(#"to Angle:%f",toAngle);
// So the angle to rotate to is relative to our current angle and the
// angle through which our finger moved (to-from)
float newAngle =angle+(toAngle-fromAngle);
NSLog(#"new angle:%.2f",newAngle);
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(newAngle);
imageView.transform=cgaRotate;
angle = newAngle;
Can any one help me ?
Wasn't totally sure what you were after; but try out this code.
If you create a new View-based Application project called 'Rotation' and replace the code in RotationViewController.h and .m for the following you'll get a green block that you can rotate using your calculations. You can replace the green block UIView with your UIImageView, or anything else you want to spin.
RotationViewController.h
#import <UIKit/UIKit.h>
#interface RotationViewController : UIViewController
{
UIView* m_block;
UILabel* m_label;
CGPoint m_locationBegan;
float m_currentAngle;
}
- (float) updateRotation:(CGPoint)_location;
#end
RotationViewController.m
#import "RotationViewController.h"
double wrapd(double _val, double _min, double _max)
{
if(_val < _min) return _max - (_min - _val);
if(_val > _max) return _min - (_max - _val);
return _val;
}
#implementation RotationViewController
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect blockFrame = CGRectMake(0, 0, 200, 200);
m_block = [[UIView alloc] initWithFrame:blockFrame];
m_block.backgroundColor = [UIColor greenColor];
m_block.center = self.view.center;
[self.view addSubview:m_block];
[m_block release];
CGRect labelFrame = CGRectMake(0, 0, 320, 30);
m_label = [[UILabel alloc] initWithFrame:labelFrame];
m_label.text = #"Loaded";
[self.view addSubview:m_label];
}
- (void) touchesBegan:(NSSet *)_touches withEvent:(UIEvent *)_event
{
UITouch* touch = [_touches anyObject];
CGPoint location = [touch locationInView:self.view];
m_locationBegan = location;
}
- (void) touchesMoved:(NSSet *)_touches withEvent:(UIEvent *)_event
{
UITouch* touch = [_touches anyObject];
CGPoint location = [touch locationInView:self.view];
[self updateRotation:location];
}
- (void) touchesEnded:(NSSet *)_touches withEvent:(UIEvent *)_event
{
UITouch* touch = [_touches anyObject];
CGPoint location = [touch locationInView:self.view];
m_currentAngle = [self updateRotation:location];
}
- (float) updateRotation:(CGPoint)_location
{
float fromAngle = atan2(m_locationBegan.y-m_block.center.y, m_locationBegan.x-m_block.center.x);
float toAngle = atan2(_location.y-m_block.center.y, _location.x-m_block.center.x);
float newAngle = wrapd(m_currentAngle + (toAngle - fromAngle), 0, 2*3.14);
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(newAngle);
m_block.transform = cgaRotate;
int oneInFifty = (newAngle*50)/(2*3.14);
m_label.text = [NSString stringWithFormat:#"Angle: %f 1in50: %i", newAngle, oneInFifty];
return newAngle;
}
#end

How to rotate and resize sprite like photo in lybrary

How can I rotate sprite around his center in cocos2d in ccTouchesMoved. I found some code, but this not what I need. I need to rotate sprite like photo in Photo gallery app.
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *allTouch = [touches allObjects];
if([allTouch count] > 1){
UITouch *touch = [allTouch objectAtIndex:0];
CGPoint point = [touch locationInView: [touch view]];
point = [[CCDirector sharedDirector] convertToGL:point];
float angleRadians = atanf((float)point.y / (float)point.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
imageFromPicker.rotation = imageFromPicker.rotation + cocosAngle;
}
}
probably is not the best way but im using this:
When I touch the sprite with two fingers, i use the arctan of the two points to rotate the sprite:
first i look for the direction with this function:
static inline int ccw(CGPoint p0, CGPoint p1, CGPoint p2)
{
int dx1, dx2, dy1, dy2;
dx1 = p1.x - p0.x; dy1 = p1.y - p0.y;
dx2 = p2.x - p0.x; dy2 = p2.y - p0.y;
int v1 = dx1 * dy2;
int v2 = dy1 * dx2;
if (v1 > v2)
return 1;
if (v1 < v2)
return -1;
if ((dx1*dx2 < 0) || (dy1*dy2 < 0))
return -1;
if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2))
return 1;
return 0;
}
and after on the ccTouchesMoved method I do this:
if ([allTouches count] == 2) {
rotating=TRUE;
NSArray *twoTouches = [allTouches allObjects];
UITouch *first = [twoTouches objectAtIndex:0];
UITouch *second = [twoTouches objectAtIndex:1];
CGPoint a = [first previousLocationInView:[touch view]];
CGPoint b = [second previousLocationInView:[touch view]];
CGPoint c = [first locationInView:[touch view]];
int direction =ccw(b, a, c);
float pX= fabs(c.x-b.x);
float pY= fabs(c.y-b.y);
float rotation = atan2(pY, pX);
// rotTotal= (rotTotal+rotacion)/10;
if(direction<0)
YourSprite.rotation=(YourSprite.rotation-rotation);
else
YourSprite.rotation=(YourSprite.rotation+rotation);
}
it works for me, hope it works for you too

Multi touch is not working perfectly on UIImageView

I am doing multi touch on UImageView means zoom in and zoom out on image view. I am using followng code but it doesn't work very well. Can anyone look at this code,
#import "ZoomingImageView.h"
#implementation ZoomingImageView
#synthesize zoomed;
#synthesize moved;
define HORIZ_SWIPE_DRAG_MIN 24
define VERT_SWIPE_DRAG_MAX 24
define TAP_MIN_DRAG 10
CGPoint startTouchPosition;
CGFloat initialDistance;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
moved = NO;
zoomed = NO;
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
- (void)dealloc {
if([timer isValid])
[timer invalidate];
[super dealloc];
}
- (void) setImage: (UIImage*)img
{
zoomed = NO;
moved = NO;
self.transform = CGAffineTransformIdentity;
[super setImage:img];
}
- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint {
float x = toPoint.x - fromPoint.x;
float y = toPoint.y - fromPoint.y;
return sqrt(x * x + y * y);
}
- (CGFloat)scaleAmount: (CGFloat)delta {
CGFloat pix = sqrt(self.frame.size.width * self.frame.size.height);
CGFloat scale = 1.0 + (delta / pix);
return scale;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if([timer isValid])
[timer invalidate];
moved = NO;
switch ([touches count]) {
case 1:
{
// single touch
UITouch * touch = [touches anyObject];
startTouchPosition = [touch locationInView:self];
initialDistance = -1;
break;
}
default:
{
// multi touch
UITouch *touch1 = [[touches allObjects] objectAtIndex:0];
UITouch *touch2 = [[touches allObjects] objectAtIndex:1];
initialDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:self]
toPoint:[touch2 locationInView:self]];
break;
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch1 = [[touches allObjects] objectAtIndex:0];
if([timer isValid])
[timer invalidate];
/*if ([touches count] == 1) {
CGPoint pos = [touch1 locationInView:self];
self.transform = CGAffineTransformTranslate(self.transform, pos.x - startTouchPosition.x, pos.y - startTouchPosition.y);
moved = YES;
return;
}****/
if ((initialDistance > 0) && ([touches count] > 1)) {
UITouch *touch2 = [[touches allObjects] objectAtIndex:1];
CGFloat currentDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:self]
toPoint:[touch2 locationInView:self]];
CGFloat movement = currentDistance - initialDistance;
NSLog(#"Touch moved: %f", movement);
CGFloat scale = [self scaleAmount: movement];
self.transform = CGAffineTransformScale(self.transform, scale, scale);
// }
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch1 = [[touches allObjects] objectAtIndex:0];
if ([touches count] == 1) {
// double tap to reset to default size
if ([touch1 tapCount] > 1) {
if (zoomed) {
self.transform = CGAffineTransformIdentity;
moved = NO;
zoomed = NO;
}
return;
}
}
else {
// multi-touch
UITouch *touch2 = [[touches allObjects] objectAtIndex:1];
CGFloat finalDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:self]
toPoint:[touch2 locationInView:self]];
CGFloat movement = finalDistance - initialDistance;
NSLog(#"Final Distance: %f, movement=%f",finalDistance,movement);
if (movement != 0) {
CGFloat scale = [self scaleAmount: movement];
self.transform = CGAffineTransformScale(self.transform, scale, scale);
NSLog(#"Scaling: %f", scale);
zoomed = YES;
}
}
}
- (void)singleTap: (NSTimer*)theTimer {
// must override
}
- (void)animateSwipe: (int) direction {
// must override
}
It is not working fine on device. can anyone tell that where i am wrong.
When you use any CGAffinTransform.... the value of the frame property becomes undefined. In your code you are using the frame.size.width and frame.size.height to calculate the change in size. After the first iteration of CGAffinTransformScale you would not get the right scale factor. According to the documentation bounds would be the right property for scale calculations.

Class for move, scale and rotate, of a uiimageview

I'm creating a subclass of UIImageView that detects touches, and will move, rotate and scale the image based on the touches. However, I really feel like I'm reinventing the wheel here, and it's driving me nuts. Shouldn't this already exist somewhere?
Does anyone have any examples, or links to a class that is already doing this? Or if you have a class you've written, that'd be helpful too.
Thanks a lot in advance.
I figured it out... I answered my own question.
Hopefully this is useful to someone.
For anyone who is interested, here is the implementation for a UIImageView subclass, that you can use to move, scale, and rotate an image. It works pretty well for me.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if( [touches count] == 1 ) {
float difx = [[touches anyObject] locationInView:self].x - [[touches anyObject] previousLocationInView:self].x;
float dify = [[touches anyObject] locationInView:self].y - [[touches anyObject] previousLocationInView:self].y;
CGAffineTransform newTransform1 = CGAffineTransformTranslate(self.transform, difx, dify);
self.transform = newTransform1;
} else if( [touches count] == 2 ) {
int prevmidx = ([[[touches allObjects] objectAtIndex:0] previousLocationInView:self].x + [[[touches allObjects] objectAtIndex:1] previousLocationInView:self].x) / 2;
int prevmidy = ([[[touches allObjects] objectAtIndex:0] previousLocationInView:self].y + [[[touches allObjects] objectAtIndex:1] previousLocationInView:self].y) / 2;
int curmidx = ([[[touches allObjects] objectAtIndex:0] locationInView:self].x + [[[touches allObjects] objectAtIndex:1] locationInView:self].x) / 2;
int curmidy = ([[[touches allObjects] objectAtIndex:0] locationInView:self].y + [[[touches allObjects] objectAtIndex:1] locationInView:self].y) / 2;
int difx = curmidx - prevmidx;
int dify = curmidy - prevmidy;
CGPoint prevPoint1 = [[[touches allObjects] objectAtIndex:0] previousLocationInView:self];
CGPoint prevPoint2 = [[[touches allObjects] objectAtIndex:1] previousLocationInView:self];
CGPoint curPoint1 = [[[touches allObjects] objectAtIndex:0] locationInView:self];
CGPoint curPoint2 = [[[touches allObjects] objectAtIndex:1] locationInView:self];
float prevDistance = [self distanceBetweenPoint1:prevPoint1 andPoint2:prevPoint2];
float newDistance = [self distanceBetweenPoint1:curPoint1 andPoint2:curPoint2];
float sizeDifference = (newDistance / prevDistance);
CGAffineTransform newTransform1 = CGAffineTransformTranslate(self.transform, difx, dify);
self.transform = newTransform1;
CGAffineTransform newTransform2 = CGAffineTransformScale(self.transform, sizeDifference, sizeDifference);
self.transform = newTransform2;
float prevAngle = [self angleBetweenPoint1:prevPoint1 andPoint2:prevPoint2];
float curAngle = [self angleBetweenPoint1:curPoint1 andPoint2:curPoint2];
float angleDifference = curAngle - prevAngle;
CGAffineTransform newTransform3 = CGAffineTransformRotate(self.transform, angleDifference);
self.transform = newTransform3;
}
}
- (NSInteger)distanceBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2 {
CGFloat deltaX = fabsf(point1.x - point2.x);
CGFloat deltaY = fabsf(point1.y - point2.y);
CGFloat distance = sqrt((deltaY*deltaY)+(deltaX*deltaX));
return distance;
}
- (CGFloat)angleBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2
{
CGFloat deltaY = point1.y - point2.y;
CGFloat deltaX = point1.x - point2.x;
CGFloat angle = atan2(deltaY, deltaX);
return angle;
}
You might also look at Erica Sadun's example from the iphone dev cookbook (oreilly). It's in chapter 8 on gestures and touches.
http://github.com/erica/iphone-3.0-cookbook-/tree/master/C08-Gestures/14-Resize%20And%20Rotate/