How to get PDF annotations when i touch on ipad screen - ios

I have developed an application which displays PDF on ipad using CATiled Layer. So far, so good& But there is a problem which really makes me cut my last hairs. I have a PDF with embedded annotations. Each annotation has an URL. I can find the coordinates of touch area but the question is how I can find if there is an annotation under my finger and how to extract URL to open it in browser?
If anyone can share any thoughts about how this can be done, I will really appreciate your help!
Thanks in advance

Getting the annotations isn't very difficult with CGPDF although it required a little fiddling around for me at first.
//Get the current page ref
CGPDFPageRef currentPdfPage = CGPDFDocumentGetPage(pdfDocumentRef, page);
//Get the page dictionary
CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(currentPdfPage);
CGPDFArrayRef annotsArray;
//Get the Annots array
if(!CGPDFDictionaryGetArray(pageDictionary, "Annots", &annotsArray)) {
//DLog(#"No Annots found for page %d", page);
[self updateProgress];
return;
}
int annotsArrayCount = CGPDFArrayGetCount(annotsArray);
//DLog(#"%d annots found for page %d in file %#", annotsArrayCount, page, _fileName);
NSMutableArray* touchRectsArray = [[NSMutableArray alloc] initWithCapacity:annotsArrayCount];
for (int j=annotsArrayCount; j >= 0; j--) {
int destPageNumber = 0;
NSString* uri = nil;
//DLog(#"%d/%d", j+1, annotsArrayCount);
CGPDFObjectRef aDictObj;
if(!CGPDFArrayGetObject(annotsArray, j, &aDictObj)) {
//DLog(#"%#", #"can't get dictionary object");
continue;
}
CGPDFDictionaryRef annotDict;
if(!CGPDFObjectGetValue(aDictObj, kCGPDFObjectTypeDictionary, &annotDict)) {
//DLog(#"%#", #"can't get annotDict");
continue;
}
//------------
CGPDFDictionaryRef aDict;
CGPDFArrayRef destArray;
if(CGPDFDictionaryGetDictionary(annotDict, "A", &aDict)) {
CGPDFStringRef uriStringRef;
if(CGPDFDictionaryGetString(aDict, "URI", &uriStringRef)) {
char* uriString = (char *)CGPDFStringGetBytePtr(uriStringRef);
uri = [NSString stringWithCString:uriString encoding:NSUTF8StringEncoding];
}
} else {
continue;
}
This will get you the URLs.
Getting the rects:
CGPDFArrayRef rectArray;
if(!CGPDFDictionaryGetArray(annotDict, "Rect", &rectArray)) {
DLog(#"%#", #"can't get Rect");
}
int arrayCount = CGPDFArrayGetCount(rectArray);
CGPDFReal coords[4];
for (int k = 0; k < arrayCount; k++) {
CGPDFObjectRef rectObj;
if(!CGPDFArrayGetObject(rectArray, k, &rectObj)) {
DLog(#"%#", #"can't get rect data");
}
CGPDFReal coord;
if(!CGPDFObjectGetValue(rectObj, kCGPDFObjectTypeReal, &coord)) {
DLog(#"%#", #"can't get coords");
}
coords[k] = coord;
}
CGRect drawRect = [[SharedConfig valueForKey:#"screenSize"] CGRectValue];
BOOL drawBoxIsLandscape = NO;
if (1 < drawRect.size.width/drawRect.size.height) {
drawBoxIsLandscape = YES;
}
CGRect pageRect = CGRectIntegral(CGPDFPageGetBoxRect(currentPdfPage, kCGPDFMediaBox));
landscape = NO;
if (1 < pageRect.size.width/pageRect.size.height) {
landscape = YES;
}
float ratio = 0.0;
//Get the rect of the clickable area
//CGRect coordsRect = CGRectMake(coords[0], coords[1], coords[2], coords[3]);
//Transform to new coordinate system
CGRect originalRect = CGRectMake(coords[0], (pageRect.size.height-(coords[3]-coords[1]))-coords[1], coords[2]-coords[0], coords[3]-coords[1]);
CGPDFInteger pageRotate = 0;
CGPDFDictionaryGetInteger(pageDictionary, "Rotate", &pageRotate);
if (pageRotate == 90 || pageRotate == 270) {
CGFloat temp = pageRect.size.width;
pageRect.size.width = pageRect.size.height;
pageRect.size.height = temp;
ratio = drawRect.size.height / pageRect.size.height;
}
if (drawBoxIsLandscape) {
ratio = landscape ? (drawRect.size.height/pageRect.size.height) : (drawRect.size.height/pageRect.size.width);
if (landscape && drawRect.size.width < pageRect.size.width*ratio) {
ratio = drawRect.size.width/pageRect.size.width;
} else if (!landscape && drawRect.size.height < pageRect.size.width*ratio) {
ratio = drawRect.size.height/pageRect.size.width;
}
} else {
ratio = landscape ? (drawRect.size.height/pageRect.size.width) : (drawRect.size.height/pageRect.size.height);
if (landscape && drawRect.size.width < pageRect.size.height*ratio) {
ratio = drawRect.size.width/pageRect.size.height;
} else if (!landscape && drawRect.size.height < pageRect.size.height*ratio) {
ratio = drawRect.size.height/pageRect.size.height;
}
}
CGRect calculatedRect = CGRectMake(originalRect.origin.x*ratio, originalRect.origin.y*ratio, originalRect.size.width*ratio, originalRect.size.height*ratio);
if ((landscape && !drawBoxIsLandscape) || (!landscape && drawBoxIsLandscape)) {
CGFloat width = calculatedRect.size.width;
calculatedRect.size.width = calculatedRect.size.height;
calculatedRect.size.height = width;
CGFloat yModifier = drawRect.size.height-(pageRect.size.width*ratio);
CGFloat x = calculatedRect.origin.x;
calculatedRect.origin.x = calculatedRect.origin.y;
calculatedRect.origin.y = drawRect.size.height-(x+calculatedRect.size.height)-yModifier;
}
if (nil != uri) {
[touchRectsArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithCGRect:calculatedRect], #"rect", uri, #"targetUrl", nil]];
}
As you can see this bit of code first gets the rectangle of the annotation, transforms it to the device coordinate system, then does some recalculation, sizing and repositioning, based on page to screen ratio, rotation factor, etc. At the end you will have an array of the touch-active areas for that page. For handling the touches the following simple solution can be used:
- (void) tapGesture:(UIGestureRecognizer*)sender
{
if (UIGestureRecognizerStateEnded == sender.state) {
CGPoint touchPoint = [sender locationInView:self.view];
if (nil != self.touchRects) for (int i=0; i<[self.touchRects count]; i++) {
if (CGRectContainsPoint([[[self.touchRects objectAtIndex:i] objectForKey:#"rect"] CGRectValue], touchPoint)) {
if ([[self.touchRects objectAtIndex:i] objectForKey:#"targetUrl"]) {
NSString* targetUrl = [[self.touchRects objectAtIndex:i] objectForKey:#"targetUrl"];
DLog(#"Hit found for target url: %#", targetUrl);
NSURL* url = [NSURL URLWithString:targetUrl];
[[UIApplication sharedApplication] openURL:url];
} return;
}
}
DLog(#"No hit found for touch at %#", NSStringFromCGPoint(touchPoint));
}
}

Related

NodesAtPoint does not find a node

I'm trying to create 10 balloons in my app. I create a random CGPoint to set my node's position and check, in case that already exist a node at this point I try again.
I don't know why, the balloons keep being placed over another balloon.
Any ideia of what I am doing wrong?
Here is my code:
-(void)gerarBaloes:(int)quantidade
{
balloons = [NSMutableArray new];
u_int32_t maxHorizontal = 900;
u_int32_t minHorizontal = 100;
u_int32_t maxVertical = 650;
u_int32_t minVertical = 100;
for (int i=1; i<= quantidade; i++) {
CGPoint posicao = CGPointMake(arc4random_uniform(maxHorizontal - minHorizontal + 1) + minHorizontal, arc4random_uniform(maxVertical - minVertical + 1) + minVertical);
while (![self validPosition:posicao]) {
posicao = CGPointMake(arc4random_uniform(maxHorizontal - minHorizontal + 1) + minHorizontal, arc4random_uniform(maxVertical - minVertical + 1) + minVertical);
}
balao* nBalao = [[balao alloc]initWithPosition:posicao];
SKLabelNode* numero = [[SKLabelNode alloc]initWithFontNamed:#"Arial Rounded MT Bold"];
numero.text = [NSString stringWithFormat:#"%d",i];
numero.zPosition = 1;
nBalao.body.zPosition = 0;
[nBalao addChild:numero];
nBalao.body.name = #"balloon";
[balloons addObject:nBalao];
[self addChild:nBalao];
}
}
And this is my validation method:
-(BOOL)validPosition:(CGPoint)position
{
NSArray* nodes = [self nodesAtPoint:position];
NSLog(#"total de nodes %d",nodes.count);
if (nodes.count > 0) {
for (SKNode* n in nodes) {
if ([n isKindOfClass:[balao class]]) {
return NO;
}
}
return YES;
}else{
return YES;
}
}
Balao.m class:
#implementation balao
-(id)initWithPosition:(CGPoint)pos
{
if (self = [super init]) {
self.position = pos;
int n = arc4random_uniform(4);
_balloonAtlas = [SKTextureAtlas atlasNamed:[NSString stringWithFormat:#"balloon%d",n]];
_explosionFrames = [NSMutableArray array];
int numImages = _balloonAtlas.textureNames.count;
for (int i=1; i<= numImages; i++){
NSString *textureName = [NSString stringWithFormat:#"balloon_%d",i];
SKTexture *temp = [_balloonAtlas textureNamed:textureName];
[_explosionFrames addObject:temp];
}
SKTexture *textInicial = [_explosionFrames[0] copy];
[_explosionFrames removeObjectAtIndex:0];
self.body = [SKSpriteNode spriteNodeWithTexture:textInicial];
[self addChild:_body];
}
return self;
}
- (void)explodeBalloon
{
SKAction* explosao = [SKAction animateWithTextures:_explosionFrames timePerFrame:0.02f resize:NO restore:YES];
[self.body runAction:explosao completion:^(void){
[self removeFromParent];
}];
[self runAction:[SKAction playSoundFileNamed:#"popSound.mp3" waitForCompletion:NO]];
}
This is how the balloons appears:
Edit:
I tried the suggested method, with CGRectCointainsPoint, but it didn't work too. :/
Checking for nodes at a given point is not enough to prevent overlap. You need to check whether the point falls inside the frame of another balloon. You can modify the function like this
-(BOOL)validPosition:(CGPoint)position
{
NSArray* nodes = [self children];
if (nodes.count > 0) {
for (SKNode* n in nodes) {
if ([n isKindOfClass:[balao class]]) {
if (CGRectContainsPoint([n getBalloonFrame], position)) // Changed line
{
return NO
}
}
}
return YES;
}
return YES;
}
CGRectContainsPoint checks whether a given rectangle contains a point.
Inside balao class define the following function. Also note the changed line in the above code.
-(void)getBalloonFrame
{
return CGRectOffset(self.body.frame, self.frame.origin.x, self.frame.origin.y)
}

Grouping Pixels in Objective-C

I am making a drawing app, and I have a NSArray with a list of all the pixels the user forget or didn't clean, what i want is make groups of that list pixels using proximity. so i can highlight all the pixel area with a black circle. this is what i got for the moment but is not grouping well
-(NSMutableArray*)orderMissingPixelsByGroups:(NSMutableArray*)missingPixels
{
NSMutableArray *finalArray=[[NSMutableArray alloc]init];
NSMutableArray *auxArray = [[NSMutableArray alloc]init];
for (int i=0; i<[missingPixels count]; i++) {
NSValue *value = [missingPixels objectAtIndex:i];
if (i<[missingPixels count]-1) {
NSValue *nextValue = [missingPixels objectAtIndex:i+1];
CGPoint point = value.CGPointValue;
CGPoint point2 = nextValue.CGPointValue;
if (abs(point.x-point2.x)<5 ) {
[auxArray addObject:[NSValue valueWithCGPoint:point]];
}
else if (abs(point.y-point2.y)<5){
[auxArray addObject:[NSValue valueWithCGPoint:point]];
}
else
{
[auxArray addObject:[NSValue valueWithCGPoint:point]];
[finalArray addObject:auxArray];
auxArray = [[NSMutableArray alloc]init];
}
}
else
{
[auxArray addObject:value];
[finalArray addObject:auxArray];
}
}
return finalArray;
}
If you have advices I will very thankful.
Yes I can imagine this is not the best approach. Try doing something like this. Note I did not test it also there is just too much room for optimizing this approach but I hope it will help you get a bit better understanding on how to create "blobs". Otherwise you can try to search for some fast approach under "blob" keyword...
- (NSMutableArray *)createBlobsFromPixels:(NSMutableArray *)pixels {
NSMutableArray *initialBlobs = [[NSMutableArray alloc] init];
for(NSValue *pixel in pixels)
{
[initialBlobs addObject:#[pixel]];
}
while (YES) {
NSIndexSet *indexSet = [self joinBlobs:initialBlobs minimumRadius:5.0f];
if(indexSet.count < 2) {
break;
}
else {
[self mergeBlobs:initialBlobs atIndexA:indexSet.firstIndex andIndexB:indexSet.lastIndex];
}
}
return initialBlobs;
}
- (NSIndexSet *)joinBlobs:(NSMutableArray *)blobs minimumRadius:(CGFloat)minRadius {
// this method will try to join 2 blobs
// if successfull it will return an index set with 2 blob indices which should be joined
// if no blobs are able to join the method will return nil
if(blobs.count < 2) {
// can not join a single blub
return nil;
}
NSUInteger count = blobs.count;
// iterate through every pair
for(NSUInteger i=0; i<count-1; i++) {
for(NSUInteger j=i+1; j<count; j++) {
NSArray *blobA = blobs[i];
NSArray *blobB = blobs[j];
// check if any of the pixels from blob A are close enough from any pixel in blob B and merge those two blobs
for(NSValue *pixelA in blobA) {
for(NSValue *pixelB in blobB) {
CGPoint pointA = [pixelA CGPointValue];
CGPoint pointB = [pixelB CGPointValue];
if(fabsf(pointA.x-pointB.x)<minRadius && fabsf(pointA.y-pointB.y)<minRadius) {
// can join these 2 blobs
NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
[indexSet addIndex:i];
[indexSet addIndex:j];
return indexSet; // returns YES as the blob can been joined
}
}
}
}
}
return nil;
}
- (void)mergeBlobs:(NSMutableArray *)blobs atIndexA:(NSUInteger)indexA andIndexB:(NSUInteger)indexB {
NSArray *blobA = blobs[indexA];
NSArray *blobB = blobs[indexB];
[blobs removeObject:blobA];
[blobs removeObject:blobB];
[blobs addObject:[blobA arrayByAddingObjectsFromArray:blobB]];
}

Alpha-beta pruning doing too few iterations for TicTacToe

I am currently adapting my Minimax algorithm to take into account alpha-beta pruning. I'm aiming for 18297 iterations, but currently I only get 14801. I am not sure where I am losing the iterations, and any help would be appreciated.
Here is my code:
static int iterations = 0;
- (int) minimaxWithRoot:(Board *) board withDepth: (NSInteger) depth andMaximisingPlayer:(BOOL)maxPlayer andAlpha:(int)alpha beta:(int)beta
{
iterations = iterations + 1;
if (board.gameOver || [[board possibleMoves] count] == 0) {
int score = [self scoreForBoard:board];
return score;
}
if (maxPlayer)
{
for (NSValue *moveWrapper in [board possibleMoves]) {
CGPoint move = moveWrapper.CGPointValue;
Board *newBoard = [board copy];
[newBoard playCrossMove:move];
int value = [self minimaxWithRoot:newBoard withDepth:depth - 1 andMaximisingPlayer:NO andAlpha:alpha beta:beta];
if (value > alpha) {
alpha = value;
self.chosenMove = move;
}
if (alpha >= beta) {
break;
}
}
return alpha;
} else {
for (NSValue *moveWrapper in [board possibleMoves]) {
CGPoint move = moveWrapper.CGPointValue;
Board *newBoard = [board copy];
[newBoard playCircleMove:move];
int value = [self minimaxWithRoot:newBoard withDepth:depth - 1 andMaximisingPlayer:YES andAlpha:alpha beta:beta];
if (value < beta) {
beta = value;
self.chosenMove = move;
}
if (beta <= alpha) {
break;
}
}
return beta;
}
}

Cocos2d 3.0 + Chipmunk + CCAnimation: moving physics body with animated object. How?

I have a boat with attached physics body. This boat is static physics body. Boat moving with CCAnimateMoveTo from left to right. When I tap on screen my character fall down. I detect collisions well. But I want that after collision my character just fall on boat and keep moving with it. Character is dynamic body. Link to sample video: Sample video
Here I create a boat:
- (void)createBoat
{
currentBoat = [CCSprite spriteWithImageNamed:#"Boat.png"];
currentBoat.position = ccp(0 - currentBoat.boundingBox.size.width, winSize.height * 0.2);
// currentBoat.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){0, 0, currentBoat.contentSize.width, currentBoat.contentSize.height * 0.5} cornerRadius:0];
CGPoint shape[6];
shape[0] = ccp(0, 30);
shape[1] = ccp(64, 10);
shape[2] = ccp(128, 30);
shape[3] = ccp(128, 0);
shape[4] = ccp(0, 0);
shape[5] = ccp(0, 30);
currentBoat.physicsBody = [CCPhysicsBody bodyWithPolylineFromPoints:shape count:6 cornerRadius:0 looped:NO];
currentBoat.physicsBody.type = CCPhysicsBodyTypeStatic;
currentBoat.physicsBody.collisionGroup = #"BoatGroup";
currentBoat.physicsBody.collisionType = #"BoatCollision";
[physicsWorld addChild:currentBoat z:PHYSICS_Z+3];
id actionMoveBoat = [[CCActionMoveTo alloc] initWithDuration:5.0f position:ccp(winSize.width + currentBoat.boundingBox.size.width, currentBoat.position.y)];
id actionMethod = [CCActionCallFunc actionWithTarget:self selector:#selector(createBoat)];
[currentBoat runAction:[CCActionSequence actions:actionMoveBoat, [[CCActionRemove alloc] init], actionMethod, nil]];
}
Character creation:
- (void)createCharacter
{
if (needCharacter)
{
CCSprite *newCharacter = [CCSprite spriteWithImageNamed:#"Character.png"];
newCharacter.opacity = 0;
newCharacter.position = ccp(winSize.width * 0.5, winSize.height * 0.76);
newCharacter.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, newCharacter.contentSize} cornerRadius:0];
newCharacter.physicsBody.affectedByGravity = NO;
newCharacter.physicsBody.allowsRotation = YES;
newCharacter.physicsBody.collisionGroup = #"playerGroup";
newCharacter.physicsBody.collisionType = #"playerCollision";
[physicsWorld addChild:newCharacter z:PHYSICS_Z+4];
id actionFadeIn = [[CCActionFadeIn alloc] initWithDuration:0.5];
[newCharacter runAction:actionFadeIn];
[allCharacters addObject:newCharacter];
needCharacter = false;
touchDone = false;
}
}
Then detection touch and collision:
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CCNode *lastCharacter = [allCharacters lastObject];
if (!touchDone)
{
[lastCharacter.physicsBody applyImpulse:ccp(0, 300)];
lastCharacter.physicsBody.type = CCPhysicsBodyTypeDynamic;
lastCharacter.physicsBody.affectedByGravity = YES;
touchDone = true;
}
}
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair playerCollision:(CCNode *)currentCharacterC BoatCollision:(CCNode *)currentBoatC {
currentCharacterC.physicsBody.collisionType = #"tmpCollision";
CCLOG(#"score++");
if ([allCharacters containsObject:currentCharacterC])
{
score++;
[scores setString:[NSString stringWithFormat:#"%d", score]];
[allCharacters removeAllObjects];
if (lives != 0)
{
needCharacter = true;
[self createCharacter];
}
}
CCLOG(#"allCharacters = %#", allCharacters);
return YES;
}
well I too faced the same problem, tried increasing the friction/surface velocity etc, it didn't really work well.
Finally had to resolve it my own way, whenever player lands on any body, you keep a pointer to that body as say _bodyUnderFeet of the player object.
Now, in the update loop add the velocity of the _bodyUnderFeet to the players calculated velocity. See the use of zeroVel_x
Sample code is here:
void Player::update(float dt)
{
float zeroVel_x = 0;
if(_bodyUnderFeet != NULL)
{
zeroVel_x = _bodyUnderFeet->v.x;
}
cpBody *bd = getCPBody();
assert(bd);
//log("Body angle %f", bd->a);
//check forward backward or at rest
float accel = _accelGround;
if(_onGroundBoost < UP_BOOST)
{
accel = _accelAir;
}
if(_touchPressedB)
{
if(!isFlippedX())
{
setFlippedX(true);
}
//cpBodySetVel(bd, cpv(cpBodyGetVel(bd).x - accel*0.25, 0));
cpVect bdv = cpBodyGetVel(bd);
bdv.x = bdv.x - zeroVel_x;
if(bdv.x > 0) bdv.x = 0;
if(bdv.x > -_maxVelocity.x)
cpBodySetVel(bd, cpv(zeroVel_x + bdv.x - accel*0.25, bdv.y));
}
else if(_touchPressedF)
{
if(isFlippedX())
{
setFlippedX(false);
}
//cpBodySetVel(bd, cpv(cpBodyGetVel(bd).x + accel*0.25, 0));
cpVect bdv = cpBodyGetVel(bd);
bdv.x = bdv.x - zeroVel_x;
if(bdv.x < 0) bdv.x = 0;
if(bdv.x < _maxVelocity.x)
cpBodySetVel(bd, cpv(zeroVel_x+bdv.x + accel*0.25, bdv.y));
}
else
{
cpFloat bd_x = cpBodyGetVel(bd).x;
bd_x = bd_x - zeroVel_x;
if(bd_x>0)
{
if(bd_x > accel*0.25)
{
cpBodySetVel(bd, cpv(zeroVel_x+bd_x - accel*0.25, cpBodyGetVel(bd).y));
}
else
{
cpBodySetVel(bd, cpv(zeroVel_x+0, cpBodyGetVel(bd).y));
}
}
else if(bd_x < 0)
{
if(bd_x < accel*0.25)
{
cpBodySetVel(bd, cpv(zeroVel_x+bd_x + accel*0.25, cpBodyGetVel(bd).y));
}
else
{
cpBodySetVel(bd, cpv(zeroVel_x+0, cpBodyGetVel(bd).y));
}
}
}
//check jump
if(_touchPressedJ)
{
if(_onGroundBoost)
{
cpVect bdv = cpBodyGetVel(bd);
if(bdv.y < 0) bdv.y = 0;
if((bdv.y + _accelUp) < _maxVelocity.y)
{
cpBodySetVel(bd, cpv(bdv.x, bdv.y + _accelUp));
--_onGroundBoost;
}
else
{
cpBodySetVel(bd, cpv(bdv.x, _maxVelocity.y));
_onGroundBoost = 0;
}
}
}
//check shots
if(_touchPressedS)
{
if(!_bulletFired)
{
}
}
//check home
if(_touchPressedH)
{
}
boundRotation(bd);
}
I think,
you can increase the friction between man and boat after he fall down. and reduce the elasticity . then the boat can 'take' the man go together...
just a trick.

How to draw a route between two rectangular Blocks on a custom map using A-Star Algorithm?

I am very new to objective-C, so the task seems typical for me. I am plotting a custom map of rectangular blocks, and also need to draw an interactive route between two given blocks. All the thing is fine, but the problem is that the route drawn using A-Star algorithm goes diagonally looks very scattered. I want a smooth route made by simple lines without any diagonal.
-(void)findPath:(int)startX :(int)startY :(int)endX :(int)endY
{
int x,y;
int newX,newY;
int currentX,currentY;
NSMutableArray *openList, *closedList;
if((startX == endX) && (startY == endY))
return;
openList = [NSMutableArray array];
//BOOL animate = [shouldAnimateButton state];
if(animate)
pointerToOpenList = openList;
closedList = [NSMutableArray array];
PathFindNode *currentNode = nil;
PathFindNode *aNode = nil;
PathFindNode *startNode = [PathFindNode node];
startNode->nodeX = startX;
startNode->nodeY = startY;
startNode->parentNode = nil;
startNode->cost = 0;
[openList addObject: startNode];
while([openList count])
{
currentNode = [self lowestCostNodeInArray: openList];
if((currentNode->nodeX == endX) && (currentNode->nodeY == endY))
{
//********** PATH FOUND ********************
aNode = currentNode->parentNode;
while(aNode->parentNode != nil)
{
tileMap[aNode->nodeX][aNode->nodeY] = TILE_MARKED;
aNode = aNode->parentNode;
}
return;
//*****************************************//
}
else
{
[closedList addObject: currentNode];
[openList removeObject: currentNode];
currentX = currentNode->nodeX;
currentY = currentNode->nodeY;
for(y=-1;y<=1;y++)
{
newY = currentY+y;
for(x=-1;x<=1;x++)
{
newX = currentX+x;
if(y || x) //avoid 0,0
{
if((newX>=0)&&(newY>=0)&&(newX<H)&&(newY<W))
{
if(![self nodeInArray: openList withX: newX Y:newY])
{
if(![self nodeInArray: closedList withX: newX Y:newY])
{
if(![self spaceIsBlocked: newX :newY])
{
//the 'cost':
aNode = [PathFindNode node];
aNode->nodeX = newX;
aNode->nodeY = newY;
aNode->parentNode = currentNode;
aNode->cost = currentNode->cost + 1;
//distance, added to the existing cost
aNode->cost += (abs((newX) - endX) + abs((newY) - endY));
//aNode->cost += MAX(abs(newX - endX), abs(newY - endY));
//aNode->cost += sqrt(pow(newX - endX, 2) + pow(newY - endY, 2));
NSLog(#"Path: %d",aNode->cost);
[openList addObject: aNode];
// if(animate) // animation
// [self setNeedsDisplay];
}
}
}
}
}
}
}
}
}
//**** NO PATH FOUND *****
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"OOPs!!" message:#"Couldn't find a path, Please try for another nearest Exhibitor." delegate:self cancelButtonTitle:#"Done" otherButtonTitles:nil, nil];
[alert show];
}
Finally i am running a loop to check tileMap[][], and the node array tileMap[x][y] marked as TILE_MARKED is the nodes to be drawn in blue colored route.
I am attaching the image below, can anyone kindly help me?
Thanks in advance and have a great day.
-asim

Resources