I have an Android application that loads tiles from a URL. Following a code sample from Google, I have the following function:
#Override
public void onMapReady(GoogleMap googleMap) {
mapView = googleMap;
mapView.setMapType(GoogleMap.MAP_TYPE_NORMAL);
LatLng baseLocation = new LatLng(37.745446, -122.459264);
mapView.addMarker(new MarkerOptions().position(baseLocation).title("Marker"));
mapView.moveCamera(CameraUpdateFactory.newLatLng(baseLocation));
mapView.moveCamera(CameraUpdateFactory.zoomTo(5));
TileProvider tileProvider = new UrlTileProvider(256, 256) {
#Override
public synchronized URL getTileUrl(int x, int y, int z) {
String formattedUrl = String.format(Locale.US, TILE_SERVER_URL, x, y, z);
URL url = null;
try {
url = new URL(formattedUrl);
Log.d("TILE_URL", url.toString());
}
catch (MalformedURLException ex) {
throw new AssertionError(ex);
}
return url;
}
};
tiles = mapView.addTileOverlay(new TileOverlayOptions().zIndex(0.0f).tileProvider(tileProvider).visible(true));
}
This has already been implemented in our iOS version and works as expected. Furthermore, I have verified that the URLs returned to the console in this function definitely result in a tile image being returned.
I'm primarily an iOS person and need some insight here. No tiles show up on the map. I've played around with zIndex of the tile overlay with no effect.
Can anyone offer some advice here? Thanks!
I am assuming you followed Google's TileOverlayDemoActivity example: if this is the case, you have to update the URL format protocol from http to https, as follows:
private static final String MOON_MAP_URL_FORMAT =
"https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw/%d/%d/%d.jpg";
It took me ages to figure it out, I hope this helps.
Related
I want to use the world map in Unity and have been looking at the API of various map services. I need to show a screenshot (a static map with markers) on the screen, and move to the full map view to navigate it after clicking on it.
MapBox managed to display the map with the selected coordinates and add test markers, but that's all I can do with a query like this: https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/url-https%3A%2F%2Fwww.mapbox.com%2Fimg%2Frocket.png(-76.9,38.9)/-76.9,38.9,15/1000x1000?access_token=pk.eyJ1IjoiZGVuZGVhZCIsImEiOiJja2F1dha4egixnnfhmnvtc2u0y3bua2ntin0.GGOyhgN_fEqtPpPc5n6OLg because this request returns a jpg image.
They also have a plugin for Unity, but it's only used in 3d projects and does not allow me to configure the display in 2d.
In MapBox, the mapping I need is implemented using JavaScript for Web and Java for Android. On Android I can do what I need. I can connect to the API on Android, but will I be able to use it in Unity later?
It's the same with Google maps.
Actually, the question is, did someone work with map services in Unity? And how can this be implemented correctly?
I don't know if this is still relevant, but I used Mapbox in Unity (the Mapbox plugin) to create a AR Soundscape by "registering" GameObjects to coordinates and moving them in real-time when the map is moved.
Your problem sounds an awful lot like the one I solved with that.
Basically you provide the Lat/Lon values for your objects and convert them to Unity world space coordinates using the AbstractMap.GeoToWorldPosition() function.
I used a raycast to actually pull that off in-engine, which is quite convenient.
//Edit:
Unity is quite capable of handling 2D projects. You just have to configure it properly and build your project around it.
The following is the class that I use to handle all positioning-related calculations. Maybe it's of some help to you.
namespace TehMightyPotato.Positioning
{
[Serializable]
public class GeoPosition
{
[Tooltip(
"Update frequency of position polling. Update every n-th frame. 1 is every frame, 60 is every 60th frame.")]
[Range(1, 60)]
public int positionUpdateFrequency = 1;
[Tooltip("Should the object have a specified altitude?")]
public bool useYOffset = false;
[Tooltip("If useMeterConversion is activated the yOffsets unit is meters, otherwise its unity units.")]
public bool useMeterConversion = false;
[Tooltip("The actual y position of the object in m or unity units depending on useMeterConversion.")]
public float yOffset = 0;
[Tooltip("X is LAT, Y is LON")]public Vector2d geoVector;
[HideInInspector] public float worldRelativeScale;
// Apply the result of this function to your gameobjects transform.position on every frame to keep them on this position.
public Vector3 GetUnityWorldSpaceCoordinates(AbstractMap map)
{
UpdateWorldRelativeScale(map);
var worldSpaceCoordinates = map.GeoToWorldPosition(geoVector, false);
if (useYOffset)
{
worldSpaceCoordinates.y = yOffset;
}
return worldSpaceCoordinates;
}
public void UpdateWorldRelativeScale(AbstractMap map)
{
worldRelativeScale = map.WorldRelativeScale;
}
public void SetGeoVectorFromRaycast(Vector3 position, AbstractMap map, LayerMask layerMask)
{
var ray = new Ray(position, Vector3.down);
if (Physics.Raycast(ray, out var hitInfo, Mathf.Infinity, layerMask))
{
geoVector = map.WorldToGeoPosition(hitInfo.point);
}
else
{
throw new NullReferenceException("Raycast did not hit the map. Did you turn on map preview?");
}
}
public void SetYOffsetFromRaycast(AbstractMap map, Vector3 position, LayerMask layerMask)
{
UpdateWorldRelativeScale(map);
// using raycast because of possible y-non-zero maps/ terrain etc.
var ray = new Ray(position, Vector3.down);
if (Physics.Raycast(ray, out var hitInfo, Mathf.Infinity, layerMask))
{
var worldSpaceDistance = Vector3.Distance(position, hitInfo.point);
if (useMeterConversion)
{
yOffset = worldSpaceDistance * worldRelativeScale;
}
else
{
yOffset = worldSpaceDistance;
}
}
else
{
throw new NullReferenceException("Could not find map below. Is map preview turned on?");
}
}
}
}
I have a WMS tile source overlay on my Osmdroid map.
On the overridden getTileURLString function I add time dimension to get a tile from a specific time.
#Override
public String getTileURLString(long pMapTileIndex) {
//https://stackoverflow.com/questions/28436050/how-to-work-osmdroid-with-web-map-service-wms-used-by-the-private-provider
String baseUrl = getBaseUrl();
StringBuilder sb = new StringBuilder(baseUrl);
if (!baseUrl.endsWith("&"))
sb.append("&");
sb.append("request=GetMap&width=").append(getTileSizePixels()).append("&height=").append(getTileSizePixels()).append("&version=").append("1.3.0");
sb.append("&layers=").append("radar-swiss:radarswiss");
sb.append("&bbox=");
MapView.WebMercatorBoundingBox bb = new MapView.WebMercatorBoundingBox(MapTileIndex.getX(pMapTileIndex), MapTileIndex.getY(pMapTileIndex), MapTileIndex.getZoom(pMapTileIndex));
sb.append(bb.getWest()).append(",");
sb.append(bb.getSouth()).append(",");
sb.append(bb.getEast()).append(",");
sb.append(bb.getNorth());
sb.append("&srs=").append("EPSG:3857");
sb.append("&format=image/png&transparent=true");
sb.append("&tiled=true");
if (currentFrameTiming != null) {
String mDateTime = getDateTimeFromTimeStamp(currentFrameTiming.getTimeInMillis(), WMSTimeFormat);
sb.append("&time=").append(mDateTime);
}
L.d("rewritten url: " + sb.toString());
return sb.toString();
}
Everything works fine but even time parameter seems to be ignored when osmdroid caches tiles. Even if time parameter is modified, the tile is not downloaded, but taken from the local cache.
How can I fix this?
I am trying to load OpenStreetMaps on an android app but the map does not load correctly. They are displayed unordered.
I am using a self-hosted map server which loads correctly in a browser (Used leaflet for the demo).
The code as follows,
public class MapActivity extends AppCompatActivity {
final private int MIN_ZOOM_LEVEL = 3;
final private int MAX_ZOOM_LEVEL = 18;
final private int TILE_SIZE = 256;
final private String IMAGE_EXTENSION = ".png";
MapView map = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//load/initialize the osmdroid configuration
Context ctx = getApplicationContext();
Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
setContentView(R.layout.activity_map);
map = (MapView) findViewById(R.id.map);
map.setTilesScaledToDpi(true);
map.setMultiTouchControls(true);
map.setTileSource(new OnlineTileSourceBase("Tiles", 2, 18, 256, ".png",
new String[] { "http://maps.MY-DOMAIN.com/tile/" }) {
#Override
public String getTileURLString(long pMapTileIndex) {
String url = getBaseUrl()
+ MapTileIndex.getZoom(pMapTileIndex)
+ "/" + MapTileIndex.getX(pMapTileIndex)
+ "/" + MapTileIndex.getY(pMapTileIndex)
+ mImageFilenameEnding;
Log.e("MAP",url);
return url;
}
});
}
}
What I end up getting is,
How can I solve this issue? I have taken a look into the documentation but nothing is mentioned about this.
Either the tile source is z/x/y vs z/y/x OR the y coordinate is inverted the tile source is closer to the TMS specification vs the slippy map format that open street maps uses. In either case, correct the issue, clear the tile cache, then try it again
I am integrating giphy to my android app..
How can i play animated gif image from URL in android? Should I use ImageView, WebView, VideoView etc? For example if i want to play animation from this URL.
Just create a html string and load that into android webview. Tested solution.
http://developer.android.com/reference/android/webkit/WebView.html#loadData(java.lang.String, java.lang.String, java.lang.String)
String x = "<!DOCTYPE html><html><body><img src=\"http://goo.gl/uPJ9P2\" alt=\"Smileyface\" width=\"100%\" height=\"100%\"></body></html>";
webView.loadData(x, "text/html", "utf-8");
Try this way
Movie movie;
GifView(Context context) {
super(context);
movie = Movie.decodeStream(
context.getResources().openRawResource(
R.drawable.some_gif));
}
#Override
protected void onDraw(Canvas canvas) {
if (movie != null) {
movie.setTime(
(int) SystemClock.uptimeMillis() % movie.duration());
movie.draw(canvas, 0, 0);
invalidate();
}
}
I'd recommend using a third-party library like Glide that can support GIFs.
I made a quick example app for displaying a GIF from Giphy's API here.
Hope that helps
The general sketch of the solution is to use employ custom View which draws asks a Movie to draw itself to the Canvas periodically.
The first step is building the Movie instance. There is factory called decodeStream that can make a movie given an InputStream but it isn't enough to use the stream from a UrlConnection. If you try this you will get an IOException when the movie loader tries to call reset on the stream. The hack, unfortunate as it is, is to use a separated BufferedInputStream with a manually-set mark to tell it to save enough data that reset won't fail. Luckily, the URLConnection can tell us how much data to expect. I say this hack is unfortunate because it effectively requires the entire image to be buffered in memory (which is no problem for desktop apps, but it is a serious issue on a memory-constrained mobile device).
Here is a snip of the Movie setup code:
URL url = new URL(gifSource);
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bis.mark(conn.getContentLength());
Movie movie = Movie.decodeStream(bis);
bis.close();
Next, you need to create a view that will display this Movie. A subclass of View with a custom onDraw will do the trick (assuming it has access to the Movie you created with the previous code).
#Override protected void onDraw(Canvas canvas) {
if(movie != null) {
long now = android.os.SystemClock.uptimeMillis();
int dur = Math.max(movie.duration(), 1); // is it really animated?
int pos = (int)(now % dur);
movie.setTime(pos);
movie.draw(canvas, x, y);
}
}
The view won't trigger itself to be redrawn without help, and blindly calling invalidate() at the end of onDraw is just an energy waste. In another thread (probably the one you used to download the image data), you can post messages to the main thread, asking for the view to be invalidated at a steady (but not insane) pace.
Handler handler = new Handler();
new Thread() {
#Override public void run() {
// ... setup the movie (using the code from above)
// ... create and display the custom view, passing the movie
while(!Thread.currentThread().isInterrupted()) {
handler.post(new Runnable() {
public void run(){
view.invalidate();
}
});
try {
Thread.sleep(50); // yields 20 fps
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}.start();
hope it will help you to understand
This question already has answers here:
Get driving directions using Google Maps API v2
(4 answers)
Closed 3 years ago.
I was looking for an answer using Google and here, and the only relevant posts I have found are:
Google Maps Android V2 and Direction API
Get driving directions using Google Maps API v2
but there is no answer there. So I have already mentioned it but I will say that again. I am looking for a solution for the Google Map API v2 using FragmentActivity and a SupportMagFragment and LatLng objects and not using MapView ,MapActivity and GeoPoint.
In addition I don't have the Overlay object to use so I can't paint the direction on the map, is there an alternative for that?
So is there a way to do that?
Try this solution here. You can get driving or walking direction on V2.
The Overlay is indeed something to forget.
Polylines can easily be drawn
https://developers.google.com/maps/documentation/android/lines#add_a_polyline
Just loop through yourr points after you parsed tjhe JSON response:
PolylineOptions rectOptions = new PolylineOptions()
.add(new LatLng(37.35, -122.0))
.add(new LatLng(37.45, -122.0)) // North of the previous point, but at the same longitude
.add(new LatLng(37.45, -122.2)) // Same latitude, and 30km to the west
.add(new LatLng(37.35, -122.2)) // Same longitude, and 16km to the south
.add(new LatLng(37.35, -122.0)); // Closes the polyline.
// Set the rectangle's color to red
rectOptions.color(Color.RED);
// Get back the mutable Polyline
Polyline polyline = myMap.addPolyline(rectOptions);
Your question title is much more general than your requirements, so I will answer this in a way that I think will benefit those viewing this question and hopefully meet your requirements in perhaps a different way.
If you are not showing directions in the context of a map already being a loaded fragment and something having been done to show directions over the map (which is probably similar to what the OP is doing), it's easier and I believe standard to do this with an Intent.
This launches a map pathing activity (through a separate application - where the app launched depends on the user's compatible apps, which by default is Google Maps) that plots directions from the origin address (String originAddress) to the
destination address (String destinationAddress) via roadways:
// Build the URI query string.
String uriPath = "https://www.google.com/maps/dir/";
// Format parameters according to documentation at:
// https://developers.google.com/maps/documentation/directions/intro
String uriParams =
"?api=1" +
"&origin=" + originAddress.replace(" ", "+")
.replace(",", "") +
"&destination=" + destinationAddress.replace(" ", "+")
.replace(",", "") +
"&travelmode=driving";
Uri queryURI = Uri.parse(uriPath + uriParams);
// Open the map.
Intent intent = new Intent(Intent.ACTION_VIEW, queryURI);
startActivity(activity, intent, null);
(Where activity is simply the currently active Activity - obtained through whatever means are appropriate in the current programming context).
The following code gets an address String from a LatLng object (which must then be processed for the URI query String as above):
/**
* Retrieves an address `String` from a `LatLng` object.
*/
private void getAddressFromLocation(
final StringBuilder address, final LatLng latlng) {
// Create the URI query String.
String uriPath =
"https://maps.googleapis.com/maps/api/geocode/json";
String uriParams =
"?latlng=" + String.format("%f,%f",
latlng.latitude, latlng.longitude) +
"&key=" + GOOGLE_MAPS_WEB_API_KEY;
String uriString = uriPath + uriParams;
// Issue the query using the Volley library for networking.
RequestFuture<JSONObject> future = RequestFuture.newFuture();
JSONObject response = null;
// Required for JsonObjectRequest, but not important here.
Map<String, String> jsonParams = new HashMap<String, String>();
JsonObjectRequest request =
new JsonObjectRequest(Request.Method.POST,
uriString,
new JSONObject(jsonParams),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
if (response != null) {
String resultString =
response.getJSONArray("results")
.getJSONObject(0)
.getString("formatted_address");
// Assumes `address` was empty.
address.append(resultString);
} // end of if
// No response was received.
} catch (JSONException e) {
// Most likely, an assumption about the JSON
// structure was invalid.
e.printStackTrace();
}
} // end of `onResponse()`
}, // end of `new Response.Listener<JSONObject>()`
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(LOG_TAG, "Error occurred ", error);
}
});
// Add the request to the request queue.
// `VolleyRequestQueue` is a singleton containing
// an instance of a Volley `RequestQueue`.
VolleyRequestQueue.getInstance(activity)
.addToRequestQueue(request);
}
This request is asynchronous, but it can be made synchronous.
You will need to call toString() on the actual parameter passed to address to obtain originAddress.
Q:I was looking for an answer using Google and here, and the only
relevant posts i have found are: Google Maps Android V2 and Direction
API Google map API v2 - get driving directions
Answer: Your saying, "but there is no answer there." is not absolutely right. In this site, you can find just only a few clues about that. I think you will not get the perfect code and concrete implement KNOW-HOWs here. In fact, many developers want to make the app to display the routing or directions on Google Maps. But I think there is no solution to get directions just only with the pure Google Maps API v2.
Q: So I have already mentioned it but I will say that again. I am
looking for a solution for the Google Map API v2 using
FragmentActivity and a SupportMagFragment and LatLng objects and not
using MapView ,MapActivtiy and GeoPoint.
Answer: Here are a few good sample tutorials (click here). You can find what you want.
Q: In addition i don't have the Overlay object to use so i can't paint
the direction on the map, is there an alternative for that? So is
there a way to do that?
Answer: In the Google Maps API v2, the annoying Overlay and so on are not any more required. For this, you can find the answer in my linked site above.