Search code examples
google-mapsgmsgroundoverlay

Google Maps SDK for iOS : GMSGroundOverlay on wrong side of the Earth it zoom less than 3.0


I'm trying to place an image in a GMSGroundOverlay but noticed something weird when I zoom out to zoom < 3.0 (world level). The image should cover the whole screen of the iPad which is does fine at zoom >= 3.0. but if I zoom out the image is placed offscreen and is visible if you pan left or right.

It's like its been wrapped around the globe but on the reverse side.


  • The user pans/zooms the map.
  • When they stop I get the screen dimensions for the ipad I call a web service to get the image to place over the whole screen.
  • It contains ship positions and alpha channel so you can see the map.

I find the 4 points of the map thats on the iPad.

                        //southWest = nearLeft
                    CLLocationCoordinate2D SW_ = CLLocationCoordinate2DMake([vesselTileRequest_.nearLeft_latitude doubleValue],
                                                                            [vesselTileRequest_.nearLeft_longitude doubleValue]);


                    //northEast = farRight = top right of ipad screen
                    CLLocationCoordinate2D NE_ = CLLocationCoordinate2DMake([vesselTileRequest_.farRight_latitude doubleValue],
                                                                            [vesselTileRequest_.farRight_longitude doubleValue]);
                    //-----------------------------------------------------------------------------------
                    CLLocationCoordinate2D SE_ = CLLocationCoordinate2DMake([vesselTileRequest_.nearRight_latitude doubleValue],
                                                                            [vesselTileRequest_.nearRight_longitude doubleValue]);


                    //northEast = farRight = top right of ipad screen
                    CLLocationCoordinate2D NW_ = CLLocationCoordinate2DMake([vesselTileRequest_.farLeft_latitude doubleValue],
                                                                            [vesselTileRequest_.farLeft_longitude doubleValue]);

I place the image at SW,NE as per google docs:

overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
                                                     coordinate:NE_];
              self.overlay = [GMSGroundOverlay groundOverlayWithBounds:overlayBounds
                                                                            icon:responseImage_];

This works fine for any zoom level higher than 3.0.

But when we zoom out, nothing appears on the map but if you pan left or right the image has bee mapped to the opposite side of the earth.

I've had to turn of overlap mapping when zoom is < 3.0.

I tried every combination of NW/NE/SW/SE combo but all opposite corners just put the image on the wrong side of the earth.

if(self.mapView.camera.zoom < 3.0){
                        //nothing appears
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NW_
//                                                                                 coordinate:NE_];

//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NW_
//                                                                                 coordinate:SW_];
//
                        //appears but off screen
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NW_
//                                                                                 coordinate:SE_];
//                          //nothing
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NE_
//                                                                                 coordinate:NW_];
                        //off screen
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NE_
//                                                                                 coordinate:SW_];
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:NE_
//                                                                                 coordinate:SE_];
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
//                                                                                 coordinate:NW_];
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
//                                                                                 coordinate:NE_];
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
//                                                                                     coordinate:SW_];
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
//                                                                                 coordinate:SE_];
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
//                                                                                 coordinate:NW_];
//                            overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
//                                                                                 coordinate:NE_];
                        overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
                                                                             coordinate:SW_];
                        overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SE_
                                                                             coordinate:SW_];

                        self.overlay = [GMSGroundOverlay groundOverlayWithBounds:overlayBounds
                                                                            icon:responseImage_];

                        //-----------------------------------------------------------------------------------
////                            CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(self.mapView.projection.visibleRegion.farLeft.latitude,
////                                                                                                 self.mapView.projection.visibleRegion.farLeft.longitude);
//                            CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(0.0,
//                                                                                                 0.0);
//                            
//                            DebugLog(@"self.mapView.camera.zoom:%f",self.mapView.camera.zoom);
//                            self.overlay = [GMSGroundOverlay groundOverlayWithPosition:position_farLeft
//                                                                                  icon:responseImage_
//                                                                             zoomLevel:self.mapView.camera.zoom];
                        //-----------------------------------------------------------------------------------

                    }else{
                        //correct as of docs
                        overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:SW_
                                                                             coordinate:NE_];
                        self.overlay = [GMSGroundOverlay groundOverlayWithBounds:overlayBounds
                                                                            icon:responseImage_];
                    }

I also tried other methods to create the overlay but if I hard code the position to 0,0 so on the equator. It appears over australia. Its again on the opposite side of the earth to where it should be

  CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(self.mapView.projection.visibleRegion.farLeft.latitude,
                                                                   self.mapView.projection.visibleRegion.farLeft.longitude);
  CLLocationCoordinate2D position_farLeft = CLLocationCoordinate2DMake(0.0,
                                                                 0.0);
  DebugLog(@"self.mapView.camera.zoom:%f",self.mapView.camera.zoom);
  self.overlay = [GMSGroundOverlay groundOverlayWithPosition:position_farLeft
                                                  icon:responseImage_
                                             zoomLevel:self.mapView.camera.zoom];

Result - nothing appears on the map

Result - nothing appears on the map

If i tap, hold and pan the image is off the screen.

If i tap, hold and pan the image is off the screen.

if i do the same and pan to the right you see the image is exactly on the opposite side of the earth to the rect shown on the ipad screen

pan left


Solution

  • Digging into this, and for the first issue raised - the GMSGroundOverlay being on the reverse side of the globe at zoom levels of 3.0 or lower it appears that the culprit is that GMSCoordinateBounds initWithCoordinate:coordinate: initialization method normalizes the coordinates, as per the method documentation:

    /**
     * Inits the northEast and southWest bounds corresponding
     * to the rectangular region defined by the two corners.
     *
     * It is ambiguous whether the longitude of the box
     * extends from |coord1| to |coord2| or vice-versa;
     * the box is constructed as the smaller of the two variants, eliminating the
     * ambiguity.
     */
    

    It turns out for an iPad, held in landscape mode, that zoom level 3.0 is the point at which a GMSGroundOverlay for the entire visibleRegion covers 180 degrees. Zoom out, and GMSCoordinateBounds normalizes to the smaller area, which just happens to be the other side of the globe.

    The real answer here is to use GMSTileLayer.