Compartir a través de


Este artículo proviene de un motor de traducción automática.

Código malvado

Tomar Silverlight Deep Zoom para el siguiente nivel

Jeff Prosise

Contenido

Corrección panorámica lógica del compositor
Acceso a Sub-Images y metadatos
Deep Zoom] dinámico: Proporcionar píxeles de imagen en tiempo de ejecución
DeepZoomTools.dll

Después de que Silverlight Deep Zoom se introdujo en el mundo en MIX 2008, los rumores se conservan durante semanas.Un outgrowth del proyecto Seadragon enLaboratorios de Microsoft LiveDeep Zoom es una adaptación de Silverlight de una tecnología para presentar grandes cantidades de datos gráficos a los usuarios de una manera muy eficaz ancho de banda.Las adaptaciones sister destinadas a Windows Mobile y AJAX están disponibles y sirven para aumentar el alcance de la plataforma.

Si no ha visto Deep Zoom antes, quite lo que estás haciendo y visite el sitio de Deep Zoom canónico en memorabilia.hardrock.com.Utilice el mouse para recorrer en la escena y la rueda del mouse para acercar y alejar.Gracias a Deep Zoom, no tienes que descargar gigabytes (o terabytes) de imágenes memorabilia amplia colección del Café Rock duro de examinar.Deep Zoom descarga sólo los píxeles que necesita en la resolución que necesita y en Silverlight, la complejidad de Deep Zoom es enmascarada detrás de un control notables denominado MultiScaleImage.Una vez (normalmente con Deep Zoom Composer, que puede descargar gratuitamente desde go.microsoft.com/fwlink/?LinkId=148861) se compone una escena de Deep Zoom, presentar la escena en un explorador requiere poco más de declarar un control MultiScaleImage y que señala la propiedad origen del control a resultado del Deep Zoom Composer.Admitir interactivo de panorámica y zoom, requiere un poco código de control del mouse (ratón) que interactúe con el control, pero estos días que Deep Zoom Composer incluso proporcionará que para.

A pesar de la facilidad con que se puede generar una aplicación de Deep Zoom básica, está falta out en la riqueza de Deep Zoom es true si va a no más de Deep Zoom Composer le.¿Sabía, por ejemplo, que puede manipular mediante programación las imágenes en una escena de Deep Zoom, que puede crear metadatos y asociar a cada imagen, o que las imágenes de Deep Zoom pueden proceder de una base de datos o estar compuesto sobre la marcha?Algunos de las realmente notables Deep Zoom aplicaciones ahí se basan en una característica poco conocida de Deep Zoom que agrega una totalmente nueva dimensión a la plataforma.

Si ocupa llevar Silverlight Deep Zoom al nivel siguiente, éstas son tres formas de hacerlo.

Corrección panorámica lógica del compositor

Primeras cosas primera: si desea obtener más provecho de Deep Zoom, lo primero que debe saber es no debe confiar en el código de control de mouse emitido por Deep Zoom Composer.El código que gira alrededor de la escena en respuesta a eventos MouseMove "pierde" el mouse si panorámica demasiado rápidamente.Pruébelo.Tomar cualquier aplicación de Deep Zoom creada por Deep Zoom Composer y coloque el cursor del mouse (ratón) sobre un punto de identificación o un píxel en la escena.A continuación, mueva el mouse rápidamente hacia delante y hacia atrás hacia arriba y hacia abajo varias veces.Observe que cuando se detiene y la escena resortes a la posición del cursor, el cursor ya no se encuentra en el punto que estaba cuando se inició.Más y más rápido mover, mayor será la diferencia.No lo un trato es separador, pero intente el experimento mismo en el sitio de Rock duro Memorabilia y encontrará que la escena se confiable ajusta volver a la posición del cursor original independientemente de cómo duro intenta engañar.

figura 1 muestra cómo modificar código del Deep Zoom Composer para corregir el problema.En primer lugar, declare dos nuevos campos denominados lastViewportOrigin y lastMousePosition en la clase Page Page.XAML.cs.(Mientras lo está, eliminar los campos denominados dragOffset y currentPosition, porque no se necesitan.) A continuación, vuelva a escribir los controladores MouseLeftButtonDown y MouseMove tal como se muestra.Encontrará que se la escena ajusta volver a con precisión la posición del cursor original cuando deja de mover el mouse (ratón) y, si estás como fastidious como estoy acerca de estas cosas, no podrá suspensión por la noche una vez más.

Figura 1 solucionar código de panorámica del Deep Zoom Composer

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;
    }
};

Acceso a Sub-Images y metadatos

Es posible que haya observado que al exportar un proyecto de Deep Zoom Composer, está ofrecen la posibilidad de exportar como una composición o como una colección con la opción última viene con una ventaja muy deseable: en lugar de exportar una escena de Deep Zoom que contiene todas las imágenes que agregó mezcladas juntos en una imagen monolítica, que exporta una escena que contiene sub-images individualmente direccionables.Los sub-images se exponen a través la MultiScaleImage propiedad del control SubImages y porque son objetos individualmente direccionables al, los sub-images pueden manipularse, animación y fumigated (sólo kidding) para agregar chispeante e interactividad a las aplicaciones de Deep Zoom.

Cada elemento de la colección SubImages es una instancia de MultiScaleSubImage, que se deriva de DependencyObject y que incluye las propiedades AspectRatio, opacidad, ZIndex, ViewportOrigin y ViewportWidth.Los últimos dos combinan para determinar de una sub-imagen tamaño y posición en una escena de Deep Zoom.Tenga en cuenta que cuando un control MultiScaleImage carga por primera vez, su propiedad SubImages es vacía.La primera oportunidad de recorrer en iteración los sub-images es cuando el control desencadena su evento ImageOpenSucceeded.

Un uso de la propiedad SubImages es a prueba de detección imágenes individuales para mostrar los metadatos, títulos, descripciones etc., en respuesta a clics o mouseovers.Otro uso para él es mediante programación reorganizar las imágenes en una escena de Deep Zoom.La aplicación de DeepZoomTravelDemo que se muestra en la figura 2 muestra cómo realizar ambos procedimientos.Cuando coloque el mouse sobre uno de las imágenes en la escena, un panel de información parcialmente transparente aparece en la derecha que contiene un título de la imagen y una descripción.Y al hacer clic en el botón orden aleatorio en la esquina superior izquierda, las imágenes propias reorganizar en orden aleatorio.

fig02.gif

Figura 2 DeepZoomTravelDemo

Las imágenes de nueve destacadas en DeepZoomTravelDemo son fotos que ajusta en algunas de Mis viajes extranjeros.Importan ellos Deep Zoom Composer, organizó en una cuadrícula y exporta la escena (asegurándose de seleccionar "Exportar como colección").A continuación, importar el resultado de Deep Zoom Composer en un proyecto de Silverlight y agrega lógica de zoom y panorámica similar a la en la sección anterior.Para mantener el tamaño de descarga manejable (13 MB frente a 170 MB), he eliminado a las parte inferior de dos capas de la pirámide de imágenes que Composer generado antes de que cargará la aplicación en MSDN Code Gallery.La versión que descargue funciona perfectamente, pero cuando hace zoom, las imágenes obtienen granuladas mucho más rápido que en la versión original.

Mostrar metadatos de imagen como DeepZoomTravelDemo presenta dos desafíos para el desarrollador.En primer lugar, ¿dónde almacenan los metadatos, y cómo asociarlo con imágenes en la escena?¿Segundo, cómo que correlacionar los elementos de la MultiScaleImage colección del control SubImages con imágenes en la escena puesto que la clase MultiScaleSubImage no proporciona información relacionada con los dos?

La primera tarea, almacenar los metadatos, se consigue al escribir una cadena de texto en el cuadro de etiqueta que se muestra en la esquina inferior derecha de Deep Zoom Composer cuando se selecciona una imagen.Lo he usado para almacenar cada imagen título y descripción, separados por signos más.Compositor escribe las etiquetas en el archivo de Metadata.xml creado cuando exporta el proyecto.Cada imagen en la escena se representa mediante un elemento <Image> Metadata.xml y cada elemento <Image> contiene un denominado <Tag> subelemento que contiene la etiqueta correspondiente.figura 3 muestra el elemento de <image> escrito en Metadata.xml para la imagen en la esquina superior izquierda de la escena.Etiqueta de compositor edición interfaz es un poco torpe ya que el cuadro etiqueta es tan pequeño, pero puede siempre modificar el archivo Metadata.xml manualmente como hice para etiquetar cada imagen con un título y una descripción.

Figura 3 un elemento <image> en Metadata.xml

<Image>
  <FileName>
    C:\Users\Jeff\Documents\Expression\Deep Zoom Composer
    Projects\DeepZoomTravelDemo\source images\great wall of china.jpg
  </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>

Sería estupendo si la clase MultiScaleSubImage tuviera una propiedad de etiqueta que se inicializa automáticamente con el contenido del elemento <tag>; pero no es así, por lo que tiene que improvise. En primer lugar, puede escribir un fragmento de código que descarga Metadata.xml y analiza las etiquetas de él. En segundo lugar, puede utilizar los elementos de <zorder> Metadata.xml para correlacionar los elementos de <image> con imágenes en la escena de Deep Zoom. Si la escena contiene nueve imágenes (y por lo tanto la MultiScaleImage colección del control SubImages contiene nueve objetos MultiScaleSubImage), SubImages [0] corresponde a la imagen cuyo <ZOrder> es 1, SubImages [1] corresponde a la imagen cuyo <ZOrder> es 2 y así sucesivamente.

DeepZoomTravelDemo utiliza esta correlación para almacenar la imagen títulos y descripciones. En el inicio, el constructor de página utiliza un objeto de WebClient para iniciar una descarga asincrónica de Metadata.xml de la carpeta del servidor ClientBin (consulte la figura 4 ). Una vez finalizada la descarga, el método de WebClient_OpenReadCompleted analiza el XML con XmlReader descargado e inicializa el campo denominado _Metadata con una matriz de objetos de SubImageInfo que contiene información acerca de las imágenes de la escena, incluidos los títulos y descripciones. La clase se muestra aquí:

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

Figura 4 descarga Metadata.xml y Correlating metadatos con 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;
}

Los valores de <zorder> leen Metadata.xml se utilizan para ordenar los objetos SubImageInfo en la matriz _Metadata, asegurarse de que el orden de los elementos de la matriz _Metadata es idéntico al orden de los elementos de colección de SubImages del MultiScaleImage. En otras palabras, _Metadata [0] contiene el título y la descripción de SubImages [0], _Metadata [1] contiene el título y la descripción de SubImages [1] y así sucesivamente. Por cierto, he usado XmlReader en lugar de LINQ to XML para evitar aumentar el tamaño de al archivo XAP introduciendo un ensamblado adicional requerido por LINQ to XML (System.Xml.Linq.dll).

Ahora que se inicializa _Metadata con SubImageInfo objetos que contiene los títulos y descripciones, el siguiente paso es escribir el código para mostrar los títulos y descripciones. Eso sucede en la figura 5 . El controlador de MouseMove que gira la escena de Deep Zoom, si el botón primario del mouse está abajo se comporta de diferente si el botón primario hasta: las pruebas de posicionamiento la escena para saber si el cursor está sobre uno de los sub-images. El método auxiliar denominado GetSubImageIndex, que devuelve -1 si no está el cursor sobre un sub-image o un índice de imagen basada en 0 si se realiza las pruebas de posicionamiento. Ese índice identifica tanto un sub-image en MutliScaleImage.SubImages y un objeto SubImageInfo en _Metadata. Unas pocas líneas de código copia el título y descripción del objeto SubImageInfo a un par de TextBlocks y una línea de código de desencadenadores más una animación que muestra el panel de información si ya no se muestra. Observe que comprueba GetSubImageIndex si sub-images para visitas en orden inverso desde el final sub-image de SubImages colección del control MultiScaleimage es mayor en el orden Z, el sub-image siguiente al último segundo es mayor en el orden Z y así sucesivamente.

Figura 5 comprobar visitas las 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;
}

Además para admitir mouseovers, DeepZoomTravelDemo le permite reorganizar las imágenes en la escena. Si no lo ha hecho ya, intente haciendo clic en el botón orden aleatorio en la esquina superior izquierda de la escena. (De hecho, haga clic en él varias veces; las imágenes supondrá un orden diferente cada vez). La reorganización se realiza mediante el método de orden aleatorio en la figura 6 , que crea una matriz que contiene ViewportOrigins todas las imágenes, reordena la matriz mediante un generador de números aleatorios y, a continuación, crea un guión gráfico y una serie de PointAnimations para mover los sub-images a las posiciones de la matriz reordenada. La clave aquí es que la MultiScaleimage propiedad del control SubImages expone sub-images al código, y puede modificar ViewportOrigin propiedad de una sub-imagen para cambiar su posición en la escena.

Figura 6 barajando los 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();        
}

Como había investigado esta columna, encontré varias entradas de blog que proporcionan información útil.Uno era Jaime Rodriquez"Trabajar con colecciones en Deep Zoom]." Otro fue"Deep Zoom Composer, filtrado por ejemplo de etiqueta", que fue escrito por un miembro de los equipo de Expression Blend y presenta una técnica para filtrar las imágenes de Deep Zoom se basa en las etiquetas de imagen.Implementación mouseovers, reorganizar las imágenes en una escena y filtrado de imágenes basadas en la etiqueta de datos son pero algunas de las características posible gracias a la capacidad para tratar las sub-images individuales en un Deep Zoom escena y asociar metadatos con ellos.

Hacer Zoom Deep dinámica mejor par

he sido fascinated por fractal desde que descubren hace algunos años 20.Escribí mi primera Visor Mandelbrot en principios de los noventa, si la memoria sirve me correctamente.Mi estante de libros de libros de informática oldie-pero-goodie todavía contiene una copia original de un libro titulado compresión de imágenes de Fractal Barnsley y Hurd utilizados en un proyecto de investigación en compresión de datos en mid-años 90.Y uno de mis libros favoritos de todo el tiempo es Chaos por James Gleick (pingüino, 2008).

Generar un interactivo y visualmente atractivas Mandelbrot Visor para exploradores es algo que ha quería hacer desde el primer día que colocan los ojos en Silverlight.Dinámico Deep Zoom hizo posible.Por supuesto, la desventaja es que las imágenes se generan en el servidor y se descarga al cliente, iniciales a la latencia no deseado y también aumentar la carga en el servidor.

Silverlight 2 no incluye una API para generar mapas de bits en el cliente, pero puede generar a través de todos modosCodificador de PNG de Silverlight de Joe Stegman. Minh Nguyen utiliza lo para generar Mandelbrot explorador, que puede leer todo sobre ella en su artículo blog"T. MinhMandelbrot Explorer 1.0 del Nguyen de Silverlight 2.0 con código fuente." 3 De Silverlight, que estará en beta en el momento en que leer esto, tiene un mapa de bits API, pero el problema permanece que Deep Zoom desea extraer imágenes del servidor.Es poco claro en el momento si la versión siguiente de Deep Zoom tiene un artículo de cliente, pero si lo hace, seguro que va ser revisar MandelbrotDemo para 3 de Silverlight funcionar completamente en el cliente.

Deep Zoom] dinámico: Proporcionar píxeles de imagen en tiempo de ejecución

Característica de exportación del Deep Zoom Composer genera todos los datos necesarios por un control MultiScaleImage.Los datos incluyen un archivo XML (dzc_output.xml) que hace referencia a otros archivos XML, que a su vez hacen referencia las imágenes individuales en la escena.Salida del compositor también incluye cientos (a veces miles) de mosaicos de imagen generados a partir de esas imágenes.Los mosaicos forman una pirámide de imágenes, con cada nivel de la pirámide que contiene una versión en mosaico de la imagen original y cada nivel que representa una resolución diferente.El nivel en la parte superior de la pirámide, por ejemplo, podría contener un único mosaico con una interpretación de 256 x 256 de la imagen.El siguiente nivel hacia abajo contendría cuatro 256 x 256 mosaicos que reunir una versión de 512 x 512 de la imagen del formulario.El siguiente nivel hacia abajo contendría dieciséis 256 x 256 mosaicos que representa distintas partes de un 1. 024 x 1, 024 imagen y así sucesivamente.Deep Zoom Composer genera tantos niveles como sea necesario para describir la imagen original en su resolución nativa.Como un usuario zooms y moldes en una escena de Deep Zoom, el control MultiScaleImage es constantemente activar HTTP solicitudes al servidor para recuperar los mosaicos de imagen con la resolución correcta.También realiza algunas ingenioso mezcla trabajo para suavizar la transición de un nivel a otro.

Lo que probablemente no observa sobre el control MultiScaleImage es que no requiere Deep Zoom Composer.Compositor es simplemente una herramienta de creación de rápida y fácilmente proyectos de Deep Zoom que incorporan plano generado a partir de imágenes estáticas.Como alternativa a proporcionar MultiScaleImage con contenido estático, puede generar el contenido en tiempo de ejecución en respuesta a solicitudes de MultiScaleImage y descargar dicho contenido en el cliente.

¿Por qué sería nunca necesita generar Deep Zoom contenido en tiempo de ejecución?Los desarrolladores preguntar cómo hacerlo todo el tiempo. "Es posible proporcionar datos de imagen para Deep Zoom dinámicamente?" La razón es que permite un género totalmente nuevo de aplicaciones de Deep Zoom que mosaicos de imagen de recuperación de bases de datos y generen mosaicos de imagen sobre la marcha.

¿Desea un ejemplo?Desproteger elProyecto profunda de tierray un ejemplo de la Tierra detallado en el trabajo endeepearth.soulsolutions.com.au/ . Tierra profunda se conoce como un control de asignación con la combinación de la plataforma de Microsoft Silverlight 2 y el control DeepZoom (MultiScaleImage).En otras palabras, se trata de un control puede colocar en una aplicación de Silverlight para exponer la gran cantidad de datos geográficos disponibles de Microsoft Virtual Earth a través de un front-end Deep Zoom.Puede iniciar en espacio exterior y zoom completamente hacia abajo a su jardín frontal.Y el zoom es increíblemente suave, gracias al trabajo realizado entre bastidores por MultiScaleImage y el tiempo de ejecución Deep Zoom.

Tierra Deep no está controlada por una serie de archivos XML y de salida de mosaicos de imagen de Deep Zoom Composer; proporciona mosaicos de imagen al control MultiScaleImage dinámicamente y recupera los mosaicos de imagen de Virtual Earth.Los usuarios de la Tierra Deep se refieren a esto como "dinámico de Deep Zoom."

La aplicación muestra en la figura 7 muestra los fundamentos de Deep Zoom dinámico.MandelbrotDemo proporciona una ventana de Deep Zoom en el conjunto de Mandelbrot, probablemente el fractal más famoso del mundo.El conjunto de Mandelbrot es infinitamente complejo, lo que significa que puede acercar indefinidamente y nunca se reducirá el nivel de detalle.Visores de Mandelbrot son comunes en el mundo de software, pero pocas son como ingenioso que utiliza Deep Zoom.Pruébelo; ejecute MandelbrotDemo y acercar algunas de las regiones remolinos en el borde de la Mandelbrot establecer (en el límite entre los colores brillantes y negros).No puede hacer zoom indefinidamente porque incluso una escena de Deep Zoom dinámica tiene un alto y ancho finito, pero dimensiones de la escena puede ser muy grande (hasta 232 píxeles por lado).

fig09a.gif

dos vistas de conjunto de Mandlebrot

fig09b.gif

El primer paso para implementar dinámico Deep Zoom es derivar MultiScaleTileSource clase de Silverlight, que se encuentra en el espacio de nombres de System.Windows.Media de System.Windows.dll, y reemplazar el método GetTileLayers.Cada vez que el control MultiScaleImage necesita un mosaico, llama a GetTileLayers.Su trabajo es crear un mosaico de imagen y devolverlo al control MultiScaleImage agregándolo a IList pasado en la lista de parámetros de GetTileLayers.Otros parámetros de entrada a GetTileLayers especifican el nivel de zoom (literalmente, el nivel de la pirámide de imágenes desde el que se están solicita mosaicos) y la posición dentro de ese nivel de la pirámide X e Y del mosaico se solicita.Como valores X, Y y Z son suficientes para identificar un punto en el espacio de coordenadas 3D, un valor de X, un valor de Y y un nivel, identifican un mosaico de imagen en una pirámide de imágenes de Deep Zoom.

la figura 8 muestra la clase derivada MultiScaleTileSource destacada en MandelbrotDemo.El reemplazo de GetTileLayers enviar algo más de una solicitud HTTP para el mosaico de imagen al servidor.El extremo de la solicitud es un controlador HTTP denominado MandelbrotImageGenerator.ashx.Sin antes de que examinamos el controlador, embargo, vamos a ver cómo se conecta MandelbrotTileSource hasta un control MultiScaleImage.

Figura 8 MultiScaleTileSource Derivative

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));
    }
}

figura 9 muestra un extracto del archivo Page.XAML.cs del MandelbrotDemo, específicamente, el XAML code-behind del constructor de clase. La instrucción clave es el que crea un objeto MandelbrotTileSource y asigna una referencia a él a la propiedad origen del control MultiScaleImage. Para estático Deep Zoom, se establece el origen en el URI de dzc_output.xml. Para dinámico Deep Zoom, elija es un objeto MultiScaleTileSource en su lugar. El objeto de MandelbrotTileSource creado aquí se especifica que la imagen que se sirve 230 píxeles en cada lado y se divide en mosaicos de 128 x 128 píxeles.

Figura 9 registrar una profundidad consulta origen mosaico

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);
}

El trabajo de generación de los mosaicos de imagen se realiza por MandelbrotImageGenerator.ashx volver en el servidor (consulte la figura 10 ). Después de recuperar los parámetros de entrada de la cadena de consulta, se crea un mapa de bits que representa gráficamente el mosaico solicitado y se escribe los bits de imagen en la respuesta HTTP. DrawMandelbrotTile realiza la generación de píxel. Cuando llama a, convierte el valor de X-Y-nivel que identifica el mosaico de imagen que se solicitó en las coordenadas en el plano de complejo (un plano matemático en la que representar gráficamente los números reales junto a los números de eje y imaginario de X, los números que incorporan la raíz cuadrada de -1, se representar gráficamente en el eje Y). A continuación, recorre en iteración todos los puntos en el plano complejo que corresponden a píxeles en el mosaico de imagen, compruebe cada punto de determinar si pertenece a la Mandelbrot establecido y asignar el píxel correspondiente a un color que representa la relación a la Mandelbrot configurado (en un momento más información sobre este aspecto).

Figura 10 controladores de HTTP para generar Deep Zoom mosaicos de imagen

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;
    }
}

Por desgracia, no hay prácticamente ninguna documentación sobre MultiScaleTileSource clase de Silverlight. Menos piensa soy un genius para calcular todo esta salida (cualquiera que me sepa se afirme que no estoy), voy a dar crédito donde crédito es vencimiento. Como wrestled con el significado de los parámetros de entrada y de cómo asignar valores de Deep Zoom X-Y-nivel al plano de complejo, encontré una entrada de blog excelente por Mike Ormond, Deep Zoom, MultiScaleTileSource y establecer Mandelbrot. Su posterior proporciona clave investigar dinámico Deep Zoom y también hace referencia a otra entrada de blog, El conjunto de Mandelbrot, que describe un enfoque eficaz para calcular el conjunto de Mandelbrot. Probablemente se halved mi trabajo por trabajo otros tenían antes de mí.

Una nota final sobre mi implementación: prácticamente todas las aplicaciones que representa el conjunto de Mandelbrot utilizan una combinación de colores diferente. Se ha elegido un esquema que asigna los píxeles que representa las coordenadas de la Mandelbrot establezca negro y píxeles que representa las coordenadas fuera la Mandelbrot colores RGB. El más una coordenada reside desde el conjunto de Mandelbrot, el "refrigerador" o bluer el color; cuanto más cerca se encuentra en el conjunto de Mandelbrot, el "hotter" el color. Distancia desde el conjunto de Mandelbrot viene determinado por cómo rápidamente el punto de escapa a infinito. En el código, es el número de iteraciones tarda DrawMandelbrotTile bucle para determinar el punto no es parte del conjunto Mandelbrot while. Las menos las iteraciones, más el el punto queda del conjunto de puntos que componen el conjunto de Mandelbrot. Calcula el código que genera un valor de color RGB desde el número de iteraciones en una clase independiente denominado ColorMapper ( figura 11 ). Si desea experimentar con combinaciones de colores diferentes, simplemente modificar el método GetColor. Puede ver los resultados de la representación de escala de grises haciendo lo siguiente:

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

Figura 11 ColorMapper clase

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

Un tidbit final de la información acerca de Deep Zoom le resultarán útiles implica a un ensamblado denominado DeepZoomTools.dll. Deep Zoom Composer utiliza este ensamblado para generar imágenes en mosaico y metadatos desde el plano que cree. En teoría, podría utilizar para generar herramientas de composición de su propio. Digo "en la teoría" porque hay valioso poco ahí en términos de documentación. Obtenga más información acerca de DeepZoomTools.dll en el Expression Blend y diseñoblog. Y me lanzar un mensaje de correo electrónico si idear algunos usos únicos, creativas para Deep Zoom pero no está bastante seguro de cómo hacer que hace lo que desea.

Envíe sus preguntas y comentarios para Jeff a wicked@microsoft.com.

Jeff Prosise es colabora como editor de MSDN Magazine y autor de varios libros, incluyendo Programming Microsoft .NET (Microsoft Press, 2002). También es cofundador de Wintellect ( www.Wintellect.com), una software empresa de consultoría y formación que especializada en Microsoft. NET. ¿Tiene un comentario en esta columna? Póngase en contacto con Jeff en wicked@microsoft.com.