Here is my code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapView);
mapView.setComponents(new Components());
RasterDataSource datasource = new PackagedRasterDataSource(new EPSG3857(), 11, 12, "t{zoom}_{x}_{y}", getApplicationContext());
RasterLayer mapLayer = new RasterLayer(datasource, 16);
mapView.getLayers().setBaseLayer(mapLayer);
mapView.setFocusPoint(mapView.getLayers().getBaseLayer().getProjection().fromWgs84(217884.21f, 1928068.13f));
//mapView.setZoom(15);
}
I have added .map file from http://www.mapcacher.com/ and converted it to PNG using http://dev.nutiteq.ee/jarmaps/ . I have mentioned the correct zoom level, checked that t11 and t12 files exist under res/raw. Also I have converted lat/lon to the required format using http://www.latlong.net/lat-long-utm.html . What is it that I am doing wrong.I don't get any errors in log cat but a blank page with Nutiteq logo is diplayed.
This line is wrong, instead of UTM coordinates
mapView.setFocusPoint(mapView.getLayers().getBaseLayer().getProjection().fromWgs84(217884.21f, 1928068.13f));
you should use WGS84, lat-long coordinates (first parameter long as x, then lat as y), like method name fromWgs84 suggests. No need to convert from/to UTM externally.
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'm trying out the Google API V2 Heatmap (Android) which was introduced this february and it's not working entirely. I'm not sure if it's the same problem as Google Maps API v2 HeatMap Won't Reliably Display (and I can't contact him by comments because I don't have enough rep.. :c ).
Using locations from file
Anyway, what I was trying to do was an App with just a GoogleMap and the same locations as in their guide (https://developers.google.com/maps/documentation/android/utility/heatmap) and when I launch it, I can only see 3/5 locations.
I tried adding more points and still, it's consistently not showing them all, but I can't see a pattern or something. The code is the same as in their guide.
private void addHeatMap() {
List<LatLng> list = null;
// Get the data: latitude/longitude positions of police stations.
try {
list = readItems(R.raw.police_stations);
} catch (JSONException e) {
Toast.makeText(this, "Problem reading list of locations.", Toast.LENGTH_LONG).show();
}
// Create a heat map tile provider, passing it the latlngs of the police stations.
mProvider = new HeatmapTileProvider.Builder()
.data(list)
.build();
// Add a tile overlay to the map, using the heat map tile provider.
mOverlay = mMap.addTileOverlay(new TileOverlayOptions().tileProvider(mProvider));
}
private ArrayList<LatLng> readItems(int resource) throws JSONException {
ArrayList<LatLng> list = new ArrayList<LatLng>();
InputStream inputStream = getResources().openRawResource(resource);
String json = new Scanner(inputStream).useDelimiter("\\A").next();
JSONArray array = new JSONArray(json);
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
double lat = object.getDouble("lat");
double lng = object.getDouble("lng");
LatLng latLng = new LatLng(lat, lng);
list.add(latLng);
}
return list;
}
Trying with weighted locations had the same result, some of them showing and some not.
Using locations "onClick"
In this case, normal LatLng were added and the map was updated until I got to the equator and then it stopped :p.
For the case of weightedLatLngs, it didn't update/show any :(
That's basically it... I don't know where to look for more information, whether it's something with the API, the device or something else.
Does anyone know why this might happen and/or where to look for a solution ?
Thank you in advance !
Btw, I'm using Android 4.0.4 on a Samsung Galaxy S Duos if that may prove useful..
The Googlemaps API for Heatmap only allows for 1,000 plotted points. You can reduced that by filtering out your original data or by converting to "weighted locations".
This looks like it was caused by this bug, where bounds calculations were excluding max values.
This is now fixed.
I'm trying to write an android application that uses google maps api version 2.
In Debug the application crashes when it executes the instruction:
setContentView(R.layout.activity_poi_map);
This is the error:
the source attachment does not contain the source for the file
Layoutinflater.class
I don't understand the reason. In headers I imported the whole class
android.view.*
Thank you in advance for any answer.
This is the code:
public class PoiMap extends FragmentActivity {
private GoogleMap pMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent callerIntent = getIntent();
final LatLng userCoord = callerIntent.getParcelableExtra("userCoord");
final Poi poi = (Poi) callerIntent.getSerializableExtra("poi");
setContentView(R.layout.activity_poi_map);
setUpMapIfNeeded(userCoord);
// Sets a callback that's invoked when the camera changes.
pMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
/* Only use the simpler method newLatLngBounds(boundary, padding) to generate
* a CameraUpdate if it is going to be used to move the camera *after* the map
* has undergone layout. During layout, the API calculates the display boundaries
* of the map which are needed to correctly project the bounding box.
* In comparison, you can use the CameraUpdate returned by the more complex method
* newLatLngBounds(boundary, width, height, padding) at any time, even before the
* map has undergone layout, because the API calculates the display boundaries
* from the arguments that you pass.
* #see com.google.android.gms.maps.GoogleMap.OnCameraChangeListener#onCameraChange(com.google.android.gms.maps.model.CameraPosition)
*/
public void onCameraChange(CameraPosition arg0) {
// Move camera.
if (poi != null){
LatLng poiCoord = poi.getLatLng();
pMap.addMarker(new MarkerOptions()
.position(poiCoord)
.title(poi.getName())
.snippet(poi.getCategory())
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_star)));
Log.d("userCoord", userCoord.toString());
Log.d("poiCoord", poiCoord.toString());
double minY = Math.min(userCoord.latitude, poiCoord.latitude);
double minX = Math.min(userCoord.longitude, poiCoord.longitude);
double maxY = Math.max(userCoord.latitude, poiCoord.latitude);
double maxX = Math.max(userCoord.longitude, poiCoord.longitude);
Log.d("minY", " " + minY);
Log.d("minX", " " + minX);
Log.d("maxY", " " + maxY);
Log.d("maxX", " " + maxX);
LatLng northEast = new LatLng(maxY, maxX);
LatLng southWest = new LatLng(minY, minX);
LatLngBounds bounds = new LatLngBounds(southWest, northEast);
// move camera
pMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 40));
// Remove listener to prevent position reset on camera move.
pMap.setOnCameraChangeListener(null);
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_poi_map, menu);
return true;
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded(new LatLng(0.0, 0.0));
}
private void setUpMapIfNeeded(LatLng coord) {
// Do a null check to confirm that we have not already instantiated the map.
if (pMap == null) {
// Try to obtain the map from the SupportMapFragment.
pMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (pMap != null) {
setUpMap(coord);
}
}
}
private void setUpMap(LatLng userCoord) {
pMap.addMarker(new MarkerOptions()
.position(userCoord)
.title("Your location")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_user)));
pMap.animateCamera(CameraUpdateFactory.newLatLng(userCoord));
/* public static CameraUpdate newLatLngZoom (LatLng latLng, float zoom)
* Returns a CameraUpdate that moves the center of the screen to a latitude
* and longitude specified by a LatLng object, and moves to the given zoom
* level.
* Parameters
* latLng a LatLng object containing the desired latitude and longitude.
* zoom the desired zoom level, in the range of 2.0 to 21.0.
* Values below this range are set to 2.0, and values above it are set to 21.0.
* Increase the value to zoom in. Not all areas have tiles at the largest zoom levels.
* Returns
* a CameraUpdate containing the transformation.
*/
pMap.animateCamera(CameraUpdateFactory.newLatLngZoom(userCoord, 15));
}
}
This is a common question and I can never find a good answer for anyone so I'll do my best to help.
This sounds like you are missing the source code for Android. You need to download the Sources for Android SDK in Eclipse with the SDK Manager.
Open the SDK Manager in Eclipse
Find the version of android you want the source for. In this example, Android 4.2 (API17)
Check the box Sources for Android SDK
Click Install # packages
For example
After that, run your program and get to the point that you get that error. Now you will need to attach the documentation you've downloaded
Short
Click the button Edit Source Lookup Path
Click the Default folder
Click Add
Select File System Directory and click OK
Locate your downloaded source code. In this example, look for android-17 for API17. It will be in a directory such as adt-bundle\sdk\sources\android-17
Click OK a few times and your source is now linked.
Long
Click the button Edit Source Lookup Path
Click the Default folder and click Add
Select File System Directory and click OK
Locate your downloaded source code. In this example, look for android-17 for API17. It will be in a directory such as adt-bundle\sdk\sources\android-17
Click OK twice and it should look something like this
Click OK and enjoy your source code
This usually means that you are unable to access the source code whose bytecode is being called. In order to list out the exception you would need the original source which unfortunately is usually unavailable in jar formats.
Your option is to update the .jar file by updating your Android SDK with correct Rev’s and let it compile again to fix the issue.
I've been pulling my hair out trying to get my own offline Mobile Atlas Creator OSMDroid SQLite map working with OSMDroid 3.0.8 without luck. It's been a long 3 days. I'll try to explain with clips from my application. I've been extending ItemizedIconOverlay and OverlayItem so I hope it doesn't get too confusing.
I created my own OSMDroid SQLite map file with 3 different zoom levels for a small are, like 10 square kms. I copied the resulting "base.sqlite" file into my project /res/raw/ directory. Note that the GeoPoints in my application should be well within the map's tile range. The "base.sqlite" file should get saved to the application specific data directory.
Next I turfed the /osmdroid directory on my phone so I could get the previously cached maps off. I thought I had my own offline maps working until I turned on Airplane mode and noticed the cached maps were still available.
Now all I get is blanks. I have no clue how to get this going. I've see a couple of examples but after a ton of experimentation I haven't been successful in getting any of them working.
private Hashtable<String, NodeOverlayItem> nodes = new Hashtable<String, NodeOverlayItem>();
private MapView mapView;
private Context context;
private LocationManager locManager;
private MapController mapController;
private MapTileProviderArray mapProvider;
private String mapTileArchivePath = "base.sqlite";
private ResourceProxy resourceProxy;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
this.mapView = new MapView(this, 256);
this.mapView.setBuiltInZoomControls(true);
this.mapView.setMultiTouchControls(true);
this.context = this.getApplicationContext();
this.resourceProxy = new DefaultResourceProxyImpl(context);
XYTileSource TILERENDERER = new XYTileSource("test",
ResourceProxy.string.offline_mode,
1, 20, 256, ".png", "http://127.0.0.1");
SimpleRegisterReceiver simpleReceiver = new SimpleRegisterReceiver(this.context);
IArchiveFile[] archives = { ArchiveFileFactory.getArchiveFile(this.getMapsFile()) };
MapTileModuleProviderBase moduleProvider = new MapTileFileArchiveProvider(
simpleReceiver,
TILERENDERER,
archives);
this.mapProvider = new MapTileProviderArray(TILERENDERER, null, new MapTileModuleProviderBase[] { moduleProvider });
this.mapProvider.setUseDataConnection(false);
this.mapView = new MapView(this, 256, this.resourceProxy, this.mapProvider);
this.mapView.setUseDataConnection(false);
mapController = mapView.getController();
mapController.setZoom(18);
mapController.setCenter(new GeoPoint((int)(45.349622 * 1E6), (int)(-75.880700 *1E6)));
this.setContentView(mapView);
} catch(Exception ex) {
Log.e("test", ex.getMessage());
}
}
public File getMapsFile() throws IOException {
Log.d("test", "Trying to load map tiles to: " + this.mapTileArchivePath);
FileOutputStream fos = this.openFileOutput(this.mapTileArchivePath, Context.MODE_PRIVATE);
InputStream in = getResources().openRawResource(R.raw.osmdroid);
byte[] buff = new byte[1024];
int read = 0;
try {
while ((read = in.read(buff)) > 0) {
fos.write(buff, 0, read);
}
} finally {
in.close();
fos.close();
}
return new File(this.getFilesDir(), this.mapTileArchivePath);
}
OK! I know what I doing wrong and I have it all working now! (I'm excited :)
Firstly, I had some trouble with writing my Raw resource map file to the application specific directory (e.g. openFileOutput()) I'm using a Galaxy Nexus which doesn't have an SD slot so I can't dump the map file to SD. Ensure the maps file you intend to use is byte compared with the original copy. Eclipse's DDMS perspective is useful to view a device's file structure.
I also switched to the OSMdroid Zip format. I then made sure the XYTileSource() name matched the directory created in the Zip file by MOBAC, plus ensure the tile size and zoom levels match.
XYTileSource TILERENDERER = new XYTileSource("OSM CloudMade 1", ResourceProxy.string.offline_mode, 16, 18, 256, ".png", "http://127.0.0.1");
MOBAC by default will create 256 pixel tiles. I created an atlas file with 16, 17, and 18 zoom levels. PNG is the default MOBAC tile image format.
Also, if your map file has any issues, ArchiveFileFactory.getArchiveFile() will catch them, even before MapTileFileArchiveProvider.
Here's my usage. Just make every effort to get your IArchive setup correctly and you should be ok:
XYTileSource TILERENDERER = new XYTileSource("OSM CloudMade 1", ResourceProxy.string.offline_mode, 16, 18, 256, ".png", "http://127.0.0.1");
SimpleRegisterReceiver simpleReceiver = new SimpleRegisterReceiver(this.context);
IArchiveFile[] archives = { ArchiveFileFactory.getArchiveFile(this.getMapsSdCard()) };
MapTileModuleProviderBase moduleProvider = new MapTileFileArchiveProvider(
simpleReceiver,
TILERENDERER,
archives);
this.mapProvider = new MapTileProviderArray(TILERENDERER, null, new MapTileModuleProviderBase[] { moduleProvider });
this.mapProvider.setUseDataConnection(false);
this.mapView = new MapView(this, 256, this.resourceProxy, this.mapProvider);
this.mapView.setUseDataConnection(false);
Maybe I'm the only one who had trouble with this, but osmdroid doesn't clearly document how to do this, and when I opened the issue I couldn't get them to comment on my usage. If they had said I was implementing MapTileFileArchiveProvider correctly or included a good offline mapping sample, I would have focused on everything else first.
If you want to use sqlite db you only have to change
ArchiveFileFactory.getArchiveFile(this.getMapsSdCard())
to
MBTilesFileArchive.getDatabaseFileArchive(f)
where f is a File that points to your sqlite database.
I have an Android application and I'm trying to populate a Google Map with a route, this route is store on a JSON array this way:
JSONArray.getString("points") = ["-33.45591917507404, -70.59198361376951","-33.453484420618416, -70.61635952929686"]
So in this case I have
Point A=(-33.49088437162095, -70.64043194102163) and
Point B=(-33.49423964397045, -70.63992768572683)
And my route or path is A-----B
I'm new to Android and I was wondering how to get this to work. Also, in this case my route is A-----B, but it can also be A----B----C----D. I can have any number of points on the path.
One thing you can try is the Google Maps Polyline object: https://developers.google.com/maps/documentation/javascript/reference#Polyline You specify to setPath() an ordered list of the points (either an Array of LatLng or an MVCArray or LatLng), you want to connect together on the map, and Google Maps will make a polyline for you to your specifications.
// path = Array of LatLng or MVCArray of LatLng
routeLine = new Polyline();
routeLine.setPath(JSONArray);
In your case, passing JSONArray into setPath should work OK.
If you want to get fancy and incorporate directions, you need to use the Google Directions API. https://developers.google.com/maps/documentation/javascript/directions
// All waypoints must be stopovers for the Directions service to optimize their route.
// start & end are of type String or LatLng, waypts is an array of String or LatLng
request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: [type Boolean],
travelMode: [type TravelMode]
};
// go on and actually perform the request
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
// if successful, this will run
}
});
Once you finish constructing your object, you should be able to display it by running setMap(map:Map), such as
routeLine.setMap(map)