ThinkGeo.com    |     Documentation    |     Premium Support

Set MapView current Extent to a calculated RectangleShape

Afternoon ThinkGeo.

During the init of my map I need to set where the map is looking. All the examples you have use a fixed RectangleShape and that works well. But I cannot use a set in code fixed point.

Being a mobile app I want to use the following rules in the defined order when the previous one cannot be used:

  1. If I have any features then get a bounding box of those and use that as extent.
  2. If no features yet then lets use the Devices location as a starting point.
  3. If I cannot obtain Devices location (permissions not given, etc) then I will simply show the country as the extent.

Lets talk about each of those rules as I have a few questions on each. I now see why your samples all use a set in code fixed Rectangle as this is hard. :slight_smile:

  1. If I have any features. I say if I have any as the features will be coming down the line using SignalR so the data may have arrived or not. I cannot be sure. In the early stages of my development I had the simple scenario of a single Overlay and Layer. I used the following code:
    MapView.CurrentExtent = RectangleShape.ScaleUp(MapView.Overlays[MyOverlay].GetBoundingBox(), 100).GetBoundingBox();
    This worked well when there are features within that Overlay. I get a box, then I scaled it a little and it looked perfect. I note that when there are no features to be found in that Overlay then the bounding box is small and is the middle of the map. No error just in the middle of the ocean. Today as my app progresses I have many Overlays with many Layers so I need to do something different. I also have to be careful to not try to obtain a bounding box for no features.

So the logic here I use is to iterate over all the Overlays, then iterate over the layers and if there are features I get the bounding box and pop that into a collection as I may have quite a few.
At the end if there are entries in the the collection I then take the first entry as a bounding box and then for each one after the first I use RectangularShape.ExpandToInclude. At the end of this I should have a bounding box that encompasses all my features. I have yet to test this but I think this logic is sound. What do you think?

  1. Center on Device Location.
    If I have no features, which is quite possible, I then request for the devices coordinates.
    I have those and I create a baseshape from the coordinates using the correct projection.
    This is where I am having some issue as I create a boundingbox from that baseshape and set that as my extent. It is the correct position on map but the zoom is not right and the tiles do not render correctly. If I then zoom out using the map controls it is perfectly rendered. How do I get the correct zoomlevel during mapview init? I cannot use zoomto as the map has not completed. I guess I am looking to be at the city block zoom level if I am centering on Device. How do I set that using the extent?

  2. Have the extent set to the country level.
    This one is easy as I can hard code this in code and this is my final fall back if the user insists on not allowing my app to obtain the device location.

I hope you can help here with the Center on Device Location.

My environment is:
Xamarin Forms 5.0.0.2401
ThinkGeo Maps 12.3.18

Cheers
Chris …

Hey @Chris_Marassovich1,

I think your logic with getting the bounding boxes for each of the layers for the first case is pretty good. I would say that you probably want to make sure that you don’t include all of your overlays though. Let’s say you are using a base map like OpenStreetMap or Google. Getting the Bounding Box of those layers/overlays would yield in the whole world, which isn’t what you want. If you have a handful of overlays that just contain your app’s shape data, use those.

For Centering on the Device Location, getting a good bounding box from a point can be a bit tricky. since you aren’t able to use the mapView.ZoomTo method, another good way would be to buffer the bounding box of the device location’s point shape:

// Buffers a point's bounding box by 1km
var boundingBox = deviceLocation.GetBoundingBox().Buffer(1, GeographyUnit.Meter, DistanceUnit.Kilometer).GetBoundingBox();
mapView.CurrentExtent = boundingBox;

This code will expand the bounding box of the device’s location by 1 kilometer. Since the bounding box of the device location is already miniscule, it’s basically creating a RectangleShape 1 square kilometer centered on the device’s location. That should be sufficient to be a neighborhood. You may want to go bigger or smaller.

Hope that helps!

Thanks,
Kyle

Hi @Kyle_Day,

.Buffer() … how simple and perfect. Yes getting a good bounding box from a point is hard.
I must admit for me the API doco on .Buffer() certainly does not lead me to think it could have been a solution to my issue. But I am new to spatial and mapping.
I would suspect in the mobile space this requirement of mine to “default” the map would be quite regular and is a good candidate to be added to your sample solution. I appreciate why it was left out and the current extent is just hard coded cause this stuff has lots of moving parts in mobile.

As for my logic on processing all overlays looking for features you are quite right that my logic is left wide open to extra unwanted processing. I was restricting it to process overlays only of type LayerOverlay with a layer of only InMemoryFeatureLayer and right now it is working perfectly but I see how that can be short lived as the OSM or Google Overlays could easily fit within those rules.
My problem is that I have quite a lot of Overlays with my shape data and I will create overlays at runtime based on data coming down the line.
I shall have to work something out and thanks for pointing out my mistake.

Once again thanks for your help and prompt response.

Cheers
Chris …

Hey @Chris_Marassovich1,

Yeah, .Buffer() will do the trick for you, and I’ll admit that the api docstring on that method definitely doesn’t explain what it does clearly. We try to keep up on those when we have the legroom, but it could be better.
The reason why we don’t do anything complicated with the starting extent on our sample is because we don’t want to pile on too much on a sample so that people can concentrate on learning what the sample does and not what some query is being used to set the extent of the map does. So, we decided to just hard code one that is basically the same area of the map at all times. We let the sample concerning setting the map extent to handle the more complicated side of it. Yours is a unique case in that you are setting the map extent in the initializer and not in the .OnAppearing() event of the page, which is fine.

Yeah, so long as you make sure that the layers you inspect are of your interest, then you should be good. Most cases you would just need one overlay for your shape data, but more complicated setups might have more. For instance, our ThinkGeo Maps has a ground overlay, underground overlay, and above ground overlay with shape data to ensure draw ordering for things like overpasses and tunnels.

Thanks,
Kyle