PDA

View Full Version : CALayer addSublayer question




Cbswe
Aug 17, 2010, 10:09 AM
Hi!

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
Carl



robbieduncan
Aug 17, 2010, 10:14 AM
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?

Cbswe
Aug 17, 2010, 10:22 AM
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?


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?

robbieduncan
Aug 17, 2010, 10:31 AM
shouldn't the pois have shown with the map transparency on?

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

Cbswe
Aug 17, 2010, 10:46 AM
Maybe. I've not looked too closely at how the layer system draws. What is going on in your drawLayer method?

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);
}

robbieduncan
Aug 17, 2010, 11:08 AM
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...

Cbswe
Aug 18, 2010, 03:33 AM
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...

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.

robbieduncan
Aug 18, 2010, 04:07 AM
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?

Cbswe
Aug 18, 2010, 04:46 AM
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?

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?

robbieduncan
Aug 18, 2010, 04:49 AM
that is, the CGContextTranslateCTM(ctx, 0, imgH) and CGContextScaleCTM(ctx, 1.0, -1.0) calls?

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

Cbswe
Aug 18, 2010, 04:54 AM
Possibly. Perhaps you are (once the translate/scale take effect) are drawing the image outside the bounds of the layer/context they are within?


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

robbieduncan
Aug 18, 2010, 05:11 AM
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?

Cbswe
Aug 18, 2010, 05:31 AM
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?

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

Cbswe
Aug 18, 2010, 07:31 AM
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).

robbieduncan
Aug 18, 2010, 07:40 AM
Are you setting the bounds or the frame? I think you may be needing to set the frame...

Cbswe
Aug 18, 2010, 08:00 AM
Are you setting the bounds or the frame? I think you may be needing to set the frame...

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.

Cbswe
Aug 18, 2010, 08:58 AM
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?

robbieduncan
Aug 18, 2010, 09:03 AM
Is it correct to add several layers with the addSublayer method in the first place?

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.

Cbswe
Aug 19, 2010, 06:53 AM
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!

robbieduncan
Aug 19, 2010, 06:59 AM
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!

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

Cbswe
Aug 19, 2010, 07:00 AM
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

I sure did! :D
Cheers, mate!