OSMDroid PathOverlay drawing is corrupted at high zoom levels

有些话、适合烂在心里 提交于 2020-01-14 04:40:10

问题


I'm using OSMdroid to implement a mapping application.

I have implemented a custom MapTileProvider that uses a tile source that allows zoom levels up to 22.

The default MAPNIK provider only allows zooms to level 18.

The problem is that any PathOverlay instances draw perfectly until zoom level 19, but then are not drawn properly at zoom level 20-22. it looks like someone's rubbed out the path with an eraser over 90% of the path length (see screenshots below).

I've stepped through the draw() method of PathOverlay and exerything seems to be calculating correctly (the intermediate points appear correct for ZoomLevel 22, and then the XY projections are dividing by 22-ZoomLevel to get current screen coordinates).

Can anyone provide some insight as to what the problem is, and how to resolve it?

The same thing happens if I invoke the MapView using Cloudmade small tiles, which allows zooms up until level 20 and is a 'built-in' osmDroid tile provider class.

    //mMapTileProvider = new HighResMapTileProvider(this);
    mMapTileProvider = new MapTileProviderBasic(this,TileSourceFactory.CLOUDMADESMALLTILES);
    mMapView = new MapView(this, 256, mResourceProxy,mMapTileProvider);

So the problem does not appear to be with the tile source or provider but with the canvas drawing method. Any ideas on how to resolve this?

At zoomLevel 19 I can see my paths nicely:

But here is that same path at the next zoom level:


回答1:


Update: This has been fixed in osmdroid 3.0.9.

Original Answer:
This issue appears to be rooted in Android. I believe it is due to a rounding error that happens when you scroll a view to a large offset (possibly due to use of SKScalar). This bug can be isolated by creating a new android project with an activity and a view:

  1. Begin with the view at the origin with no scroll offset yet.
  2. Draw a circle on the canvas: canvas.drawCircle(screenCenterX, screenCenterY, 100, mPaint)
  3. Scroll the view to a large number: mainView.scrollTo(536870912, 536870912)
  4. Draw a circle on the canvas: canvas.drawCircle(newScreenCenterX, newScreenCenterY, 100, mPaint)

The first circle draws ok, the second one draws distorted. For further evidence, try to draw your path near 0 lat/0 long and zoom in - notice the distortion no longer appears.

I will update the osmdroid ticket with some possible solutions workarounds.




回答2:


I've found a workaround. It's not ideal, but it does work.

Firstly, if I add a canvas.drawCircle(screenPoint1.x, screenPoint1.y, 5, cpaint);

to PathOverlay's draw() method I see this, so I know the co-ordinates are at least being calculated correctly.

So the problem seems to be related to the underlying line draw method in Android.

After some trial and error, I found that setting the STROKE WIDTH to 0.0 for the PathOverlay's Paint object fixes the problem, but the line is obviously only 1 pixel wide.

Adding a check for the current zoom level in PathOverlay.draw() to set the stroke width will keep the current behaviour for levels <20 and draw a hairline path for higher zoom levels.

Some other things I noticed:

  • The circles become squares at zoom level 21&22. This strongly suggests that there's some floating point precision issues when passing very large (x,y) co-ordinates to Path.lineTo / canvas.drawCircle etc, e.g. mPath.lineTo(131000001,38000001)
  • Setting stroke width to say, 5 sort-of works up to zoom level 21, but the same problem crops up at level 22 again



回答3:


I am fairly sure this is because the default PathOverlay only draws the line between points in the view. If a the point is outside of the curent view the line segment is not drawen. At lower zoom levels you just don't see that the bit of the line going off the view is not showen as all the sections are small.

I think you have 2 options.

The easy but maybe not the best is to put more points into the path, then at least the problem will be less noticable. If this is a good idea or not will depend how many points you already have.

The corect solution will be to extend the class and do your own draw method then clip the line segmet that gose off the view to the view edge. Idealy you would contribute your code back to the source.




回答4:


I have the same problem and I posted a bug on OSMDroid here:

http://code.google.com/p/osmdroid/issues/detail?can=2&start=0&num=100&q=221&colspec=ID%20Type%20Status%20Priority%20Milestone%20Owner%20Summary&groupby=&sort=&id=221

I'm not sure if it's a problem of OSMDroid or just a problem of too big canvas.

Other workaround would be drawing on a new, smaller canvas (size of current visible mapView) and using drawBitmap in the top left corner of a big canvas. Just remember not to create new bitmap each draw - because it's expensive.

All shapes are drawn perfectly fine but Im struggling with other problem with not smooth panning in levels > 18. You can see that when you pan the map it is not moving every pixel as it is in levels < 18, but it jumps over few pixels.




回答5:


I agree that this is OSMDROID related bug because I got the same working DrawPath function (Zoom level 21 & 22) using Google MapView. I hope they will be able to address this issue.




回答6:


To solve this problem, we need to implement the line clipping algorithm. By clipping with the map viewport, the path is adding more vertexes. Thus it will be drawed correctly at big zoom level.



来源:https://stackoverflow.com/questions/9273561/osmdroid-pathoverlay-drawing-is-corrupted-at-high-zoom-levels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!