ThinkGeo.com    |     Documentation    |     Premium Support

ZoomToScale strange behavior

Hi All,


it seem to me that WpfMap.ZoomToScale doesn't work well.



        
  • I tried to Zoom In/out on screen point to some scales in ZoomLevelSet, but it works only when i have more detailed zoom.


 



        
  • when i zoom the interaction effect is keeping mouse position - it shows zooming on mouse position but then it centers on the right position i entered, strange.


In attached example i try to ZoomIn, ZoomOut on specific point (red ellipse placed on the bottom of the map control).



        public MainWindow()
        {
            InitializeComponent();
        }

        private void WpfMapLoaded(object sender, RoutedEventArgs e)
        {
            wpfMap1.MapUnit = ThinkGeo.MapSuite.Core.GeographyUnit.Meter;
            
            var overlay = new OpenStreetMapOverlay();
            overlay.TileType = TileType.SingleTile;
            wpfMap1.Overlays.Add(overlay);
            wpfMap1.Refresh();
        }

        private void ZoomInClick(object sender, RoutedEventArgs e)
        {
            Point pointCanvas = new Point((double)ellipse.GetValue(Canvas.LeftProperty), (double)ellipse.GetValue(Canvas.TopProperty));
            Point pointMap = canvas.TranslatePoint(pointCanvas, wpfMap1);
            ScreenPointF p = new ScreenPointF((float)pointMap.X, (float)pointMap.Y);

            double targetScale = ZoomLevelSet.GetLowerZoomLevelScale(wpfMap1.CurrentScale, wpfMap1.ZoomLevelSet);
            wpfMap1.ZoomToScale(targetScale, p);
        }

        private void ZoomOutClick(object sender, RoutedEventArgs e)
        {
            Point pointCanvas = new Point((double)ellipse.GetValue(Canvas.LeftProperty), (double)ellipse.GetValue(Canvas.TopProperty));
            Point pointMap = canvas.TranslatePoint(pointCanvas, wpfMap1);
            ScreenPointF p = new ScreenPointF((float)pointMap.X, (float)pointMap.Y);


            double targetScale = ZoomLevelSet.GetHigherZoomLevelScale(wpfMap1.CurrentScale, wpfMap1.ZoomLevelSet);
            wpfMap1.ZoomToScale(targetScale, p);
        }

Please, what am i doing wrong?


Thank you Libor


 


 



TestZooming.zip (13.5 KB)

Libor, 
  
 Thanks for your sample code that I can recreate your problem, I think it’s our bug caused precision of double, We will try to fix it or give you a workaround first. Any progress I will let you know. 
  
 Thanks, 
 James

 Libor,


Eventually, I figured out the problem, it's precision problem as I mentioned. Our API accept float(not double) as parameters, they're based on GDI+ API, but in the following time WPF is popular, however WPF allow double(not float) so that the same of two number divided have two different results if ones are double and the other ones are float. 


I provide a workaround to you that you can fix your problem, we will consider to update our WpfDesktopEdition to fix it totally.


//wpfMap1.ZoomToScale(targetScale, p);
            wpfMap1.CurrentExtent = ZoomToScale(targetScale, wpfMap1.CurrentExtent, wpfMap1.ActualWidth, wpfMap1.ActualHeight, pointMap.X, pointMap.Y);
            wpfMap1.Refresh();

private RectangleShape ZoomToScale(double targetScale, RectangleShape worldExtent, double screenWidth, double screenHeight, double offsetScreenPointX, double offsetScreenPointY)
{
    PointShape worldPointBefore = ExtentHelper.ToWorldCoordinate(worldExtent, (float)offsetScreenPointX, (float)offsetScreenPointY, (float)screenWidth, (float)screenHeight);
    RectangleShape resultExtent = ZoomToScale(targetScale, worldExtent, screenWidth, screenHeight);
    PointShape worldPointAfter = ExtentHelper.ToWorldCoordinate(resultExtent, (float)offsetScreenPointX, (float)offsetScreenPointY, (float)screenWidth, (float)screenHeight);

    resultExtent.TranslateByOffset(worldPointBefore.X - worldPointAfter.X, worldPointBefore.Y - worldPointAfter.Y, GeographyUnit.Meter, DistanceUnit.Meter);

    return resultExtent;
}

private RectangleShape ZoomToScale(double targetScale, RectangleShape worldExtent, double screenWidth, double screenHeight)
{
    double resolution = targetScale / 3779.5296;
    double newWidth = resolution * screenWidth * .5;
    double newHeight = resolution * screenHeight * .5;
    PointShape centerPoint = worldExtent.GetCenterPoint();

    PointShape newUpperLeftPoint = new PointShape(centerPoint.X - newWidth, centerPoint.Y + newHeight);
    PointShape newLowerRightPoint = new PointShape(centerPoint.X + newWidth, centerPoint.Y - newHeight);
    return new RectangleShape(newUpperLeftPoint, newLowerRightPoint);
}

Thanks,


James