views:

54

answers:

2

I have a strange problem that I don't really know how to attack so I'm wondering if someone has had a similar problem before.

I override the draw(Canvas canvas, MapView mapView, boolean shadow) method in an ItemizedOverlay subclass to draw some paths, text etc. between the items. The first thing I do in the override is call super.draw with all these parameters. When I start the app, the lines that I draw in my override are where they are supposed to be, but the actual OverlayItems that the super.draw draws are way off. The interesting thing is that as I move the map towards the upper left corner (coords 0,0) the OverlayItems get nearer and nearer to the place where I expect them to be (in fact, they appear to match perfectly when I get the first item to point (0,0)). As I move the map so that the OverlayItems get further from the (0,0) point, they linearly get further from their geolocation.

In case nobody has faced this problem before and it isn't something obvious, I'll try to make a minimal example that still has this behavior and post it here. The actual code is relatively large so I'd like to avoid that much work if someone has any idea what might be the problem.

edit: an additional piece of information that might be helpful... my draw method looks like this:

public void draw(Canvas canvas, MapView mapView, boolean shadow) {
    super.draw(canvas, mapView, shadow);
    if (!shadow) {
        // code for drawing the lines etc.
        // on the canvas (uses mapView.getProjection()) 
    }
}

The custom part of the overlay doesn't have a shadow layer (I've used the same logic when extending Overlay without trouble). The shadow layer that gets drawn for the OverlayItems by super.draw is actually halfway between the Drawable and the expected geolocation for each particular item.

Here are tree screenshots from the avd to better illustrate what is happening. The four red pins should be on the red line above them and actually move towards the line as I slide the map towards the top left. The two pins and the line between them is drawn in my custom override, super.draw draws the four shadows and the four extra red pins.

Since this is my first post and I can't post more than one link, I put all three screenshots on the same jpg.
screenshot

A: 

It's hard to diagnose without looking at the code. I would check a few things, though:

  1. Are you using the MapView's projection? Are making sure to you retrieve a new one each time draw() is called?

  2. Did you make sure to a bound method for your Drawables? e.g., boundCenter() or boundCenterBottom()

Daniel Lew
1. yes, I call mapView.getProjection() as one of the first things in the draw method and use the returned object for the duration of that draw method - however, I don't even think that not using the accurate projection for my draw override would cause this problem since the result of the super.draw call is what is giving me unexpected results.2. yes, I'm using the same default drawable for all OverlayItems and I'm setting it in the constructor via super(boundCenterBottom(defaultMarker))
Ivan Budiselic
A: 

I have solved this problem and I guess the insight I got might be useful to others, so I'll explain what happened here. I'm not sure if it is appropriate to answer my own question - if not, please instruct me where I should put this text and I will edit/delete accordingly.

The problem was in my misunderstanding of the fundamental way Drawables get drawn. This misunderstanding came about from reading the JavaDoc for Drawable.draw which says:

Draw in its bounds (set via setBounds) respecting optional effects such as alpha (set via setAlpha) and color filter (set via setColorFilter).

Since I originally had an Overlay subclass drawing the path you can see on the screenshot and decided to use ItemizedOverlay for the markers along that path (so that they are easily tappable etc.) I set out to slightly alter my class. At a certain point, to see if things were working the way I had expected, I added some items and used the same Drawable as for one of the path endpoints. Guided by the JavaDoc for the draw method, I used something like this for drawing the path endpoints

private void drawMarker(Canvas canvas, Projection projection,
    GeoPoint location, Drawable drawable) {
    Point point = projection.toPixels(location, null);
    drawable.setBounds(
        point.x,
        point.y - drawable.getIntrinsicHeight(),
        point.x + drawable.getIntrinsicWidth(),
        point.y);
    drawable.draw(canvas);
}  

However, when I traced through the super.draw call, I noticed that it ended up calling Drawable.draw but the drawable always had the same bounds - the ones I set with the previous call to this drawMarker method. I still don't really understand how Drawable.draw knows where to actually put the Drawable, but sure enough, at that point the behavior I described in the question was pretty obvious. In hindsight, I probably should have realized that boundCenter and boundCenterBottom actually define the bounds on a Drawable (which is what their JavaDoc says), but instead I guess I thought it just changed the way that the bounds are determined "eventually", when the actual point you want to draw at is known.

In any case, I added a bit of extra functionality to use the drawables I actually wanted to use for the OverlayItems and sure enough, it works perfectly. I'm still wondering if what I'm doing in drawMarker is the way it is supposed to be done, but I don't know of any other way to tell the canvas where to put the Drawable.

Ivan Budiselic