private void DisplayThumbnails(string panoId, string cachePathBase)
        {
            StreetviewDownloaderModel _model = new StreetviewDownloaderModel
            {
                PanoID = panoId
            };

            // Clear previous items
            thumbnails.Children.Clear();

            //Set up downloader...
            Downloader.Downloader imageDownloader = new Downloader.Downloader(cachePathBase);

            System.Drawing.Image bigImage   = imageDownloader.GetFullImage(panoId, 2, null);
            panorama             panoObject = _model.DownloadPanoramaInfo(panoId);

            decimal panoYaw = panoObject.projection_properties.pano_yaw_deg;

            System.Drawing.Image smallImage = new System.Drawing.Bitmap(720, 360);
            using (Graphics g = Graphics.FromImage(smallImage)) {
                g.DrawImage(bigImage, 0, 0, smallImage.Width, smallImage.Height);
            }

            // Get all the thumbnails
            foreach (var annotation in panoObject.annotation_properties.OrderBy(item => item.yaw_deg))
            {
                var button   = new System.Windows.Controls.Button();
                var thumbImg = new System.Windows.Controls.Image();

                //headingDelta >= 2 || headingDelta <= -2
                System.Drawing.Image thumbnail = imageDownloader.ManipulateImage(smallImage, panoYaw, annotation.yaw_deg, 90);

                thumbImg.Source = ImageConverter(thumbnail);
                thumbImg.Width  = 180;

                button.Content = thumbImg;
                button.Click  += (object sender, RoutedEventArgs e) =>
                {
                    foreach (Button thumbButton in thumbnails.Children)
                    {
                        thumbButton.BorderThickness = new Thickness(1);
                        thumbButton.BorderBrush     = System.Windows.Media.Brushes.Gray;
                    }

                    button.BorderThickness = new Thickness(2);
                    button.BorderBrush     = System.Windows.Media.Brushes.Yellow;

                    DesiredHeading = annotation.yaw_deg;
                };
                thumbnails.Children.Add(button);
            }
        }
        private string GetPanoramaLocationText(panorama panoObject)
        {
            string location = string.Empty;

            string country   = panoObject.data_properties.country ?? string.Empty;
            string region    = panoObject.data_properties.region ?? string.Empty;
            string text      = panoObject.data_properties.text ?? string.Empty;
            string copyright = panoObject.data_properties.copyright ?? string.Empty;

            location = text + ", " + region + ", " + country + " " + copyright;

            return(location);
        }
        private void DisplayThumbnails(panorama panoObject, System.Drawing.Image bigImage)
        {
            // Clear previous items
            thumbnails.Children.Clear();
            keyboardPanoLinkList.Clear();

            //Set up downloader...
            Downloader.Downloader imageDownloader = new Downloader.Downloader(_model.CachePathBase);

            int     thumbnailKey = 1;
            decimal panoYaw      = panoObject.projection_properties.pano_yaw_deg;

            System.Drawing.Image smallImage = new System.Drawing.Bitmap(720, 360);
            using (Graphics g = Graphics.FromImage(smallImage)) {
                g.DrawImage(bigImage, 0, 0, smallImage.Width, smallImage.Height);
            }

            // Get all the thumbnails
            foreach (var annotation in panoObject.annotation_properties.OrderBy(item => item.yaw_deg))
            {
                var button   = new System.Windows.Controls.Button();
                var thumbImg = new System.Windows.Controls.Image();

                //headingDelta >= 2 || headingDelta <= -2
                System.Drawing.Image thumbnail = imageDownloader.ManipulateImage(smallImage, panoYaw, annotation.yaw_deg, 90);

                thumbImg.Source = ImageConverter(thumbnail);
                thumbImg.Width  = 125;

                button.Content = thumbImg;
                button.ToolTip = "Click to move to next image. Heading = " + annotation.yaw_deg + " PanoID = " + annotation.pano_id;
                button.Click  += (object sender, RoutedEventArgs e) =>
                {
                    foreach (Button thumbButton in thumbnails.Children)
                    {
                        thumbButton.IsEnabled = false;
                    }

                    _model.PanoID  = annotation.pano_id;
                    _model.Heading = annotation.yaw_deg;
                    RetrieveAndDisplayPanorama(annotation.pano_id);
                };
                thumbnails.Children.Add(button);

                keyboardPanoLinkList.Add(thumbnailKey++, annotation.pano_id);
            }
        }
        private async void TimeLapseAsync(string fileSavePath, string startPanoId)
        {
            int timelapseFileCounter = 1;

            continueTimelapse = true;
            _model.StopTimelapseVisibility = Visibility.Visible;
            string nextPanoId = startPanoId;

            try {
                while (continueTimelapse)
                {
                    Task  retrievePanoramaTask = RetrieveAndDisplayPanoramaAsync(nextPanoId);
                    await retrievePanoramaTask;

                    // Save the current image
                    displayedImage.Save(fileSavePath + FiveZero(timelapseFileCounter++) + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

                    // Get the pano info to find linked panoramas
                    panorama panoObject = _model.DownloadPanoramaInfo(nextPanoId);

                    if (panoObject.annotation_properties.Length > 0)
                    {
                        // Pick pano with closest heading
                        var nextPano = panoObject.annotation_properties.OrderBy(item => Math.Abs(_model.Heading - item.yaw_deg)).First();
                        nextPanoId     = nextPano.pano_id;
                        _model.Heading = nextPano.yaw_deg;
                    }
                    else
                    {
                        //No linked panoramas (it can happen)
                        continueTimelapse = false;
                        break;
                    }
                }
            } catch (Exception e) {
                MessageBox.Show(e.Message + Environment.NewLine + e.InnerException, "An error occured creating timelapse images");
            } finally {
                // Open the folder the images are saved to
                System.Diagnostics.Process.Start(fileSavePath.Substring(0, fileSavePath.LastIndexOf(@"\")));
            }
        }
        public panorama DownloadPanoramaInfo(string panoId)
        {
            //Set up downloader...
            Downloader.Downloader imageDownloader = new Downloader.Downloader(CachePathBase);

            //Download XML or Load from cache
            if (!System.IO.File.Exists(CachePathBase + panoId + @"\" + panoId + ".xml") || new FileInfo(CachePathBase + panoId + @"\" + panoId + ".xml").Length == 0)
            {
                if (!System.IO.Directory.Exists(CachePathBase + panoId))
                {
                    System.IO.Directory.CreateDirectory(CachePathBase + panoId);
                }
                imageDownloader.Download("http://cbk0.google.com/cbk?output=xml&panoid=" + panoId, CachePathBase + panoId + @"\" + panoId + ".xml");
            }

            XmlSerializer serializer = new XmlSerializer(typeof(panorama));
            StreamReader  reader     = new StreamReader(CachePathBase + panoId + @"\" + panoId + ".xml");
            panorama      panoObject = (panorama)serializer.Deserialize(reader);

            reader.Close();

            return(panoObject);
        }
        private async Task RetrieveAndDisplayPanoramaAsync(string panoId)
        {
            try {
                // Show progress bar
                _model.ProgressBarVisibility = Visibility.Visible;

                // Holds technical meta information about the pano
                panorama panoObject = await Task.Run(() =>
                {
                    return(_model.DownloadPanoramaInfo(panoId));
                });

                if (panoObject.data_properties == null)
                {
                    _model.Location = "Error: Panorama has invalid XML data...";
                    return;
                }

                _model.Location = GetPanoramaLocationText(panoObject);

                if (panoObject.data_properties.image_width < 3330 && _model.ZoomLevel > 3)
                {
                    _model.ZoomLevel = 3;                     //We're dealing with a low res panorama here
                }

                // Progress value, max value, status text
                IProgress <Tuple <int, int, string> > progressIndicator = new Progress <Tuple <int, int, string> >(ReportProgress);

                var image = await Task.Run(() =>
                {
                    return(DownloadBigPano(panoId, progressIndicator));
                });

                // Show the image width and height on screen
                UpdateDimenions(image.Width, image.Height);

                // Download progress complete
                progressIndicator.Report(new Tuple <int, int, string>(0, 100, "Displaying image..."));

                // Set the center of the image to the desired heading and narrow to selected field of view
                Downloader.Downloader imageDownloader  = new Downloader.Downloader(_model.CachePathBase);
                System.Drawing.Image  manipulatedImage = null;
                if (_model.FieldOfView == 360 && _model.Zero360Timelapses)
                {
                    manipulatedImage = imageDownloader.ManipulateImage(image, panoObject.projection_properties.pano_yaw_deg, 0, _model.FieldOfView);
                }
                else
                {
                    manipulatedImage = imageDownloader.ManipulateImage(image, panoObject.projection_properties.pano_yaw_deg, _model.Heading, _model.FieldOfView);
                }
                _model.MainImageSource = ImageConverter(manipulatedImage);
                // Show the image width and height on screen
                UpdateDimenions(manipulatedImage.Width, manipulatedImage.Height);
                displayedImage = manipulatedImage;


                progressIndicator.Report(new Tuple <int, int, string>(100, 100, "Displaying image..."));

                // The Save As... dialog in the file menu
                _model.FileMenuSaveAsEnabled    = true;
                _model.FileMenuTimelapseEnabled = true;

                // Show the thumbnail images looking towards linked panoramas
                if (!continueTimelapse)
                {
                    DisplayThumbnails(panoObject, image);
                }

                // Hide Progress Bar
                _model.ProgressBarVisibility = Visibility.Hidden;
            } catch (Exception e) {
                MessageBox.Show(e.Message + Environment.NewLine + e.InnerException, "An error occured downloading the image");
            }
        }