How to overlay MKPolyline on top of different maps - mkmapview

So I draw a MKPolyline with the users updated CLLocationCoordinates as per usual. When my quits and starts again, all of the past points are loaded onto the mapview to be displayed with
routeLine = [MKPolyline polylineWithCoordinates:clCoordinates count:numberOfSteps];
[_mapView addOverlay:routeLine];
and in MKOverlayRenderer method I have
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [[UIColor whiteColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
}
This all works a treat, but problems arise when I change the type of map with
[self resetMapViewAndRasterOverlayDefaults];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
_rasterOverlay = [[MBXRasterTileOverlay alloc] initWithMapID:#"jonobolitho.j834jdml"];
_rasterOverlay.delegate = self;
[_mapView addOverlay:_rasterOverlay];
Note, I have the resetMapViewAndRasterOverlayDefaults helper method
// Reset the MKMapView to some reasonable defaults.
//
_mapView.mapType = MKMapTypeStandard;
_mapView.zoomEnabled = YES;
[_mapView removeAnnotations:_rasterOverlay.markers];
[_mapView removeOverlay:_rasterOverlay];
[_rasterOverlay invalidateAndCancel];
I am using MBXMapKit to display the maps. The maps display correctly, but the polyline isn't shown on top of the map. The map just loads over the top of my polyline (routeLine). I know this because in between the tiles of the new map I can see the routeLine underneath.
So basically is there a way to load the MKPolyline but always keep it on the top layer of the map, even if it changes?

Instead of:
[_mapView addOverlay:_rasterOverlay];
You want:
[_mapView insertOverlay:_rasterOverlay belowOverlay:routeLine];
Or something similar. Overlays have an order.

Related

Positioning sprites inside scene

I would like when i create all my sprites to get centred in the screen, but that is not the case, i have a sprite when i set it's position to CGPointMake(self.size.width / 2, self.size.height / 2) it gets centred vertically but not horizontally, when i set it to CGPointMake(0, 0) it sets at the bottom of the screen with only half of it's body visible ( which is what you expect) but horizontally it doesn't get positioned right ( half his vertical body appears ) until i set it's X to 300.
How come the sprite's Y position gets set right but the X doesn't ?
scene.scaleMode = .AspectFill
and i haven't set any anchorPoint, 4' screen.
UPDATE:
I'm using Portrait, played around with different scaleMode and found out that the perfect (0, 0) that sets the sprite on the bottom left is:
scene.scaleMode = .ResizeFill
It also works fine with different screen sizes,but (self.size.width / 2) puts it further to the left.Do you think it's the best setting for all SpriteKit Portrait projects?
I tried to reproduce what you are saying, but I couldn't, either using .sks file or not for loading the scene. Also I've produced good results on both 7.1 and 8.1 simulators...The thing is that simulators sometimes could be tricky and not 100% reliable, so you should not trust them much.
I don't know if this will help you, but you should consider it...In Xcode 5 projects scene is programmatically created to have a size of the view. Basically it's done in viewDidLoad method like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
GameScene * scene = [GameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
Or using viewWillLayoutSubviews like LearnCocos2D pointed:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
skView.showsDrawCount = YES;
//skView.showsQuadCount = YES;
skView.showsPhysics = YES;
skView.ignoresSiblingOrder = YES;
if(!skView.scene){
// Create and configure the scene.
GameScene * scene = [GameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
}
But Xcode 6 uses an SKS file:
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// Configure the view.
let skView = self.view as SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
}
}
If you look at the GameScene.sks you can see that the default scene size is 1024x768.
Try to print your scene size as well as view's bounds size to see actuall sizes. You can use something like:
println("view.bounds\(view.bounds), self.size\(self.size)")
I don't know if any of this helped, but I hope it will lead you somewhere. Goodluck!

UICollectionView layout, cells spaced far out

I have a UICollectionView that displays images. My images are size 114x133 but for some reason the actual UICollectionVewCell is bigger than this (I can see this because I set the cell background to red). Because of this the view can display only 2 images and there is a huge gap between the two. I am implementing the following
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
UIImage* img = [UIImage imageNamed:#"thumbnail_frame.png"];
return img.size;
}
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(1, 1, 1, 1);
}
I am creating the cell's contentview programmatically (i.e init imageView etc).
I face the same problem in a different view where I am creating the whole view programmatically. There I do:
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.minimumInteritemSpacing=10;
flowLayout.minimumLineSpacing= 30;
flowLayout.sectionInset = UIEdgeInsetsMake(5, 5, 5, 5);
if(collectionView != nil) {
[collectionView removeFromSuperview];
}
CGRect frm= CGRectMake(45, 80, 250, 230);
collectionView = [[UICollectionView alloc] initWithFrame:frm collectionViewLayout:flowLayout];//(0, 0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:flowLayout];
collectionView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
collectionView.clipsToBounds = YES;
collectionView.layer.cornerRadius = 10.0;
collectionView.dataSource = self;
collectionView.delegate = self;
[collectionView registerClass:[YourPicCollectionViewCell class] forCellWithReuseIdentifier:#"YourPicCell"];
Again there is either a big gap between two images, or if I make the width smaller, there are 3 images but the right-most one is half-visible.
I tinkered with spacing but it doesn't seem to work. What could be the problem?
I think instead of resizing the cell.. you should try resizing the collection view. Make sure that the collection view has just enough width to hold 2 items in a row. This is because if the collection view has more width than the cells, then then will stick to the extreme right and left. If it's too short, then only one cell will be displayed at the centre (Assuming that you are trying to keep 2 cells in a row).
The reason that one of your cell was half visible is that the collection view had more width than its super view.
So doing the following would help you get what you want..
Frame your collection view such that its less than its super view and should be equal to (numberOfCells X width) + ((numberOfCells-1) X cellGap).
If it's a custom collection view cell try adding constraints to the imageView such that the image sticks to the cells edges.

Centre location not updating, puts me in the middle of the ocean?

Stuck on something very basic, just started up with MKMapView and trying to get it to zoom in on my location.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate; }
This code seems to just not be working, I understand it usually takes a little bit of time to get the location and i have left it for a while with now luck. However the location shows up correctly but it doesn't centre in on this (it centres into the very middle of the map just off west africa)
I also have the following code in viewDidLoad, which seems to be correct as it zooms in to the specified height, just not place.
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 20000, 20000);
[self.mapView setRegion:region animated:YES];
EDIT: It seems to be working on the simulator now after pressing back once or twice and then re-viewing to the map. But it doesn't work on my iPhone still. I have checked all the location services settings and they seem to be all on.
I use the following code to set center and span to be shown in MapView. It should work.
MKCoordinateRegion region = {{0,0},{.5,.5}};
region.center.latitude = doubleLattitude;
region.center.longitude = doubleLongitude;
[mapView setRegion:region animated:YES];
If a MKMapView centers to just west of Gabon, it's very likely that one of your objects is nil and thus the coordinate is 0° latitude and 0° longitude. You can easily test it by setting a breakpoint in the debugger and analyzing your objects.
self.mapView.centerCoordinate = self.mapView.userLocation.location.coordinate;
Does not center map on user location.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation is called only first time when device gets user location,
better use - (void)locationManager:didUpdateToLocation: fromLocation:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if(newLocation.horizontalAccuracy>0)
{
// set center of map (span will not be changed in this case)
[mymap setCenterCoordinate:newLocation.coordinate animated:YES];
// or use region to specify both span and center
MKCoordinateRegion region.span.latitudeDelta = .05 ;
region.span.longitudeDelta = .05 ;
region.center.latitude = newLocation.coordinate.latitude ;
region.center.longitude = newLocation.coordinate.longitude ;
[mymap setRegion:region animated:TRUE];
}
}

problem: menu does not show in cocos2d layer

I am trying to add menu to a layer in cocos2d but it just does not appear. Here's the code which is written in init method of a layer
CCMenuItem *aButton = [CCMenuItemImage itemFromNormalImage:#"btnImg.png" selectedImage:#"btnImgSel.png" target:self selector:#selector(buttonPressed:)];
aButton.position = ccp(60.0,30.0);
CCMenu *aMenu = [CCMenu menuWithItems:aButton, nil];
aMenu.position = ccp(500.0,20);
[self addChild:aMenu];
Nothing is overlapping the position i specified for menu. Is anything wrong in the code?
Try like these:-
CCLayer *menuLayer1 = [[[CCLayer alloc] init]autorelease];
[self addChild:menuLayer1];
CCMenuItemImage *startButton1 = [CCMenuItemImage
itemFromNormalImage:#"Play.png"
selectedImage:#"Play.png"
target:self
selector:#selector(Play:)];
CCMenu *menu1 = [CCMenu menuWithItems: startButton1,nil];
menu1.position = ccp(157,157 );
[menu1 alignItemsVertically ];
[menuLayer1 addChild: menu1];
For those who are facing an irritating situation where the code is right but menu items are not showing then check the image file. I was using .png images and they were refusing to be displayed. There was something internally wrong with the file, so I replaced that file and it solved the problem :)
Is the iPad your target platform? If so the "menu" should appear at the bottom of the screen. To display the Menu on iPhone adjust the "a.Menu.position" to anything lower than 480 in the first attribute of ccp

How to get text in a CATextLayer to be clear

I've made a CALayer with an added CATextLayer and the text comes out blurry. In the docs, they talk about "sub-pixel antialiasing", but that doesn't mean much to me. Anyone have a code snippet that makes a CATextLayer with a bit of text that is clear?
Here's the text from Apple's documentation:
Note: CATextLayer disables sub-pixel antialiasing when rendering text.
Text can only be drawn using sub-pixel antialiasing when it is
composited into an existing opaque background at the same time that
it's rasterized. There is no way to draw subpixel-antialiased text by
itself, whether into an image or a layer, separately in advance of
having the background pixels to weave the text pixels into. Setting
the opacity property of the layer to YES does not change the rendering
mode.
The second sentence implies that one can get good looking text if one composites it into an existing opaque background at the same time that it's rasterized. That's great, but how do I composite it and how do you give it an opaque background and how do you rasterize it?
The code they use in their example of a Kiosk Menu is as such: (It's OS X, not iOS, but I assume it works!)
NSInteger i;
for (i=0;i<[names count];i++) {
CATextLayer *menuItemLayer=[CATextLayer layer];
menuItemLayer.string=[self.names objectAtIndex:i];
menuItemLayer.font=#"Lucida-Grande";
menuItemLayer.fontSize=fontSize;
menuItemLayer.foregroundColor=whiteColor;
[menuItemLayer addConstraint:[CAConstraint
constraintWithAttribute:kCAConstraintMaxY
relativeTo:#"superlayer"
attribute:kCAConstraintMaxY
offset:-(i*height+spacing+initialOffset)]];
[menuItemLayer addConstraint:[CAConstraint
constraintWithAttribute:kCAConstraintMidX
relativeTo:#"superlayer"
attribute:kCAConstraintMidX]];
[self.menuLayer addSublayer:menuItemLayer];
} // end of for loop
Thanks!
EDIT: Adding the code that I actually used that resulted in blurry text. It's from a related question I posted about adding a UILabel rather than a CATextLayer but getting a black box instead. http://stackoverflow.com/questions/3818676/adding-a-uilabels-layer-to-a-calayer-and-it-just-shows-black-box
CATextLayer* upperOperator = [[CATextLayer alloc] init];
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGFloat components1[4] = {1.0, 1.0, 1.0, 1.0};
CGColorRef almostWhite = CGColorCreate(space,components1);
CGFloat components2[4] = {0.0, 0.0, 0.0, 1.0};
CGColorRef almostBlack = CGColorCreate(space,components2);
CGColorSpaceRelease(space);
upperOperator.string = [NSString stringWithFormat:#"13"];
upperOperator.bounds = CGRectMake(0, 0, 100, 50);
upperOperator.foregroundColor = almostBlack;
upperOperator.backgroundColor = almostWhite;
upperOperator.position = CGPointMake(50.0, 25.0);
upperOperator.font = #"Helvetica-Bold";
upperOperator.fontSize = 48.0f;
upperOperator.borderColor = [UIColor redColor].CGColor;
upperOperator.borderWidth = 1;
upperOperator.alignmentMode = kCAAlignmentCenter;
[card addSublayer:upperOperator];
[upperOperator release];
CGColorRelease(almostWhite);
CGColorRelease(almostBlack);
EDIT 2: See my answer below for how this got solved. sbg.
Short answer — You need to set the contents scaling:
textLayer.contentsScale = [[UIScreen mainScreen] scale];
A while ago I learned that when you have custom drawing code, you have to check for the retina display and scale your graphics accordingly. UIKit takes care of most of this, including font scaling.
Not so with CATextLayer.
My blurriness came from having a .zPosition that was not zero, that is, I had a transform applied to my parent layer. By setting this to zero, the blurriness went away, and was replaced by serious pixelation.
After searching high and low, I found that you can set .contentsScale for a CATextLayer and you can set it to [[UIScreen mainScreen] scale] to match the screen resolution. (I assume this works for non-retina, but I haven't checked - too tired)
After including this for my CATextLayer the text became crisp. Note - it's not necessary for the parent layer.
And the blurriness? It comes back when you're rotating in 3D, but you don't notice it because the text starts out clear and while it's in motion, you can't tell.
Problem solved!
Swift
Set the text layer to use the same scale as the screen.
textLayer.contentsScale = UIScreen.main.scale
Before:
After:
Before setting shouldRasterize, you should:
set the rasterizationScale of the base layer you are going to rasterize
set the contentsScale property of any CATextLayers and possibly other types of layers(it never hurts to do it)
If you don't do #1, then the retina version of sub layers will look blurry, even for normal CALayers.
- (void)viewDidLoad {
[super viewDidLoad];
CALayer *mainLayer = [[self view] layer];
[mainLayer setRasterizationScale:[[UIScreen mainScreen] scale]];
CATextLayer *messageLayer = [CATextLayer layer];
[messageLayer setForegroundColor:[[UIColor blackColor] CGColor]];
[messageLayer setContentsScale:[[UIScreen mainScreen] scale]];
[messageLayer setFrame:CGRectMake(50, 170, 250, 50)];
[messageLayer setString:(id)#"asdfasd"];
[mainLayer addSublayer:messageLayer];
[mainLayer setShouldRasterize:YES];
}
First off I wanted to point out that you've tagged your question with iOS, but constraint managers are only available on OSX, so I'm not sure how you're getting this to work unless you've been able to link against it in the simulator somehow. On the device, this functionality is not available.
Next, I'll just point out that I create CATextLayers often and never have the blurring problem you're referring to so I know it can be done. In a nutshell this blurring occurs because you are not positioning your layer on the whole pixel. Remember that when you set the position of a layer, you use a float values for the x and y. If those values have numbers after the decimal, the layer will not be positioned on the whole pixel and will therefore give this blurring effect--the degree of which depending upon the actual values. To test this, just create a CATextLayer and explicitly add it to the layer tree ensuring that your position parameter is on a whole pixel. For example:
CATextLayer *textLayer = [CATextLayer layer];
[textLayer setBounds:CGRectMake(0.0f, 0.0f, 200.0f, 30.0f)];
[textLayer setPosition:CGPointMake(200.0f, 100.0f)];
[textLayer setString:#"Hello World!"];
[[self menuLayer] addSublayer:textLayer];
If your text is still blurry, then there is something else wrong. Blurred text on your text layer is an artifact of incorrectly written code and not an intended capability of the layer. When adding your layers to a parent layer, you can just coerce the x and y values to the nearest whole pixel and it should solve your blurring problem.
You should do 2 things, the first was mentioned above:
Extend CATextLayer and set the opaque and contentsScale properties to properly support retina display, then render with anti aliasing enabled for text.
+ (TextActionLayer*) layer
{
TextActionLayer *layer = [[TextActionLayer alloc] init];
layer.opaque = TRUE;
CGFloat scale = [[UIScreen mainScreen] scale];
layer.contentsScale = scale;
return [layer autorelease];
}
// Render after enabling with anti aliasing for text
- (void)drawInContext:(CGContextRef)ctx
{
CGRect bounds = self.bounds;
CGContextSetFillColorWithColor(ctx, self.backgroundColor);
CGContextFillRect(ctx, bounds);
CGContextSetShouldSmoothFonts(ctx, TRUE);
[super drawInContext:ctx];
}
If you came searching here for a similar issue for a CATextLayer in OSX, after much wall head banging, I got the sharp clear text by doing:
text_layer.contentsScale = self.window!.backingScaleFactor
(I also set the views background layer contentsScale to be the same).
This is faster and easier: you just need to set contentsScale
CATextLayer *label = [[CATextLayer alloc] init];
[label setFontSize:15];
[label setContentsScale:[[UIScreen mainScreen] scale]];
[label setFrame:CGRectMake(0, 0, 50, 50)];
[label setString:#"test"];
[label setAlignmentMode:kCAAlignmentCenter];
[label setBackgroundColor:[[UIColor clearColor] CGColor]];
[label setForegroundColor:[[UIColor blackColor] CGColor]];
[self addSublayer:label];

Resources