ThinkGeo.com    |     Documentation    |     Premium Support

Setting CurrentExtent and aspect ratio

We are seeing strange behavior when setting the current extent for the map display. Our map control is displayed as a square, 475 X 475. We have some code that takes in a top left and bottom right points and sets the current extent of the map display:


 



 Dim rect = New RectangleShape(topLeft.ToThinkGeoPointShape(), bottomRight.ToThinkGeoPointShape())
Me.CurrentExtent = rect
Me.Refresh()
(.ToThinkGeoPointShape() is an extension method on our internal LatLong struct)


The visible boundaries of the map is not always set as we have specified. For example, if we set the top left and bottom right corners to 47.78/-124.4 and 40.0899/-116.7043, the visible map is set correctly. But if we specify the top left and bottom right as 46.5036/-124.11524 and 41.372696/-116.98986, the visible boundary corners are actually 47.5/-124.055 and 40.43546/-117.0198. The aspect ratio of the display is also skewed. The difference is the first set of coordinates has a height/width ratio of roughly 1, whereas the second set of coordinates has a height/width ratio of .72, which is COS(Latitude).


Can you shed some light on what happens when the CurrentExtent is set? Or more specifically, under what circumstance would the CurrentExtent be changed and what is the algorithm for computing the change?


Thanks,


pk



Paul,


Thanks for your post and questions.
    I am not sure you which snapping mode are using against? Snapped or none? There is a bit difference between them. When it is snapped, we will adjust the extent to some adjacent extent according to the preset 20 zoom level scales. After this step, the rest is exactly the same for both snapping modes.
   Then what we are trying to do is to adjust the extent according to the height / width ratio of the Map Control, also will keep the center of the extent not changed. Based on these conditions, we calculate out a new extent with exactly the same ratio of Map control also with the same center. Following is the code snippet used to adjust according to the height / width ration, take a look if you are interestd.

double screenRatio = screenHeight / screenWidth;
double extentRatio = worldExtent.Height / worldExtent.Width;
 
double newWidth = 0;
double newHeight = 0;
 
if (extentRatio > screenRatio)
{
      newHeight = worldExtent.Height;
      newWidth = newHeight / screenRatio;
}
else
{
      newWidth = worldExtent.Width;
      newHeight = newWidth * screenRatio;
}
 
PointShape centerPoint = worldExtent.GetCenterPoint();
PointShape upperLeftPoint = new PointShape(centerPoint.X - newWidth * 0.5, centerPoint.Y + newHeight * 0.5);
PointShape lowerRightPoint = new PointShape(centerPoint.X + newWidth * 0.5, centerPoint.Y - newHeight * 0.5);
 
return new RectangleShape(upperLeftPoint, lowerRightPoint);

 
Any more questions please feel free to let me know.
Thanks.
Yale

Thanks Yale for the prompt reply. 
  
 Our map data is in decimal degrees, and when we set the current extent, we are defining the rectangle in decimal degrees as well. It seems that your internal computations are attempting to take a linear dimension (screen pixels) and map a non-linear dimension (the rectangle in decimal degrees) onto it. I believe this is why the aspect ratio of our map is being streched - it doesn’t stretch at the equator, but the further from the equator it gets the more streching occurs. 
  
 Is there a method to set the current extent without doing any of the adjustments to the ratio? 
  
 Thanks, 
 pk

 To be a little bit more illustrative, I will complete Yale's explantion with some pictures that I hope will clarify things. In green is the extent that you set for your map and you can see how the resulting extent of the map gets ajusted based on the width/height ratios of the extent set and of the map. You can also see the code I used for this illustration.


Note that the unit of the map used should not matter whether it is in decimal degrees, meters or feet, we simply fit the extent according to those ratios as you can see in the pictures. No "stretching" is happening.





 



    winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
    winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);

    //We set the ZoomLevelSnapping property to None to see the extent adjustment happening.
    winformsMap1.ZoomLevelSnapping = ZoomLevelSnappingMode.None;

    WorldMapKitWmsDesktopOverlay worldMapKitDesktopOverlay = new WorldMapKitWmsDesktopOverlay();
    winformsMap1.Overlays.Add(worldMapKitDesktopOverlay);

    InMemoryFeatureLayer inMemoryFeatureLayer = new InMemoryFeatureLayer();
    inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.StandardColors.Transparent,
                                GeoColor.StandardColors.Green, 3);
    inMemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

    //Width/Height ratio of Map and Extent are equal. (w/h = 1 in both cases)
    RectangleShape rectangleShape1 = new RectangleShape(-124.4, 47.78, -116.7043, 40.0899);

    //Width/Height ratio of Map and Extent are unequal. (w/h > 1 for the extent)
    RectangleShape rectangleShape2 = new RectangleShape(-124.11524, 46.5036, -116.98986, 41.372696);

    //Width/Height ratio of Map and Extent are unequal. (w/h < 1 for the extent)
    RectangleShape rectangleShape3 = new RectangleShape(-123.09,47.15,-118.29,40.79); 

    inMemoryFeatureLayer.Open();
    inMemoryFeatureLayer.InternalFeatures.Add(new Feature(rectangleShape3));
    inMemoryFeatureLayer.Close();

    LayerOverlay layerOverlay = new LayerOverlay();
    layerOverlay.Layers.Add(inMemoryFeatureLayer);
    winformsMap1.Overlays.Add(layerOverlay);

    winformsMap1.CurrentExtent = rectangleShape3;

    winformsMap1.Refresh();


Thanks for the help, Val. I think the issue lies in the assumption that 1 degree of latitude = 1 degree of longitude when calculating the aspect ratio of the extent. I believe the aspect ratio should be COS(centerPointLatitude).


A colleague of mine has produced the attached image from Google Earth. It is adjusted to a square display (width/height = 1 for map) and then zoomed to Oregon. Note the aspect ratio of the attached image to yours.



Using the cursor to get approximate Lat/Lon of the four corners of the display, it shows a ratio close to COS(centerPointLatitude) as it should. Thoughts?



I see what you are showing but you cannot compare Google Earth with World Map Kit as the projections are different. While World Map Kit is in straight WGS84, Google Earth applies some other projection tricks to get the earth as a globe. earth.google.com/support/bin/static.py


 You can set for example the World Map Kit to another projection such as Spherical Mercator (or commonly known as Google projection used by Google Map, Bing Map etc) with unit in meters and have the coordinates in Longitude/Latitude and you will see that the way the x (longitude) and y (latitude) are changing is not uniform but according to the projection used. There is a good Code Community project that shows that. I recommend you take a look at Graticule with Projection wiki.thinkgeo.com/wiki/Map_Suite_Wp...on_Samples. You even see the graticule for meridians and parallels and you can clearly see that the degree long/lat ratio varies according to the latitude.




The application always displays the map in a square frame, on screen and also in printed format.  We have several sizes of frames, all square, in which we want to display the same world map extents.  So, the scale factor is different in each frame but the world extents are the same.  We are having a problem defining the displayed world extents in either degrees or meters such that the world distance, in meters, is approximately the same both horizontally and vertically.

 I don't know what you are trying to accomplish exactely but I am trying to raise some awareness about some realities with working with maps in different projections and units. In the picture below, you can see that if you draw a rectangle of 5 degrees of longitude and longitude, it is going to be an elongated rectangle with the map in meters (Spherical Mercator projection) while it is going to be a perfect square in the map in decimal degrees (Geodetic). It is just we way it is. Projection applies distortions, change in scale etc that you have to work with and understand those limitations. For more info on that subject:


en.wikipedia.org/wiki/Map_projection for info on projections in general


en.wikipedia.org/wiki/Latitude to understand Degree length


 


-5 x 5 of degrees with map in Spherical Mercator (meters)



 


5 x 5 of degrees with map in Geodetic  (decimal degrees)



 


 



What we need are ThinkGeo Wiki articles that are that comprehensive on Extents. 
  
 I am having similar problems to Paul (except my problem is with the data rather than the display) - is there any comprehensive information available anywhere here on extents and how they fit in with map control size as well as scale, projection, geography units, etc.?

 We recently set up ThinkGeo Wiki with the goal of providing comprehensive support and high level explanations on various concepts. We are still short of that goal but working on it. In the meantime, reading the article from Wiki on general concepts of map projections helps understanding how this is applied with our map controls and you can see all the various Code Community samples touching projection: wiki.thinkgeo.com/wiki/Map_Suite_De...on_Samples

 



Looking forward to something like a Wiki explanation as Wikipedia has done. Projections & scales I have no problems with - been using them for getting on for 20 years working as programmer for various hydrographic survey companies. Extents are another matter - they seem overly complicated to the ‘newbies’ judging from the amount of questions you get in this forum on the subject. 
  
 Using examples is not so intuitive & takes a lot longer, while only giving a snapshot of the information required. I use VB2010 but I do have VS2010 and so can view the code samples in VC. However, most of them first require converting to the newer version, then invariably the references have to be changed, then other errors need to be fixed - just doing ZoomToFullExtent now and had the first 2 items above & now the following to sort out: 
 Error 1 The type ‘System.Collections.Specialized.INotifyCollectionChanged’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’. C:\Users\User\Documents\Visual Studio 2010\Projects\ThinkGeo Examples\VC\ServicesEditionSample_ZoomToFullExtent_CS_100415\ZoomToFullExtent\TestForm.cs 47 32 ZoomToFullExtent 
  
 When I get all that sorted out I have a working VC application which I can sort of understand but then I may have to convert to VB. So, it will be a 4 step process before I get some code sample which may add a little more to my knowledge. Definitely a Wiki page which told me everything I needed to know about Extents would be much better. Not sure if your development team have access to MapInfo & MapBasic reference manuals but they really set a good standard for how to explain concepts right down to every parameter of each command. 
  
 So, my vote is for your first in-depth Wiki article to be on Extents! :-) 


David,


Thanks for your post and feedback.
Yes, the error 'System.Collections.Specialized.INotifyCollectionChanged' is caused because we added the implementations of INotifyCollectionChanged, INotifyPropertyChanged interfaces in the class GeoCollection since last public release, so every time we reference the MapSuite dll set we may need to reference the WindowsBase DLL as what you have done.
 
I agree with you sometime to transfer from C# to VB or VB to C# is very troublesome, so we are trying to make the samples into both versions , while some samples published long time ago may ignore this issue, so sorry for the inconvenience for now.
 
We are now lunching our Wiki and many topics are being added or enhanced every day, we will keep an eye on the customer requirement and definitely make the wiki readable and comprehensive in the near future.
 
Any more questions please feel free to let me know.
 
Thanks.
 
Yale

Thanks Yale. I am looking forward to the Wiki library continuing to be developed. 
  
 I’ll add a +1 to David’s request - examples are great to show a tiny sliver of how to implement something, but they don’t work so well to explain the why and how things work. I frequently find myself looking at several examples to pick different pieces up to figure out how to accomplish something in ThinkGeo. Providing some articles to users that explain how things work and covering different subjects would be a huge help. 
  
 Thanks, 
 pk

I think there are many developers that are beyond needing more code samples.   I think we need a Wiki section called Overviews, with topics that tell us what is happening under the hood inside the ThinkGeo components.   Examples I might suggest:



        
  • Extensions, as has been suggested.   How are they used inside of the map.Draw event?   And when I do a map.DrawToBitmap (or whatever it is), how the extent of the current map is used to determine what gets rendered onto a bitmap with a different aspect ratio.    How do the ThinkGeo extent definitions map to more common GIS terms such as viewport extent vs worldextent, etc.

  •     
  • Draw -- I would love to see a flow-chart that tells me what happens on a Map.Draw.   And, within a layer, can we see exactly what the drawing internal call sequence is, in the abscence of any overridden layer or feature source methods.   Within the default DrawCore, are you iterating the styles, and calling the Draw method of each style?   Or are you drawing each feature, iterating the styles?

  •     
  • Explain the use of the drawing level within the above context of drawing multiple layers.   I have places where the labels of a layer drawn on the bottom of the map still show up above the features higher layers.    I need to understand exactly how the drawing level plays into multi-layer draws.

  •     
  • Refreshing overlays:   I have places where I refresh a single overlay, and it causes my DrawCore method to be executed on other layers that are drawn "below" the overlay being refreshed.  I would like to understand exactly what actions cause these lower layers to be drawn so that I can optimized my "refresh" drawing performance on layers that change.

  •     
  • Projections.   I'm not sure what is available on the Wiki for projections, and I really don't care.   I have them working just fine, but it seems to be a source of constant forum activity.   I think that is because ThinkGeo doesn't have the concept of a map projection that becomes the implicit "to" component of all layer projections.  

  •     
  • ScaleSets and how they apply... like the recent Active/InActive discussion.  

  •     
  • It would be great to have a Wiki topic dedicated to styles.   Not code samples, but a styles overview.   Like, the rules that if you apply a custom style, you loose the default styles, but if you set the custom style to null, your program breaks.   And LOTS of details about what the various style properties really mean.


I'm sure that I have thought of other topics at various early morning hours... but this might serve as a starter for what a developer that is someone experience with MapSuite would like to see, rather than some of the programming 101 stuff that tends to consume so much forum time.    Just my 2 cents.


 



Ted, 
  
   I know that we have in plan to write articles on some high level concepts. Going to such a low level of explanation like explaining the drawing internal call sequences, althought not directely useful for the developer, helps giving  a perspective on what is going on behind the hood and therefore helps writing better and more efficient code. Thank you for those ideas. I passed them to the team responsible for maintaining and expanding ThinkGeo Wiki.