views:

283

answers:

2

I need to draw a path along the shape of an image in a way that it is always matching its position on the image independent of the image scale. Think of this like the hybrid view of Google Maps where streets names and roads are superimposed on top of the aerial pictures.

Furthermore, this path will be drawn by the user's finger movements and I need to be able to retrieve the path keypoints on the image pixel coordinates. The user zooms-in in order to more precisely set the paths location.

I manage to somehow make it work using this approach:

-Create a custom UIView called CanvasView that handles touches interaction and delivers scaling, rotation, translation values to either the UIImageView or PathsView (see bellow) depending on a flag: deliverToImageOrPaths.

-Create a UIImageView holding the base image. This is set as a children of CanvasView

-Create a custom UIView called PathsView that keeps track of the 2D paths geometry and draws itself with a custom drawRect. This is set as children of the UIImageView.

So hierarchy: CanvasView -> UIImageView ->PathsView

In this way when deliverToImageOrPaths is YES, finger gestures transforms both the UIImageView and its child PathsView. When deliverToImageOrPaths is NO the gestures affect only the PathsView altering its geometry. So far so good.

QUESTION: The problem I have is that when scaling the base UIImageView (via its .transform property) the PathsView is scaled with aliasing artifacts. drawRect is still being called on the PathsView but I guess it's performing the drawing using the original buffer size and then interpolating.

How can I solve this issue? Are there better ways to implement these features?

PS: I tried changing the PathsView layer class to CATiledLayer with levelsOfDetailBias 4 and levelsOfDetail 4. It solves the aliasing problem to some extent but it's unacceptable slow to render.

A: 

If you're holding onto the path values as they are being drawn, you can capture the % scaling of the underlying image, then reposition the path values and redraw them in the PathsView's drawRect method.

It would involve a bit of math (mostly along the lines of map projections) but instead of scaling bitmaps and getting artifacts, you would be scaling point distances and redrawing using vectors, which would make it smooth at any resolution (especially if you're connecting dots with beziers instead of pixels or lines).

If you're laying paint along the paths as the user draws them and throwing away the point data, then the only solution is to do bitmap anti-aliasing which is essentially what CATiledLayer is doing for you and as you've discovered, can be slow.

Ramin
A: 

If you are targeting iPhone OS 3.0+ you could use a CAShapeLayer for your path. You assign a CGPathRef to the layer and it will handle all the drawing and scaling for you. You just set the layer's transform.

Ole Begemann