I'm using osmdroid and maps downloaded from OSM up to level 16. I was wondering if there is any way I could make the osmdroid use the tile from that zoom level but draw it bigger.
The thing is that tiles on that level have enough detail for me, but are drawn to small. I've seen some other apps use the same tile levels but somehow managing to draw them bigger.
Thanks
The best solution I have found to this problem (which I had myself earlier today), is to change the scaling in the tile source (I'm using my own version of OpenStreetMap):
final float scale = getBaseContext().getResources().getDisplayMetrics().density;
final int newScale = (int) (256 * scale);
String[] OSMSource = new String[2];
OSMSource[0] = "http://a.tile.openstreetmap.org/";
OSMSource[1] = "http://b.tile.openstreetmap.org/";
XYTileSource MapSource = new XYTileSource(
"OSM",
null,
1,
18,
newScale,
".png",
OSMSource
);
map.setTileSource(MapSource);
Varying the scale in accordance with the screen density is a relatively good solution. During my testing some of the images became slightly blurry, but if you decrease the scaling for that contingency you get a very good outcome.
This is not my solution BTW, I found it among the OSMDROID issues on Github. Thanks goes to stefangab95.
You can't do this without modifying the source code of osmdroid. Right now, tiles are shown at their actual resolution except when the view is being animated between zoom levels. That is, the tiles are switched when the animation is done, and the scale is set to 1 again. I have tried some tricks to keep the scaling when the user tries zooming beyond the highest level of detail. It works visually, but all the functions that map from pixels to map coordinates, as well as some of the interaction when dragging the map, breaks. It would therefore require a more significant modification of the source. It is doable, but I think it's not really worth the trouble - unless you actually want to contribute the modification to the project, and do it in a less hackish way.
mMapview.setTilesScaledToDpi(true)
https://github.com/osmdroid/osmdroid/blob/master/osmdroid-android/src/main/java/org/osmdroid/views/MapView.java#L307
that's should do the trick
I'm using offline tiles and just did this to display them at 2x resolution. The important part is the 512 pixel size even though the tiles are 256.
myMapView.setTileSource (new XYTileSource ("Mapnik", ResourceProxy.string.offline_mode, 13, 17, 512, ".png", "http://127.0.0.1"));
Cloudmade have support for high-resolution tiles that look much better on the current phones on the market now. Have a look here:
http://developers.cloudmade.com/projects/tiles/documents
I would use the normal tiles for ldpi and mdpi devices, and use the high-res ones for hdpi and xhdpi devices
To solve your problem completely, there exist two approach.
The first one is that you'd generate or render map tiles by your own by mapnik-like software.
The second one is using vector-based real-time renderer on mobile phone like mapsforge.
The configure file or style file is the key in both of these approach.
You can use a different tile source, for instance M$ Bing. That also has bigger street names.
One workaround that stays within the current working model of OSMdroid is to use an image manipulation package like ImageMagick or Photoshop to create a new set of bitmap tiles at the higher zoom level.
What you need to do is take each current tile (256x256px), resize it, doubling both size and width, and then cutting the image into 4 new tiles. Save each tile according to the naming convention for the new zoom level. The tile map naming convetion is described here, as well as an easy way of getting the 4 new names from the original name
Related
I have built a custom TileProvider from a map image, but the original image does not cover the required map area for the resolution corresponding to the highest zoom level.
By default, the provider returns no tiles if I do not create images for the corresponding zoom levels. Is it possible to zoom on the existing tile rather? I could create zoomed tiles these which would be basically stretched and cut versions of the highest resolution I have, but this seems redundant and would take unnecessary disk space/processing.
Is there a way to stretch tiles when none is available for a high zoom level, rather than creating those tiles explicitly? I could always set the maxZoom property on the map, but I have different overlays with different resolutions. I could also add some smart processing in the provider to return a subsampled version of a tile at lower resolution on the fly, but I am hoping there is a built in way to do this.
You cannot stretch the tiles per zoom level (automatically) but you can instead wrap your URL Tile provider with one that allows you to customize the behaviour. For example I've done (some years ago) a custom tile provider whose cached the tiles in a specific folder of the phone (better and longer caching than gmaps one), but could also be possibile to check the zoom (z) and if it is higher than a specific value, you can retrieve the tile for a lower zoom and split by 4 (no zoom but cut and zoom.
The result will be very poor, and honestly I find better to create them on server side (are you using a WMS provider maybe?).
I'm working on creating a mobile app which overlays images on top of a google map.
I have a large number of image overlays ('GroundOverlay' objects in KML-speak). I'm running into several issues (mainly performance) when the map is scrolled or zoomed
Having tried several options, I think my next approach will be to combine all the image overlays into one image beforehand, and then simply display that image as a single overlay on the map. Problem is, I'm not sure where to start.
Does anyone have any experience in combining overlay images?
I think there are two problems that need to be solved
1) Calculate the larger 'bounding box' that will contain the final image. I have the bounding box for each overlay ('LatLngBox' in KML-speak), and I think the final box can be calculated by simply examining the values of each LatLngBox and generating the final box based on the min/max values. Anyone have any insight as to whether this will work?
2) Merge all the overlay images into a single final image. I have no idea where to start here such here. Generating the actual image isn't the problem, but rather where to place each overlay (ie pixel level) so that the resulting image is accurate.
Any tips/hints would be greatly appreciated.
Thanks
the static overlay images can be combined and drawn. but the moving(regularly updated) overlay images would be an issue if you still want to combine them and post as one. the best option i believe would be to combine the static overlay resources and keep them in one set and other moving images drawn separately.
Managed to figure this out on my own.
Answer to (1): The technique I outlined in my question works perfectly
Answer to (2): You can convert between lat/lng and x/y pixels of an image as described here: Convert Lat/Longs to X/Y Co-ordinates
I would like to show a zoomable and scrollable map-like SVG in my app. The only way to do this without writing your own library etc. is to use an existing library all of which seem to render the SVG to a Bitmap, which can be assigned to an ImageView, for example.
The underlying bitmap quickly gets very large which may result in an out-of-memory exception. How do I draw only part of a possibly large and/or zoomed SVG to a Bitmap? Scaling up a small bitmap looks bad and is not an option.
I am going to answer this question myself because i have been looking for an answer for a while, found it scattered all over the web (but not here) and think that it may be helpful for others.
Can you not use Google's svg-android library? You can scale the Canvas to the correct size before rendering.
Would this be like how Google maps works? They appear to tile and increase/decrease detail as you zoom in and out.
I have done something similar in the past, not sure if it is how Google did it but my scheme worked exceptionally well for me. What I did was break my map into rectangular regions, I would then calculate which regions had any portion that was visible and pull in data only from those regions. Each rectangular region was sub-divided to provide more detail if the user zoomed in. I kept subdividing down to the level I wanted, I stopped at three, because I used a 10 X 10 grid so each level was effectively a magnification of 10 - at level three I was viewing 100 times the detail I was viewing at level one which was sufficient for my needs.
I was even able to animate this so that when you zoomed in you appeared to smoothly "fly" closer to the terrain.
First of all, I am using libsvg-android which requires the NDK but which seems to be very fast, especially if you have to redraw your SVG frequently. Actually, I am using this modified version of the library which enables you to query the width and height of the SVG as specified in the SVG document.
My first approach was this:
long svgID = SvgRaster.svgAndroidCreate();
SvgRaster.svgAndroidParseBuffer(svgID, svgString);
SvgRaster.svgAndroidSetAntialiasing(svgID, true);
Bitmap bitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.RGB_565);
SvgRaster.svgAndroidRenderToAreaUniform(svgID, new Canvas(bitmap), -300, -200, 1500, 1500);
First, the SVG source is parsed. Then, a Bitmap is created that will be assigned to an ImageView later on. Next, the SVG is rendered (zoomed to 1500x1500 pixels in size) to the bitmap. Note the translation (-300, -200) applied because the user has scrolled the image view.
This does not work. It seems that negative offsets are not supported.
Instead, the canvas has to be translated like this:
Canvas canvas = new Canvas(bitmap);
canvas.translate(-300, -200);
SvgRaster.svgAndroidRenderToAreaUniform(svgID, canvas, 0, 0, 1500, 1500);
This works as expected. The translation of the SVG is applied to the canvas; the scale is applied by adjusting the size of the rendered SVG. In this way, you can have a large SVG document and render the proportion you are interested in to a much smaller bitmap.
I've written an ImageView subclass which is scrollable in both the x and the y directions and zoomable. Its image resource is a low resolution raster image of the SVG. When the user scrolls or zooms the image, this version of the SVG is shown. When the user stops interacting with the image, I render the currently visible part of the SVG to a Bitmap the size of my image view and draw this instead of the low resolution image.
I'm writing an Android and iOS engine in C++ and currently focusing on Android with the NDK.
I'd like to render to a viewport of a smaller size (say 600x360) and automatically upscale this to the native rez (say 800x480.) Currently the smaller viewport displays in a lower corner of my screen with black regions.
My problem is I don't know of a simple way to do this transparently using the NDK. There is a GLSurfaceview.setScaleX (and Y) function in API level 11, which would be perfect, but doesn't exist in API level 9, which I am targeting. Another bad solution is to render to a FBO and blit that to the screen as a final step.
I am considering simply story a scaling matrix and asking the user of the engine (for now just me) to always multiply vertices by this when drawing to the screen. This would be similar to using glPushMatrix.
I searched for a while and couldn't find a good solution. Does anyone know how to help?
What you can do is get the SurfaceHolder from GLSurfaceView, GLSurfaceView.getHolder() and then set the resolution you desire by calling SurfaceHolder.setFixedSize(width, height).
In my case the GLSurfaceView has a FrameLayout root which fills the screen, I am not sure if thats required - I have it because I add other elements on top - but if you set the size and it doesnt fill the screen then you know what's missing!
Using a FrameBuffer is also a valid way and you could draw some cool effects with it as well, the way above is just faster when the only thing you want to do is scale the rendering down (or possibly up? I haven't tried).
I've got an image that is 800 by 300, which I know is the width of my test platform's resolution (HTC Desire at 800x480). When I try to draw this image to the screen it scales oddly. It spills over the left hand side of the screen and fills almost all the vertical.
I'm using code like this:
canvas.drawBitmap( screen[1], new Rect(0,0,800,300), new Rect(0,0,800,300), null);
For some reason
width_x = canvas.getWidth();
width_y = canvas.getHeight();
reports my resolution as 533 by 320. Now I assume this is for the expletive-deleted fascinating scaling system Android uses so apps appear the same size on all phones but I want to ignore this. I'm writing a game, so want to handle scaling and positioning myself - for instance using more screen estate if it becomes available. Best Android practice may be suitable for an icon based application, but I would like to draw to absolute pixel positions, and get absolute resolution information for the screen.
Therefore my question is this - is this absolutely impossible? If it is completely contraindicated because Android has a simple and effective system in place to do this then I would be interested to know what it is. Dpi is not relevant to my game design (just like if this was a pc game, it would be irrelevant)
Perhaps my screen actually 533 by 320 unless I specify a resolution somehow? I tried using the scaling values from width and height and the image was the correct size on screen, roughly, but had jagged edges because some sort of scaling had occurred. I therefore did not have access to all the pixels my screen is capable of displaying.
To scale it I used something like
canvas.drawBitmap( screen[1], new Rect(0,0,800,300), new Rect((int)(0.0f),(int)(0.0f),(int)(533.0f),(int)(187.5f)), null); // numbers
Just whacked in for testing - ratio equivalent to reported screen resolution. Looks horrid.
Android is not doing anything to mess with your perceived resolution - you are working with 800x480 pixels on that Desire.
Are you working in a fullscreen, custom View and overriding onDraw? Are you working with a SurfaceView? We need to know these things before we can help you with your problem.
Assuming you are doing the above, you should be able to draw your bitmap to the screen without any scaling using Canvas.drawBitmap(Bitmap bitmap, float left, float top, Paint paint). In your case, that would look something like canvas.drawBitmap( screen[1], 0.0f, 0.0f, null); to put it in the upper left corner of your canvas.
In performance-sensitive apps (like games), you don't want to use the source/destination Rect version of drawBitmap() during your draw loop, since it will do the scaling during every iteration of the loop. Instead, draw a scaled/cropped version of your original bitmap to another member bitmap, and draw that one in the loop, using the x/y offset version of drawBitmap linked above.
If you want to know the amount of screen real estate you're working with (and you definitely should, if you're doing any custom drawing), you'll want to override either onSizeChanged() or surfaceChanged(), depending on implementation.
You should really check out the API demos, there are some great examples of how to do exactly what you're trying to do in there.
Good luck!
I fixed one of my problems - in the manifest file the OS I was targeting was set up incorrectly - switching it to 4 (i.e. 1.6) seemed to fix the values I was getting for height and width, at least for the HTC. Emulator is more problematic, but at least its a major step in the right direction. For your info, I'm working in full screen, landscape mode (fixed), with overridden functions for pretty much everything. (Including onDraw, surfaceChanged, and so forth)
If I can get the absolute width and height I can write my own code for loading the correct assets and using the correct scaling for screen positioning - DPI isn't an issue so hopefully that won't stray too far from suggested guidelines.