Authored by Jon Hjelle

Check to make sure targetZoom is within minZoom and maxZoom whether the zoom is animated or not

@@ -450,54 +450,75 @@ @@ -450,54 +450,75 @@
450 [self zoomByFactor:zoomFactor near:pivot animated:animated withCallback:nil]; 450 [self zoomByFactor:zoomFactor near:pivot animated:animated withCallback:nil];
451 } 451 }
452 452
  453 +- (BOOL)shouldZoomToTargetZoom:(float)targetZoom withZoomFactor:(float)zoomFactor {
  454 + //bools for syntactical sugar to understand the logic in the if statement below
  455 + BOOL zoomAtMax = ([self zoom] == [self maxZoom]);
  456 + BOOL zoomAtMin = ([self zoom] == [self minZoom]);
  457 + BOOL zoomGreaterMin = ([self zoom] > [self minZoom]);
  458 + BOOL zoomLessMax = ([self zoom] < [self maxZoom]);
  459 +
  460 + //zooming in zoomFactor > 1
  461 + //zooming out zoomFactor < 1
  462 +
  463 + if ((zoomGreaterMin && zoomLessMax) || (zoomAtMax && zoomFactor<1) || (zoomAtMin && zoomFactor>1))
  464 + {
  465 + return YES;
  466 + }
  467 + else
  468 + {
  469 + return NO;
  470 + }
  471 +}
  472 +
453 - (void)zoomByFactor: (float) zoomFactor near:(CGPoint) pivot animated:(BOOL) animated withCallback:(id<RMMapContentsAnimationCallback>)callback 473 - (void)zoomByFactor: (float) zoomFactor near:(CGPoint) pivot animated:(BOOL) animated withCallback:(id<RMMapContentsAnimationCallback>)callback
454 { 474 {
455 zoomFactor = [self adjustZoomForBoundingMask:zoomFactor]; 475 zoomFactor = [self adjustZoomForBoundingMask:zoomFactor];
456 float zoomDelta = log2f(zoomFactor); 476 float zoomDelta = log2f(zoomFactor);
457 float targetZoom = zoomDelta + [self zoom]; 477 float targetZoom = zoomDelta + [self zoom];
458 478
  479 + if (targetZoom == [self zoom]){
  480 + return;
  481 + }
  482 + // clamp zoom to remain below or equal to maxZoom after zoomAfter will be applied
  483 + if(targetZoom > [self maxZoom]){
  484 + zoomFactor = exp2f([self maxZoom] - [self zoom]);
  485 + }
  486 +
459 if (animated) 487 if (animated)
460 { 488 {
461 - // goal is to complete the animation in animTime seconds  
462 - static const float stepTime = kZoomAnimationStepTime;  
463 - static const float animTime = kZoomAnimationAnimationTime;  
464 - float nSteps = animTime / stepTime;  
465 - float zoomIncr = zoomDelta / nSteps; 489 + if ([self shouldZoomToTargetZoom:targetZoom withZoomFactor:zoomFactor])
  490 + {
  491 + // goal is to complete the animation in animTime seconds
  492 + static const float stepTime = kZoomAnimationStepTime;
  493 + static const float animTime = kZoomAnimationAnimationTime;
  494 + float nSteps = animTime / stepTime;
  495 + float zoomIncr = zoomDelta / nSteps;
  496 +
  497 + CFDictionaryRef pivotDictionary = CGPointCreateDictionaryRepresentation(pivot);
  498 + /// \bug magic string literals
  499 + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
  500 + [NSNumber numberWithFloat:zoomIncr], @"zoomIncr",
  501 + [NSNumber numberWithFloat:targetZoom], @"targetZoom",
  502 + pivotDictionary, @"pivot",
  503 + callback, @"callback", nil];
  504 + CFRelease(pivotDictionary);
  505 + [NSTimer scheduledTimerWithTimeInterval:stepTime
  506 + target:self
  507 + selector:@selector(animatedZoomStep:)
  508 + userInfo:userInfo
  509 + repeats:YES];
  510 + } else
  511 + {
  512 + if([self zoom] > [self maxZoom])
  513 + [self setZoom:[self maxZoom]];
  514 + if([self zoom] < [self minZoom])
  515 + [self setZoom:[self minZoom]];
  516 + }
466 517
467 - CFDictionaryRef pivotDictionary = CGPointCreateDictionaryRepresentation(pivot);  
468 - /// \bug magic string literals  
469 - NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:  
470 - [NSNumber numberWithFloat:zoomIncr], @"zoomIncr",  
471 - [NSNumber numberWithFloat:targetZoom], @"targetZoom",  
472 - pivotDictionary, @"pivot",  
473 - callback, @"callback", nil];  
474 - CFRelease(pivotDictionary);  
475 - [NSTimer scheduledTimerWithTimeInterval:stepTime  
476 - target:self  
477 - selector:@selector(animatedZoomStep:)  
478 - userInfo:userInfo  
479 - repeats:YES];  
480 } 518 }
481 else 519 else
482 { 520 {
483 - if (targetZoom == [self zoom]){  
484 - return;  
485 - }  
486 - // clamp zoom to remain below or equal to maxZoom after zoomAfter will be applied  
487 - if(targetZoom > [self maxZoom]){  
488 - zoomFactor = exp2f([self maxZoom] - [self zoom]);  
489 - }  
490 -  
491 - //bools for syntactical sugar to understand the logic in the if statement below  
492 - BOOL zoomAtMax = ([self zoom] == [self maxZoom]);  
493 - BOOL zoomAtMin = ([self zoom] == [self minZoom]);  
494 - BOOL zoomGreaterMin = ([self zoom] > [self minZoom]);  
495 - BOOL zoomLessMax = ([self zoom] < [self maxZoom]);  
496 -  
497 - //zooming in zoomFactor > 1  
498 - //zooming out zoomFactor < 1  
499 -  
500 - if ((zoomGreaterMin && zoomLessMax) || (zoomAtMax && zoomFactor<1) || (zoomAtMin && zoomFactor>1)) 521 + if ([self shouldZoomToTargetZoom:targetZoom withZoomFactor:zoomFactor])
501 { 522 {
502 [mercatorToScreenProjection zoomScreenByFactor:zoomFactor near:pivot]; 523 [mercatorToScreenProjection zoomScreenByFactor:zoomFactor near:pivot];
503 [imagesOnScreen zoomByFactor:zoomFactor near:pivot]; 524 [imagesOnScreen zoomByFactor:zoomFactor near:pivot];