CALayer addSublayer question

Discussion in 'iPhone/iPad Programming' started by Cbswe, Aug 17, 2010.

  1. macrumors member


    Im trying to render points of interests on top of a CATiledLayer map, but they wont render.

    I've added the map and then the POIs with addSublayer to the UIView.

    I've checked that the coordinates is reasonable so that at least one should show up. I've also tried setting transparency to the map layer and nothing is rendered behind.

    The way the CATiledLayer and the CALayers is rendered is that I've got a NSObject that overrides drawLayer and the layers delegate properties are set to these NSObjects.

    Any help is much appreciated!

    I hope my problem description isn't too fuzzy, please ask me to explain anything unclear further.

    Thanks in advance
  2. Moderator


    Staff Member

    Can you post some of the code? Are you 100% the layers are rendering in the correct order? You're not rendering the overlay then the tiled layer over the top?
  3. macrumors member


    Actually they are rendering in the "wrong" order. The pois first, then the map. Witch is kind of wierd because I add the map first and then the pois and I've set the pois zPosition to 1 (the map is 0). Also in that case, shouldn't the pois have shown with the map transparency on?
  4. Moderator


    Staff Member

    Maybe. I've not looked too closely at how the layer system draws. What is going on in your drawLayer method?
  5. macrumors member

    The drawLayer renders png-images. But I had the "upside-down-problem" (the png coordinate system being in the other vertical direction then Quartz) so I begin with flipping the image. In the map drawLayer its:

    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {	
            CGContextTranslateCTM(ctx, 0, imgH);
    	CGContextScaleCTM(ctx, 1.0, -1.0);
    	CGContextDrawImage(ctx, drawRect, img);
    and in the pois drawLayer it's

    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {	
    	CGContextDrawImage(ctx, drawRect, img);
  6. Moderator


    Staff Member

    Are you 100% the zPositions are correct. The documentation doesn't make it clear (in the documentation I read) whether 1 is above 0 or not...
  7. macrumors member

    I've also tried it the other way around with all the pois having zpos 0 and the map having zpos 1 but the result is the same :/

    Further I've tried preventing the app from rendering the map.

    I've tried another approach when the pois are rendered in the same layer as the map, making drawing calls during the same drawlayer-call at which the map draws. And that works, but the pois has to be the same size, unaffected by the zoom, and that just didn't work out with that approach.
  8. Moderator


    Staff Member

    I am beginning to wonder if this is a side-effect of how CATiledLayer works. It seems that it requests the tiles in the background (asyncronously). I suspect what is happening is:

    1) your layers are asked to draw
    2) The CATiledLayer tries to draw and there are no tiles loaded yet so draws transparent and requests the tiles on a background thread/GCD queue
    3) You POI layers draw
    4) Some time later the tiles become available and the CATiledLayer renders them, but this renders them over the POI layer.

    If this is the case (not sure how you can test that) you need to get your POIs re-rendered after 4). Perhaps you can use a delegate method to force this?
  9. macrumors member

    Thanks for a very insightful theory!

    I added a setNeedsDisplay-call of every poi which is rendered in the tile that was drawn in each drawLayer-call of the map. So the map drawLayer method now looks like this:

    - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {	
    	CGContextTranslateCTM(ctx, 0, imgH);
    	CGContextScaleCTM(ctx, 1.0, -1.0);
    	CGContextDrawImage(ctx, drawRect, img);
    	CGFloat frX = [layer frame].origin.x; CGFloat frY = [layer frame].origin.y;
    	CGFloat frW = [layer frame].size.width; CGFloat frH = [layer frame].size.height;
    	for(int i=0;i<dbsize;i++){
    		CGFloat x = [poilayer[i] frame].origin.x; CGFloat y = [poilayer[i] frame].origin.y;
    		if(frX < x && x < frX+frW && frY < y && y < frY + frH)
    			[poilayer[i] setNeedsDisplay];
    And I've added some NSLog-calls so I can track and see that they actually render in a good order.
    But despite all this no poi shows up. Is it possible it has something to do with the coordination flipping - that is, the CGContextTranslateCTM(ctx, 0, imgH) and CGContextScaleCTM(ctx, 1.0, -1.0) calls?
  10. Moderator


    Staff Member

    Possibly. Perhaps you are (once the translate/scale take effect) are drawing the image outside the bounds of the layer/context they are within?
  11. macrumors member


    My thoughts exactly. I tried calling save state before the map translation, scaling and drawing and a restore call after. But still no result.
  12. Moderator


    Staff Member

    What happens if, instead of drawing the POI image, you just draw a coloured rectangle with CoreGraphics (removing the scale and translate)? Do you at least see that?
  13. macrumors member

    Really good idéa. I tried it, and nothing renders, so theres at least a positional problem or a drawing order problem.
  14. macrumors member

    Is it possible that the bounds property can cause problems? For the map its set to origin at (0,0) and the size is that of the map. The pois bounds are also originated at (0,0) and has a size of 21x21 (thats the size of a poi icon).
  15. Moderator


    Staff Member

    Are you setting the bounds or the frame? I think you may be needing to set the frame...
  16. macrumors member

    I checked the size of the frames of the pois, and they're 21x21. Also, I've seen that the drawRect (that is used in the pois drawLayer-method) has origin (0,0) and size 21x21.
  17. macrumors member

    I commented out the rendering part of the map and checked the log - the last thing it does is render a poi at (0,0) but still nothing shows up. The code that generates the ImageRefs have been used for the old approach that worked - so it can't be that. Is it correct to add several layers with the addSublayer method in the first place?
  18. Moderator


    Staff Member

    Yes, I think that's fine. I'm working on an app that uses a couple of sublayers that works fine, although both sublayers are the size of the screen. I cannot see why this would make any difference.
  19. macrumors member

    I found the problem, and it was something incredibly silly and rather embarrassing. The global image ref for the pois wasn't set to the one that was passed in the init-call. It was very "hidden" in the code and almost impossible to spot - but embarrassing never the less.

    Thank you very much, robbieduncan, for your help - kudos!
  20. Moderator


    Staff Member

    LOL! Well at least you got it fixed in the end. And probably learnt a load about CALayers that you didn't want to know :D
  21. macrumors member

    I sure did! :D
    Cheers, mate!

Share This Page