Redrawing CALayer subclass when super layer is scaled
-
I'm trying to use scaling of the superlayer to implement a zoom
feature in my CAD app. The various elements in the canvas are drawn by
a CALayer subclass I have, which overrides drawInContext:. After the
zoom finishes animating, I want CA to call all the sublayer's
drawInContext: methods as necessary to re-render the layer's contents.
Is there any way to do this, short of keeping track of all the layers
myself and calling setNeedsDisplay on them?
TIA,
--
Rick -
On Jul 8, 2008, at 10:53 PM, Rick Mann wrote:> I'm trying to use scaling of the superlayer to implement a zoom
> feature in my CAD app. The various elements in the canvas are drawn
> by a CALayer subclass I have, which overrides drawInContext:. After
> the zoom finishes animating, I want CA to call all the sublayer's
> drawInContext: methods as necessary to re-render the layer's
> contents. Is there any way to do this, short of keeping track of all
> the layers myself and calling setNeedsDisplay on them?
Your best solution for rendering multi-representational content in
Core Animation is to use a CATiledLayer. It will automatically be
called to update content as you zoom in and out (assuming you specify
that the level of content exists). The drawing model is exactly the
same as with a CALayer, although you can optimize the drawing a bit
with a bit more knowledge.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...> -
On Jul 9, 2008, at 09:56:36, David Duncan wrote:> Your best solution for rendering multi-representational content in
> Core Animation is to use a CATiledLayer. It will automatically be
> called to update content as you zoom in and out (assuming you
> specify that the level of content exists). The drawing model is
> exactly the same as with a CALayer, although you can optimize the
> drawing a bit with a bit more knowledge.
My CAD program has a number of "parts" laid out on the canvas at the
whim of the user. These parts are interconnected by the user with
lines comprised of a series of orthogonal line segments (it's
schematic capture CAD). There is one instance of my CALayer subclass
for each of these parts, and I'm thinking I'll use one for each
connected set of line segments (not sure yet).
Are you suggesting that each of these should subclass CATiledLayer
instead (or provide a delegate)? I was setting the transform on the
window's (root?) layer. Will that result in tile sublayers redrawing
their content?
I'll read the docs on CATiledLayer, and give this a shot. Thanks!
--
Rick -
On Jul 9, 2008, at 11:09 AM, Rick Mann wrote:> My CAD program has a number of "parts" laid out on the canvas at the
> whim of the user. These parts are interconnected by the user with
> lines comprised of a series of orthogonal line segments (it's
> schematic capture CAD). There is one instance of my CALayer subclass
> for each of these parts, and I'm thinking I'll use one for each
> connected set of line segments (not sure yet).
Given what it sounds like your content is, I might consider putting
the whole canvas on a single or small set of tiled layers (they can be
unbounded in size).> Are you suggesting that each of these should subclass CATiledLayer
> instead (or provide a delegate)? I was setting the transform on the
> window's (root?) layer. Will that result in tile sublayers redrawing
> their content?
A tiled layer will trigger redraws when it detects that higher (or
lower) resolution content is available. It caches this drawing as
well, so you won't get called to redraw just because of a resize of
content at that level is already available.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...> -
On Jul 9, 2008, at 12:59:33, David Duncan wrote:> Given what it sounds like your content is, I might consider putting
> the whole canvas on a single or small set of tiled layers (they can
> be unbounded in size).
Oh. I had thought making each individual part its own CALayer was most
appropriate. I intend for each part to change its appearance to
reflect selection, hover, etc, as well as be draggable, rotatable,
etc. Animating these these changes seems to dictate making each its
own layer.
Now, I'm not really sure how to animate something I'm drawing directly
(for example, when you're hovering over a part, I would like it's
"significant contour" to pulsate, or something like that).
--
Rick -
On Jul 9, 2008, at 2:08 PM, Rick Mann wrote:> On Jul 9, 2008, at 12:59:33, David Duncan wrote:
>
>> Given what it sounds like your content is, I might consider putting
>> the whole canvas on a single or small set of tiled layers (they can
>> be unbounded in size).
>
>
> Oh. I had thought making each individual part its own CALayer was
> most appropriate. I intend for each part to change its appearance to
> reflect selection, hover, etc, as well as be draggable, rotatable,
> etc. Animating these these changes seems to dictate making each its
> own layer.
>
> Now, I'm not really sure how to animate something I'm drawing
> directly (for example, when you're hovering over a part, I would
> like it's "significant contour" to pulsate, or something like that).
Either method should work, but you may want to consider resource usage
in both as well. Its certainly plausible to logically pull something
out of its parent layer (i.e. redraw it into another layer) when
selected, then when deselected burn it into the model so its drawn on
its parent layer again.
But its mostly an implementation detail. I would probably go with what
works first, then if you find a performance issue to consider a change
then. As always, premature optimization is to be avoided.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...> -
On Jul 9, 2008, at 12:59:33, David Duncan wrote:> A tiled layer will trigger redraws when it detects that higher (or
> lower) resolution content is available. It caches this drawing as
> well, so you won't get called to redraw just because of a resize of
> content at that level is already available.
So, this isn't really working they way I want it to.
I have a canvas, which is my window's root layer. In that I have an
arbitrary number of sublayers. If I set the scaling (via
"transform.scale") of the root layer to x2, everything is redrawn to
double the size (and it smoothly animates up to that scale).
However, at the time that my drawing code is called, the CGContextRef
that's handed to me is NOT scaled. So my drawing is done small, and
then only scaled afterward by some blit operation. The result is very
pixilated lines.
I've tried making my root layer a CATiledLayer, and I've tried making
my individual sublayers CATiledLayers (and setting levels of detail
for both). Nothing works.
I don't really want to have to set the scale on each sublayer; this
seems to defeat the purpose of the drawing transform.
The documentation says that any transform applied to a layer also
applies to its sublayers, but this is not what I'm seeing; at least,
not at draw time.
Any suggestions?
--
Rick -
On Jul 15, 2008, at 10:42 PM, Rick Mann wrote:> However, at the time that my drawing code is called, the
> CGContextRef that's handed to me is NOT scaled. So my drawing is
> done small, and then only scaled afterward by some blit operation.
> The result is very pixilated lines.
If you are dealing with CALayers, then the context covers the number
of pixels defined by layer.bounds.size. If you are dealing with a
CATiledLayer, then the context passed covers the number of pixels
defined by layer.tileSize. The primary difference between a CALayer
and a CATiledLayer is that the tiled layer has multiple
representations for the same content, whereas a CALayer has only one
representation (which is also why a CATiledLayer requires more
resources than a CALayer).
This is also why when you scale up a CALayer its content its content
looks interpolated - its the same number of pixels as before, just
interpolated larger. If you exceed the maximum LOD of a tiled layer,
you will see the same thing (which if you don't set a LOD bias means
if you scale a tiled layer above 1.0 it will also have its content
interpolated).> I've tried making my root layer a CATiledLayer, and I've tried
> making my individual sublayers CATiledLayers (and setting levels of
> detail for both). Nothing works.
I'm not certain why it would not, at least not with all your layers as
tiled layers. If just your root layer is a tiled layer, then it would
need to be transformed for its drawing code to be re-invoked, and it
would not effect any of the sublayers directly.> I don't really want to have to set the scale on each sublayer; this
> seems to defeat the purpose of the drawing transform.
This wouldn't have the effect you would want anyway (both transforms
would be concatenated, which would end up with an explosion of size
unless you flattened your layer hierarchy)> The documentation says that any transform applied to a layer also
> applies to its sublayers, but this is not what I'm seeing; at least,
> not at draw time.
Can't really say what you are or are not seeing here, I'd probably
have to see code. If this is critical, I'd recommend filing a DTS
incident.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...> -
On Jul 16, 2008, at 16:23:23, David Duncan wrote:> Can't really say what you are or are not seeing here, I'd probably
> have to see code. If this is critical, I'd recommend filing a DTS
> incident.
I'm happy to send you my code. It's not critical, in that I can find
other ways to do what I want (other than using Core Animation). This
is a side project, and I can't afford DTS incidents.
I'm just disappointed that it doesn't seem possible to make Core
Animation do what I want: redraw me at the destination resolution.
--
Rick -
On Jul 16, 2008, at 16:23:23, David Duncan wrote:> Can't really say what you are or are not seeing here, I'd probably
> have to see code. If this is critical, I'd recommend filing a DTS
> incident.
David, I checked my code again, and realized I was setting the bias to
1 (I thought I saw that in a sample). I don't really understand how
the numbers are interpreted, but when I set it higher (4, and then
10), my layers started getting redrawn.
However, I'm seeing some incorrect drawing behavior as I zoom in. I
made a movie demonstrating this:
http://roderickmann.org/stuff/XcodeScreenSnapz001.mov
Any idea what I'm seeing?
TIA,
--
Rick -
On Jul 16, 2008, at 16:23:23, David Duncan wrote:> This is also why when you scale up a CALayer its content its content
> looks interpolated - its the same number of pixels as before, just
> interpolated larger. If you exceed the maximum LOD of a tiled layer,
> you will see the same thing (which if you don't set a LOD bias means
> if you scale a tiled layer above 1.0 it will also have its content
> interpolated).
So why is it that when setting a CALayer's (not CATiledLayer)
background color, corner and border properties, those render
beautifully, no matter what the scale of the parent layer? Clearly, at
some point, Quartz is getting called to fill & stroke the layer's
frame with the appropriate CTM in place for it to appear as it does
(scaled & rotated). I wish I could get it to do the same for my
drawing code.
--
Rick -
On 21-Jul-08, at 1:20 AM, Rick Mann wrote:>
> On Jul 16, 2008, at 16:23:23, David Duncan wrote:
>
>> This is also why when you scale up a CALayer its content its
>> content looks interpolated - its the same number of pixels as
>> before, just interpolated larger. If you exceed the maximum LOD of
>> a tiled layer, you will see the same thing (which if you don't set
>> a LOD bias means if you scale a tiled layer above 1.0 it will also
>> have its content interpolated).
>
>
> So why is it that when setting a CALayer's (not CATiledLayer)
> background color, corner and border properties, those render
> beautifully, no matter what the scale of the parent layer? Clearly,
> at some point, Quartz is getting called to fill & stroke the layer's
> frame with the appropriate CTM in place for it to appear as it does
> (scaled & rotated). I wish I could get it to do the same for my
> drawing code.
all the visual properties that are 'animatable' are applied at render
time. -
On Jul 20, 2008, at 22:44:37, Scott Anguish wrote:> all the visual properties that are 'animatable' are applied at
> render time.
Thanks for that answer, Scott.
So, can I not make my own drawing code an animatable property? I
thought I could.
I was really hoping I would be able to do this:
1. Define arbitrary properties
2. Have CA interpolate to new values of those properties
3. Have CA call me to draw the contents, which I would do based on the
"current" (mid-animation) value of those properties.
3a. Have my drawing environment set up to draw at the destination
resolution.
I'm not even sure I see a way to do that by writing my own animators &
renderers (I can't figure out how to subclass CARenderer, anyway).
--
Rick -
On 21-Jul-08, at 1:52 AM, Rick Mann wrote:>
> On Jul 20, 2008, at 22:44:37, Scott Anguish wrote:
>
>> all the visual properties that are 'animatable' are applied at
>> render time.
>
>
> Thanks for that answer, Scott.
>
> So, can I not make my own drawing code an animatable property? I
> thought I could.
Nope. That is entirely private.
The reason I had mentioned the animatable properties is because those
visuals (including background color and the border) are not scaled the
same as your content, since they aren't cached.. -
On Jul 20, 2008, at 22:57:12, Scott Anguish wrote:> Nope. That is entirely private.
>
> The reason I had mentioned the animatable properties is because
> those visuals (including background color and the border) are not
> scaled the same as your content, since they aren't cached..
Okay, thanks for the info. I think it's clear that I cannot really use
CA for my drawing, which is a pity. It seems like it's "really close"
to giving me what I want, but in the end, doesn't.
I might still get what I need from CATiledLayer, if the drawing
glitches I posted about earlier can be resolved.
Thanks again.
--
Rick -
On Jul 20, 2008, at 4:04 PM, Rick Mann wrote:> David, I checked my code again, and realized I was setting the bias
> to 1 (I thought I saw that in a sample). I don't really understand
> how the numbers are interpreted, but when I set it higher (4, and
> then 10), my layers started getting redrawn.
Its all powers of 2. Levels of detail is how many of them you have,
starting at 1. So if you set levelsOfDetail to 3, then you have 1,
1/2, 1/4. If you set it to 7 you add 1/8, 1/16. This effectively means
you have smaller representations of your data.
levelsOfDetailBias biases levelsOfDetail so that you can scale up as
well as down. So if we go back to levelsOfDetail set to 3, but set
levelsOfDetailBias to 1, then you get instead 2, 1, 1/2. If you set it
to 2, then you get 4, 2, 1. Setting this value greater than
levelsOfDetail-1 is may work (haven't tried it) but doesn't really
give you anything.
Effectively together you get the powers of 2 from
2^(levelsOfDetailBias) to 2^(levelsOfDetailBias-levelsOfDetail+1) for
your representations.> I'm not even sure I see a way to do that by writing my own animators
> & renderers (I can't figure out how to subclass CARenderer, anyway).
You wouldn't want to subclass CARenderer anyway, I can't imagine
anything useful that you could get out of doing so.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...>


