Клевый код

Вывести Silverlight Deep Zoom на следующий уровень

Джефф Просайз

Содержание

Исправление логики Panning элемента композитор
Доступ к Sub-Images и метаданные
Dynamic Deep Zoom: Supplying Image Pixels at Run Time
DeepZoomTools.dll

После глубокая масштаб Silverlight была введена в мире на конференции MIX 2008, окружающих его разговоров сохраняется для недель.Outgrowth Seadragon проекта в Microsoft Live Labs, глубокая масштаб является Silverlight адаптации технологии для представления огромных объемов управляющих данных пользователям в высокой пропускной способности эффективным способом.Sister процедур, предназначенных для Windows Mobile и AJAX доступны и служат для увеличения достижения платформы.

Если вы еще не видели глубокая масштаб перед, удалите вы выполняете и посетите каноническое узел глубокая масштаб memorabilia.hardrock.com.Сдвиг вокруг сцены и колесика мыши и уменьшение масштаба с помощью мыши.Благодаря для глубокая масштаб не необходимо загрузить гигабайт (или терабайт), imagery Обзор Café рок жесткого огромное memorabilia коллекции.Глубокий масштаб загружает только необходимые ему разрешением и в Silverlight точек, сложность глубокая масштаб маскируется за замечательные управления с именем MultiScaleImage.После того как глубокая масштаб сцены состоит (обычно с глубокая масштаб композитор, который можно загрузить бесплатно go.microsoft.com/fwlink/?LinkId=148861), представления сцены в обозревателе требует немного более объявление элемента управления MultiScaleImage и указывает свойство элемента управления источника вывода глубокая масштаб композитор элемента.Поддержка интерактивного panning и масштабирования требует немного мыши обработки кода, взаимодействующего с элементом управления, но эти дни, глубокая композитор масштаб будет даже предоставить.

Несмотря на простоту, с которой основное приложение глубокая масштаб может быть построен вы отсутствует out д true полнофункциональность глубокая масштаб дальнейшее, чем глубокая композитор масштаб осуществляется при переходе.Вы знали, например, можно программно управлять изображения в сцене глубокая масштаб, можно создавать метаданные и связать его с каждого изображения или что глубокая масштаб изображения можно поступают из базы данных или состоять на лету?Некоторые действительно поразительными глубокая масштаб приложения существует извлечение полагаться на возможность малоизвестных глубокая масштаб, который добавляет совершенно новое измерение платформы.

Если важно предпринять Silverlight глубокая масштаб для следующего уровня, здесь можно тремя способами делать это.

Исправление логики Panning элемента композитор

Все по порядку. Если требуется получить более вне глубокая масштаб, первое, что следует знать, это не следует доверять код обработки мыши, получится глубокая композитор масштаб.Код, pans вокруг сцены в ответ на события MouseMove «потере»мышь, если сдвиг слишком быстро.Попробуйте это.Возьмите любое приложение глубокая масштаб, созданные глубокая композитор масштаб и поместите указатель мыши на личную точку или точек в сцене.Затем переместите мышь быстро перемещаться вверх и вниз несколько раз.Обратите внимание, что при остановке и сцены springs к позиции курсора, курсор больше не находится в точке, она была при запуске.Дополнительные и быстрее перемещается, тем больше разницу.Не стоит a сделки средство разбиения по словам, но попробуйте же эксперимент узле Memorabilia рок жестких и вы обнаружите, что сцены надежно привязывается обратно к исходной позиции курсора независимо от того как жесткого попытке обмануть систему его.

Рисунок 1 показано, как изменить код глубокая масштаб композитор элемента, чтобы устранить проблему.Во-первых объявите два новых поля с именем lastViewportOrigin и lastMousePosition в классе страницы в Page.XAML.cs.(При работе в его удалите поля с именем dragOffset и currentPosition, поскольку они все не требуется.) Затем перепишите MouseLeftButtonDown и MouseMove обработчики, как показано.Вы обнаружите, что сцены привязывается обратно к точно исходной позиции курсора при остановить перемещение мыши, а если вы как fastidious меня о таких вещах, вы сможете спать по ночам еще раз.

Устранение кода Panning композитор глубокая масштаб на рисунке 1

Point lastViewportOrigin;
Point lastMousePosition;
  ...
this.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
{
    mouseButtonPressed = true;
    mouseIsDragging = false;
    lastViewportOrigin = msi.ViewportOrigin;
    lastMousePosition = e.GetPosition(msi);
};

this.MouseMove += delegate(object sender, MouseEventArgs e)
{
    if (mouseIsDragging)
    {
        Point pos = e.GetPosition(msi);
        Point origin = lastViewportOrigin;
        origin.X += (lastMousePosition.X - pos.X) /
            msi.ActualWidth * msi.ViewportWidth;
        origin.Y += (lastMousePosition.Y - pos.Y) /
            msi.ActualWidth * msi.ViewportWidth;
        msi.ViewportOrigin = lastViewportOrigin = origin;
        lastMousePosition = pos;
    }
};

Доступ к Sub-Images и метаданные

Возможно, вы заметили, что при экспорте в проект из глубокая композитор масштаб, вы предлагается выбора Экспорт как композиции или как коллекцию последний параметр поставляется с одним очень желательна преимуществ: Вместо экспорта глубокая масштаб сцены, содержащий все образы добавленные lumped вместе в один объединенный образ его экспортирует сцены, содержащий отдельно адресуемый sub-images. The sub-images предоставляются через свойство элемента управления MultiScaleImage SubImages и поскольку они являются отдельно адресуемый объектами sub-images можно управлять, анимированные и fumigated (просто kidding!) для добавления искра и интерактивность глубокая масштаб приложений.

Каждый элемент в коллекции SubImages является экземпляр MultiScaleSubImage, который является производным от DependencyObject и содержит свойства, AspectRatio, прозрачность, ZIndex, ViewportOrigin и ViewportWidth. Последний два объединить для определения размера и положения в сцене глубокая масштаб в sub образ. Следует помнить, что при первой загрузке элемент MultiScaleImage SubImages свойство пуст. Первая возможность перебора sub-images в том элементе управления событие его ImageOpenSucceeded.

Одно свойство SubImages используется для проверки нажатия отдельные изображения для отображения метаданных — заголовки, описания и так далее — в ответ на щелчок или mouseovers. Другой он используется для программно изменить порядок изображений в сцене глубокая масштаб. Приложение DeepZoomTravelDemo, показанное на рис. 2 демонстрируется выполните оба. Когда наведите указатель мыши на один изображений в сцене панели частично прозрачных сведения справа содержащий изображение заголовок и описание. И при нажатии кнопки случайном порядке, в верхнем левом углу изображения упорядочивание сами в произвольном порядке.

Рисунок 2 DeepZoomTravelDemo

Девять изображения, рекомендуемые DeepZoomTravelDemo, фотографии, я другие на некоторых моих overseas обращений. Я импортирован глубокая композитор масштаб, расположены в сетке и экспортировать сцены (делая установите «Экспорт как коллекции»). Затем я импортированные выходные данные из глубокая композитор масштаб в проект Silverlight и добавлены масштабирования и панорамирования логики аналогичны в предыдущем разделе. Чтобы сохранить размер загрузки управляемой (13 МБ или 170 МБ), БЫЛИ удалены нижней двух уровней пирамиды изображения, созданные перед передачей ЛИ приложение к коллекции кода MSDN композитор. Прекрасно работает с версией, загрузки, но при увеличении, изображения получить зернистыми существенно ускорить, чем в исходной версии.

Отображение метаданных изображения как DeepZoomTravelDemo представлены две проблемы для разработчика. Во-первых хранения метаданных и как его связать с изображениями в сцене? Во-вторых, как, сопоставления элементов в коллекции SubImages MultiScaleImage элемента управления с изображениями в сцене поскольку MultiScaleSubImage класс не предоставляет сведения о двух?

Первая задача — хранения метаданных — достигается путем ввода текстовой строки в поле тегов, отображаемое в нижнем правом углу глубокая композитор масштаб при выборе изображения. Я используется его для хранения название и описание, разделенных плюс каждого изображения. Композитор записывает теги в файл Metadata.xml создается при экспортировать в проект. Каждое изображение в сцене представляется <Image>элемент в Metadata.xml и каждого <Image>элемент содержит вложенный элемент с именем <Tag>содержащий соответствующий тег. на рис. 3 показано <Image> элемент, записанных в Metadata.xml для изображения в верхнем левом углу сцены. Тег элемента композитора интерфейс редактирования является довольно неловкий, поскольку поле тег является настолько мал, но можно всегда редактировать файл Metadata.xml вручную как я сделал тег заголовок и описание каждого изображения.

На рисунке 3 <Image> Элемент в Metadata.xml

<Image>
  <FileName>
    C:\Users\Jeff\Documents\Expression\Deep Zoom Composer
    Projects\DeepZoomTravelDemo\source images\great wall of china.png
  </FileName>
  <x>0</x>
  <y>0</y>
  <Width>0.316957210776545</Width>
  <Height>0.313807531380753</Height>
  <ZOrder>1</ZOrder>
  <Tag>
    Great Wall of China+The Great Wall of China near Badaling, about an hour
    north of Beijing. This portion of the Great Wall has been restored and
    offers outstanding views of the surrounding mountains.
  </Tag>
</Image>

Было бы хорошо, если класса MultiScaleSubImage имеет свойство Tag, который автоматически был инициализирован с содержимым <Tag> элемент;но он отсутствует, поэтому improvise. Во-первых можно написать немного кода, который загружает Metadata.xml и анализирует теги из него. Во-вторых можно использовать <ZOrder> элементы в Metadata.xml корреляции <Image> элементы с изображениями в сцене глубокая масштаб. Если сцены содержит девять изображения (и коллекции SubImages MultiScaleImage управления таким образом содержит девять объекты MultiScaleSubImage), SubImages [0] соответствует изображения которого <ZOrder> 1, SubImages[1] соответствует изображения которого <ZOrder>— 2 и т. д.

DeepZoomTravelDemo использует этот корреляции для хранения образа названиями и описаниями. При запуске конструктора страницы использует объект WebClient для запуска асинхронной загрузки Metadata.xml из папки ClientBin на сервер (см. рис. 4). После завершения загрузки WebClient_OpenReadCompleted метод анализирует загруженного XML с помощью XmlReader и инициализирует поле с именем _Metadata с массивом объектов SubImageInfo, содержащий сведения о изображений в сцене, включая названия и описания. Класс показан ниже:

public class SubImageInfo
{
    public string Caption { get; set; }
    public string Description { get; set; }
    public int Index { get; set; }
}

На рисунке 4 загрузка Metadata.xml и сопоставление метаданных с помощью Sub-Images

private SubImageInfo[] _Metadata;
  ...
public Page()
{
    InitializeComponent();

    // Register mousewheel event handler
    HtmlPage.Window.AttachEvent("DOMMouseScroll ", OnMouseWheelTurned);
    HtmlPage.Window.AttachEvent( "onmousewheel ", OnMouseWheelTurned);
    HtmlPage.Document.AttachEvent( "onmousewheel ", OnMouseWheelTurned);

    // Fetch Metadata.xml from the server
    WebClient wc = new WebClient();
    wc.OpenReadCompleted += new
        OpenReadCompletedEventHandler(WebClient_OpenReadCompleted);
    wc.OpenReadAsync(new Uri( "Metadata.xml ", UriKind.Relative));
}

private void WebClient_OpenReadCompleted(object sender,
    OpenReadCompletedEventArgs e)
{
    if (e.Error != null)
    {
        MessageBox.Show( "Unable to load XML metadata ");
        return;
    }

    // Create a collection of SubImageInfo objects from Metadata.xml
    List<SubImageInfo> images = new List<SubImageInfo>();

    try
    {
        XmlReader reader = XmlReader.Create(e.Result);
        SubImageInfo info = null;

        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element &&
                reader.Name ==  "Image ")
                info = new SubImageInfo();
            else if (reader.NodeType == XmlNodeType.Element &&
                reader.Name ==  "ZOrder ")
                info.Index = reader.ReadElementContentAsInt();
            else if (reader.NodeType == XmlNodeType.Element &&
                reader.Name ==  "Tag ")
            {
                string[] substrings =
                    reader.ReadElementContentAsString().Split('+');
                info.Caption = substrings[0];
                if (substrings.Length > 1)
                    info.Description = substrings[1];
                else
                    info.Description = String.Empty;
            }
            else if (reader.NodeType == XmlNodeType.EndElement &&
                reader.Name ==  "Image ")
                images.Add(info);
        }
    }
    catch (XmlException)
    {
        MessageBox.Show( "Error parsing XML metadata ");
    }

    // Populate the _Metadata array with ordered data
    _Metadata = new SubImageInfo[images.Count];

    foreach (SubImageInfo image in images)
        _Metadata[image.Index - 1] = image;
}

<ZOrder> чтение из Metadata.xml значения используются для заказа SubImageInfo объектов в массиве _Metadata, обеспечения идентичны в порядке из элементов в коллекции SubImages MultiScaleImage порядок элементов в массиве _Metadata. Другими словами _Metadata [0] содержит заголовок и описание SubImages [0], _Metadata [1] содержит заголовок и описание для SubImages [1] и т. д. Между прочим я использовал XmlReader вместо LINQ во избежание увеличения размера файла XAP путем введения дополнительных сборки, необходимые LINQ (System.Xml.Linq.dll).

Теперь, _Metadata инициализируется SubImageInfo объекты, содержащие названия и описания, следующим шагом является написание кода для отображения названия и описания. Это происходит в рис. 5. Обработчик MouseMove, pans отключен сцены глубокая масштаб, если кнопка мыши влево различается Если кнопки мыши влево подключен: он тесты нажатия сцены определить является ли курсор в данный момент над одним sub-images. Попадания осуществляется с именем GetSubImageIndex, возвращается значение -1, если курсор не через sub-image или индексом изображения на основе 0 в случае вспомогательный метод. Этот индекс определяет sub-image MutliScaleImage.SubImages в и в _Metadata SubImageInfo объект. Несколько строк кода копирует заголовок и описание из объекта SubImageInfo пару TextBlock и еще одна строка кода триггеров анимации, которая отображает панель информации, если оно еще не отображалось. Обратите внимание, GetSubImageIndex проверяет sub-images попаданий в обратном порядке с момента окончательного sub-image в коллекции SubImages MultiScaleimage управления максимальна в Z-порядком, sub-image следующего последнего второй является наивысшим в Z-порядок и т. д.

На рис. 5-попадания Sub-Images

private int _LastIndex = -1;
  ...
private void MSI_MouseMove(object sender, MouseEventArgs e)
{
    if (_Dragging)
    {
        // If the left mouse button is down, pan the Deep Zoom scene
          ...
    }
    else
    {
        // If the left mouse button isn't down, update the infobar
        if (_Metadata != null)
        {
            int index = GetSubImageIndex(e.GetPosition(MSI));

            if (index != _LastIndex)
            {
                _LastIndex = index;

                if (index != -1)
                {
                    Caption.Text = _Metadata[index].Caption;
                    Description.Text = _Metadata[index].Description;
                    FadeIn.Begin();
                }
                else
                {
                    FadeOut.Begin();
                }
            }
        }
    }
}

private int GetSubImageIndex(Point point)
{
    // Hit-test each sub-image in the MultiScaleImage control to determine
    // whether  "point " lies within a sub-image
    for (int i = MSI.SubImages.Count - 1; i >= 0; i--)
    {
        MultiScaleSubImage image = MSI.SubImages[i];
        double width = MSI.ActualWidth /
            (MSI.ViewportWidth * image.ViewportWidth);
        double height = MSI.ActualWidth /
            (MSI.ViewportWidth * image.ViewportWidth * image.AspectRatio);

        Point pos = MSI.LogicalToElementPoint(new Point(
            -image.ViewportOrigin.X / image.ViewportWidth,
            -image.ViewportOrigin.Y / image.ViewportWidth)
        );
        Rect rect = new Rect(pos.X, pos.Y, width, height);

        if (rect.Contains(point))
        {
            // Return the image index
            return i;
        }
    }

    // No corresponding sub-image
    return -1;
}

В дополнение к поддержке mouseovers DeepZoomTravelDemo позволяет упорядочить изображения в сцене. Если это еще не сделано, попробуйте кнопки случайном порядке, в верхнем левом углу сцены. (Фактически, щелкните его несколько раз;изображения считает другом порядке каждый раз.) Переупорядочение осуществляется в случайном порядке метод рис.6, который создает массив, содержащий все изображенияViewportOrigins, упорядочивает массива с помощью генератора случайных чисел и затем создается раскадровки и ряд PointAnimations перемещения sub-images в позиции, содержащиеся в упорядоченный массив. Ключ здесь является предоставляет свойство элемента управления MultiScaleimage SubImages sub-images в коде, и изменять свойство ViewportOrigin в sub образ для изменения его положения в сцене.

На рис. 6 Перетасовывание Sub-Images

private void Shuffle()
{
    // Create a randomly ordered list of sub-image viewport origins
    List<Point> origins = new List<Point>();

    foreach (MultiScaleSubImage image in MSI.SubImages)
        origins.Add(image.ViewportOrigin);

    Random rand = new Random();
    int count = origins.Count;

    for (int i = 0; i < count; i++)
    {
        Point origin = origins[i];
        origins.RemoveAt(i);
        origins.Insert(rand.Next(count), origin);
    }

    // Create a Storyboard and animations for shuffling
    Storyboard sb = new Storyboard();

    for (int i = 0; i < count; i++)
    {
        PointAnimation animation = new PointAnimation();
        animation.Duration = TimeSpan.FromMilliseconds(250);
        animation.To = origins[i];
        Storyboard.SetTarget(animation, MSI.SubImages[i]);
        Storyboard.SetTargetProperty(animation,
            new PropertyPath( "ViewportOrigin "));
        sb.Children.Add(animation);
    }

    // Run the animations
    sb.Begin();        
}

Как я researched этот столбец, я обнаружил несколько записей блога, полезные сведения.Один был Jaime Rodriquez «работа с коллекциями в глубокая масштаб.» Другой был "глубокая композитор масштаб — фильтрация пример тегов", которого сделана членом группы Expression Blend и представляет способ отбора глубокая масштаб изображения, основываясь на теги изображений.Реализация mouseovers упорядочивания изображений в сцене и фильтрации изображений, в зависимости от тега, данных, но несколько функций, возможно, возможность адрес отдельных sub-images глубокая масштаб сцены и сопоставить метаданных с ними.

Создание динамических глубокая масштаб четная лучше

Я был по fractals fascinated мечтал, поскольку я обнаружил их некоторые 20 лет назад.Если памяти служит мне правильно в начале 1990-х годов написал Мой первый просмотра Mandelbrot.Мои Книжная полка книг oldie но goodie компьютер по-прежнему содержит эталонный копию книги с названием фрактала сжатия изображений, Barnsley Hurd, используемый в проекте исследования на сжатие данных в mid 90s.И один из моих любимых книг все время является хаоса, Джеймс Gleick (пингвином, 2008).

Построение интерактивных и визуально привлекательные Mandelbrot является средство просмотра для обозревателей хотелось делать с момента первого дня, я определены глаза в Silverlight.Динамические глубокая масштаб писать.Недостатком, конечно, том, что изображения являются создается на сервере и загрузки клиент начальные нежелательных задержки и также увеличение нагрузки на сервер.

Silverlight 2 не включать API-ИНТЕРФЕЙС для создания точечных рисунков на клиентском компьютере, но можно создать их все равно кодировщик PNG Silverlight Джо Стегмэн.Minh Nguyen используются для построения обозреватель Mandelbrot, в котором можно прочесть о его в своей статье блог Minh T.1.0 Обозревателя Nguyen Mandelbrot в Silverlight 2.0 с источником кода . 3 Silverlight будет в бета-версии ознакомиться с этого времени имеет точечный рисунок API, но проблема остается, глубокая масштаб хочет по запросу изображения с сервера.Это непонятное в данный момент ли следующей версии глубокая масштаб будет иметь статьи со стороны клиента, но если он существует, вы можно поспорить, я вам содержимое MandelbrotDemo 3 Silverlight работать полностью на клиенте.

Динамические глубокая масштаб: Предоставление пикселы изображения во время выполнения

Функция экспорта глубокой масштаб композитор пользователя создает все данные, необходимые для управления MultiScaleImage.Что данные содержат XML-файл (dzc_output.xml), который ссылается на другие файлы XML, которые в свою очередь отдельных изображений в сцене.Вывод элемента композитора также включает сотни (иногда тысяч) фрагментов изображения, созданного из изображения.Фишки формы пирамиды изображения, с каждого уровня пирамиды, содержащий мозаичные версии исходного образа и каждого уровня, представляющий другое разрешение.Уровень в верхней части пирамиды, например, может содержать один участок с 256 x 256 преобразование изображения.Следующий уровень вниз будет содержать четыре 256 x 256 фишки, которые объединить формы 512 x 512 версию образа.Следующий уровень вниз будет содержать шестнадцать 256 x 256 плитки, представляющие различные части 1, x 1 024 024 изображение и т.д.Глубокий композитор масштаб создает столько уровней необходимости изображают исходное изображение в его собственного разрешения.Пользователю увеличивать масштаб отображения и является элемент управления MultiScaleImage pans в сцене глубокая масштаб постоянно срабатывание сеанс HTTP запросы серверу для выборки фрагментов изображения правильной разрешением.Также не некоторые ловко смешение работы сгладить переход от одного уровня на другой.

Что, вероятно не реализовать сведения об элементе управления MultiScaleImage является, не требует глубокая композитор масштаб.Композитор — лишь средство для быстро и легко создавать проекты глубокая масштаб, включающих сцены, построенного из статические изображения.В качестве альтернативы для обеспечения MultiScaleImage со статическим содержимым создания содержимого во время выполнения в ответ на запросы MultiScaleImage и загрузите содержимого на клиенте.

Почему бы никогда не нужно создавать глубокая масштаб содержимого во время выполнения?Разработчикам запрашивать, как это сделать все время. "Это позволяет предоставить данные изображения глубокая масштаб динамически?» Причина в том, что позволяет целый новый жанр глубокая масштаб приложений фрагментов изображения выборки из базы данных и создания фрагментов изображения на ходу.

Хотите пример?Извлечь проект глубокая земли и пример глубокая Земли с работы на deepearth.soulsolutions.com.au/.Глубокий земли, называется управления сопоставления, питаются комбинации платформы Silverlight 2 и управления DeepZoom (MultiScaleImage).Другими словами, это элемент управления можно перетащить в приложение Silverlight для предоставления огромное объем географических данных из Microsoft Virtual Earth доступны клиентскую глубокая масштаб.Начните outer места и масштаб всего вниз передней Садовое.И масштабирования невероятно Плавное благодаря трудозатрат за кулисами MultiScaleImage, среда выполнения глубокая масштаб.

Глубокий земли не определяется набор файлов XML и вывода фрагментов изображения, глубокая композитор масштаб;Предоставляет плитки изображение в элемент управления MultiScaleImage динамически, и извлекает фрагментов изображения из Virtual Earth.Пользователи глубокая земли называть это «динамический глубокая масштаб».

Приложения на рис. 7 демонстрируются основные принципы динамических глубокая масштаб.MandelbrotDemo предоставляет глубокая увеличить окно в наборе Mandelbrot — вероятно самый знаменитый фрактала в мире.Набор Mandelbrot является бесконечно сложным, которой означает, что можно увеличить ограничено и никогда не будет уменьшить уровень детализации.Mandelbrot просмотра общих в мире программного обеспечения, но некоторые как полезная, использующий глубокая масштаб.Попробуйте это;Запустите MandelbrotDemo и масштаба некоторые области swirling на границе Mandelbrot (на границы между черным и ярко-цвета).Вы не увеличение бесконечный даже динамического глубокая масштаб сцены имеет ограниченное ширину и высоту, но сцены элемента измерения может быть очень, очень большим (до 232 точек на одной стороне).

fig09a.gif

Два представления набора Mandlebrot

fig09b.gif

Первый шаг в реализации динамической глубокая масштаб является производными от класса MultiScaleTileSource Silverlight, который находится в пространстве имен System.Windows.Media System.Windows.dll, и переопределить метод GetTileLayers.Каждый раз, MultiScaleImage элемент управления должен мозаики, он вызывает GetTileLayers.Задание является создание Мозаичное изображение и вернуть его MultiScaleImage элемента управления путем добавления IList, переданный GetTileLayersсписок параметров.Другие параметры ввода GetTileLayers укажите уровень масштаба (буквально, уровень которого запрашиваются плитки пирамиды изображения) и X и Y положения внутри этого уровня пирамиды плитка запрашиваемой.Как значения X, Y и Z достаточны для определения точки в трехмерном пространстве координат, значение X, Y значение и уровнем, однозначно Мозаичное изображение в глубокая масштаб изображения пирамиды.

Рисунок 8 показан класс производный MultiScaleTileSource, рекомендуемые MandelbrotDemo.Переопределение GetTileLayers немного более Отправка запроса HTTP для фрагмента изображения на сервер.Конечная точка для запроса является обработчик HTTP, с именем MandelbrotImageGenerator.ashx.Перед изучения обработчик, однако посмотрим как проводной MandelbrotTileSource до элемента управления MultiScaleImage.

Производная MultiScaleTileSource на рис. 8

public class MandelbrotTileSource : MultiScaleTileSource
{
    private int _width;  // Tile width
    private int _height; // Tile height

    public MandelbrotTileSource(int imageWidth, int imageHeight,
        int tileWidth, int tileHeight) :
        base(imageWidth, imageHeight, tileWidth, tileHeight, 0)
    {
        _width = tileWidth;
        _height = tileHeight;
    }

    protected override void GetTileLayers(int level, int posx, int posy,
        IList<object> sources)
    {
        string source = string.Format(
             "http://localhost:50216/MandelbrotImageGenerator.ashx? " +
             "level={0}&x={1}&y={2}&width={3}&height={4} ",
            level, posx, posy, _width, _height);

        sources.Add(new Uri(source, UriKind.Absolute));
    }
}

на рис. 9 показан отрывок из файл Page.XAML.cs MandelbrotDemo — в частности, конструктор класса фонового кода XAML. Инструкция ключа является, который создает MandelbrotTileSource объект и присваивается свойству источника элемента управления MultiScaleImage ссылку на него. Для статических глубокая масштаб следует установить исходный URI dzc_output.xml. Динамические глубокая масштаб можно указывать его объекту MultiScaleTileSource вместо. MandelbrotTileSource объект, созданный здесь указывает, что изображение обслуживаемых 230 точек на каждой стороне и разделена плитки 128 x 128 пикселов.

На рисунке 9 регистрации глубокий масштаб исходного рядом

public Page()
{
    InitializeComponent();

    // Point MultiScaleImage control to dynamic tile source
    MSI.Source = new MandelbrotTileSource((int)Math.Pow(2, 30),
        (int)Math.Pow(2, 30), 128, 128);

    // Register mousewheel event handler
    HtmlPage.Window.AttachEvent( "DOMMouseScroll ", OnMouseWheelTurned);
    HtmlPage.Window.AttachEvent( "onmousewheel ", OnMouseWheelTurned);
    HtmlPage.Document.AttachEvent( "onmousewheel ", OnMouseWheelTurned);
}

Работа создания фрагментов изображения выполняется по MandelbrotImageGenerator.ashx на сервере (см. рис. 10). После извлечения входных параметров из строки запроса, она создает точечный рисунок показывает запрошенный плитка и записывает биты изображения в HTTP-ответа. DrawMandelbrotTile не создания точек. При вызове, он преобразует значение X, Y, уровня, идентифицирующее плитка изображение было запрошенной в координатах плоскости сложных (математических плоскости, в котором действительных чисел graphed вдоль оси и мнимые номера X — числа, включить квадратный корень-1 — graphed по оси Y). Затем он итерацию всех точек плоскости сложных, соответствуют точкам Мозаичное изображение, проверка каждой точки, чтобы определить, принадлежит ли он к Mandelbrot набора и назначения соответствующей точки цвет, представляющий его отношение к Mandelbrot набора (Подробнее об этом чуть).

На рис. 10 обработчика HTTP для создания глубокий масштаб изображения рядом

public class MandelbrotImageGenerator : IHttpHandler
{
    private const int _max = 128;     // Maximum number of iterations
    private const double _escape = 4; // Escape value squared

    public void ProcessRequest(HttpContext context)
    {
        // Grab input parameters
        int level = Int32.Parse(context.Request[ "level "]);
        int x = Int32.Parse(context.Request[ "x "]);
        int y = Int32.Parse(context.Request[ "y "]);
        int width = Int32.Parse(context.Request[ "width "]);
        int height = Int32.Parse(context.Request[ "height "]);

        // Generate the bitmap
        Bitmap bitmap = DrawMandelbrotTile(level, x, y, width, height);

        // Set the response's content type to image/jpeg
        context.Response.ContentType =  "image/jpeg ";

        // Write the image to the HTTP response
        bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);

        // Clean up and return
        bitmap.Dispose ();
    }

    public bool IsReusable
    {
        get { return true; }
    }

    private Bitmap DrawMandelbrotTile(int level, int posx, int posy,
        int width, int height)
    {
        // Create a bitmap to represent the requested tile
        Bitmap tile = new Bitmap(width, height);

        // Compute the number of tiles in each direction at this level
        int cx = Math.Max(1, (int)Math.Pow(2, level) / width);
        int cy = Math.Max(1, (int)Math.Pow(2, level) / height);

        // Compute starting values for real and imaginary components
        // (from -2.0 - 1.5i  to 1.0 + 1.5i)
        double r0 = -2.0 + (3.0 * posx / cx);
        double i0 = -1.5 + (3.0 * posy / cy);

        // Compute increments for real and imaginary components
        double dr = (3.0 / cx) / (width - 1);
        double di = (3.0 / cy) / (height - 1);

        // Iterate by row and column checking each pixel for
        // inclusion in the Mandelbrot set
        for (int x = 0; x < width; x++)
        {
            double cr = r0 + (x * dr);

            for (int y = 0; y < height; y++)
            {
                double ci = i0 + (y * di);
                double zr = cr;
                double zi = ci;
                int count = 0;

                while (count < _max)
                {
                    double zr2 = zr * zr;
                    double zi2 = zi * zi;

                    if (zr2 + zi2 > _escape)
                    {
                        tile.SetPixel(x, y,
                            ColorMapper.GetColor(count, _max));
                        break;
                    }

                    zi = ci + (2.0 * zr * zi);
                    zr = cr + zr2 - zi2;
                    count++;
                }

                if (count == _max)
                    tile.SetPixel(x, y, Color.Black);
            }
        }

        // Return the bitmap
        return tile;
    }
}

К сожалению является практически не документации на класс MultiScaleTileSource Silverlight. Перечислите предполагается, что я genius для расчета всех это out (любой знает мне будет подтверждающим, я не), позвольте мне дать кредит где оплаты кредит. Как я wrestled с понятие входные параметры и способы сопоставления значений глубокая масштаб X-Y-уровень плоскости сложной, я нашел отлично блога, Ormond Майк и глубокая масштаб, MultiScaleTileSource Mandelbrot SET. Его учет предоставляются ключа советам в динамических глубокая масштаб и также ссылка другого блога, The Mandelbrot SET, описывающий эффективный подход для вычисления набора Mandelbrot. Моей работы было возможно halved по трудозатрат другие до меня.

Один конечный примечание в моей реализации: практически каждое приложение, отображающий набора Mandelbrot использует другую цветовую схему. Я выбрал схему, которая назначает представляющих координаты, принадлежащих Mandelbrot точек задать черного и представляющих координаты вне Mandelbrot точек задавать цвета RGB. Дальнейшей координат располагается из набора Mandelbrot "охладитель"или bluer цвет;ближе располагается в набор Mandelbrot "hotter"цвет. Расстояние от набора Mandelbrot определяется как быстро экранирует точки до бесконечности. В коде ниже, это число итераций занимает DrawMandelbrotTile во время цикла определить, что точка не является частью набора Mandelbrot. Меньше итерации, дальнейшей точку, лежит из набора точек, составляющих набор Mandelbrot. Я разложить код, который создает значение цвета RGB из число итераций в отдельный класс с именем ColorMapper (рис. 11). Если хотите поэкспериментировать с различных цветовых схем, просто измените метод GetColor. Чтобы увидеть результаты отрисовки серого, выполнив следующие:

int val  = (count * 255) / max;
return Color.FromArgb(val, val, val);

Класс ColorMapper на рис. 11

public class ColorMapper
{
    public static Color GetColor(int count, int max)
    {
        int h = max >> 1; // Divide max by 2
        int q = max >> 2; // Divide max by 4

        int r = (count * 255) / max;
        int g = ((count % h) * 255) / h;
        int b = ((count % q) * 255) / q;

        return Color.FromArgb(r, g, b);
    }
}

DeepZoomTools.dll

Окончательный tidbit сведения, касающиеся глубокая масштаб, могут оказаться полезными включает сборку с именем DeepZoomTools.dll. Глубокий композитор масштаб использует эту сборку для создания мозаичные изображения и метаданные из сцены при построении. В теории можно использовать для создания собственных средств композиции. Сказать «теоретически»так как ценное немного извлечение существует в терминах документации. Узнать больше о DeepZoomTools.dll в блоге Expression Blend и разработка. И прокрутить мне сообщение электронной почты, если придумать некоторые использует уникальный, творческих для глубокая масштаб, но непонятно довольно как сделать ее следует, что нужно сделать.

Направляйте свои вопросы и комментарии Джеффу по адресу wicked@microsoft.com.

Джефф Просайз является пишущим редактором журнала MSDN Magazine и автор несколько книг, включая программирования Microsoft .NET (Microsoft Press, 2002). Кроме того, он является соучредителем компании Wintellect (www.wintellect.com), оказывающей консультационные и образовательные услуги в области программного обеспечения и специализирующейся на Microsoft .NET. У вас появились замечания? С Джеффом можно связаться по адресу wicked@microsoft.com.